Updated to hostap_2_6
authorDan Breslau <dbreslau@painless-security.com>
Mon, 10 Oct 2016 18:15:24 +0000 (14:15 -0400)
committerDan Breslau <dbreslau@painless-security.com>
Mon, 10 Oct 2016 18:15:24 +0000 (14:15 -0400)
649 files changed:
.gitignore
CONTRIBUTIONS
hostapd/hostapd.android.rc [new file with mode: 0644]
libeap/COPYING
libeap/README
libeap/build_release
libeap/doc/ctrl_iface.doxygen
libeap/doc/dbus.doxygen
libeap/doc/doxygen.conf
libeap/doc/p2p.doxygen
libeap/hostapd/Android.mk
libeap/hostapd/ChangeLog
libeap/hostapd/Makefile
libeap/hostapd/README
libeap/hostapd/android.config
libeap/hostapd/config_file.c
libeap/hostapd/ctrl_iface.c
libeap/hostapd/defconfig
libeap/hostapd/hapd_module_tests.c
libeap/hostapd/hlr_auc_gw.c
libeap/hostapd/hostapd.conf
libeap/hostapd/hostapd_cli.c
libeap/hostapd/main.c
libeap/hs20/client/Android.mk
libeap/hs20/client/Makefile
libeap/hs20/client/est.c
libeap/hs20/client/osu_client.c
libeap/hs20/server/www/spp.php
libeap/mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf [deleted file]
libeap/mac80211_hwsim/tests/0001-wpa2-psk/test.txt [deleted file]
libeap/mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf [deleted file]
libeap/mac80211_hwsim/tests/0002-vlan/hostapd.accept [deleted file]
libeap/mac80211_hwsim/tests/0002-vlan/hostapd.conf [deleted file]
libeap/mac80211_hwsim/tests/0002-vlan/hostapd.vlan [deleted file]
libeap/mac80211_hwsim/tests/0002-vlan/test.txt [deleted file]
libeap/patches/openssl-0.9.8za-tls-extensions.patch [deleted file]
libeap/patches/openssl-0.9.8zf-tls-extensions.patch [deleted file]
libeap/radius_example/radius_example.c
libeap/src/ap/accounting.c
libeap/src/ap/accounting.h
libeap/src/ap/acs.c
libeap/src/ap/ap_config.c
libeap/src/ap/ap_config.h
libeap/src/ap/ap_drv_ops.c
libeap/src/ap/ap_drv_ops.h
libeap/src/ap/ap_mlme.c
libeap/src/ap/authsrv.c
libeap/src/ap/beacon.c
libeap/src/ap/beacon.h
libeap/src/ap/ctrl_iface_ap.c
libeap/src/ap/ctrl_iface_ap.h
libeap/src/ap/dfs.c
libeap/src/ap/dhcp_snoop.c
libeap/src/ap/drv_callbacks.c
libeap/src/ap/gas_serv.c
libeap/src/ap/gas_serv.h
libeap/src/ap/hostapd.c
libeap/src/ap/hostapd.h
libeap/src/ap/hw_features.c
libeap/src/ap/iapp.c
libeap/src/ap/ieee802_11.c
libeap/src/ap/ieee802_11.h
libeap/src/ap/ieee802_11_auth.c
libeap/src/ap/ieee802_11_auth.h
libeap/src/ap/ieee802_11_ht.c
libeap/src/ap/ieee802_11_shared.c
libeap/src/ap/ieee802_11_vht.c
libeap/src/ap/ieee802_1x.c
libeap/src/ap/ieee802_1x.h
libeap/src/ap/mbo_ap.c [new file with mode: 0644]
libeap/src/ap/mbo_ap.h [new file with mode: 0644]
libeap/src/ap/ndisc_snoop.c
libeap/src/ap/neighbor_db.c [new file with mode: 0644]
libeap/src/ap/neighbor_db.h [new file with mode: 0644]
libeap/src/ap/pmksa_cache_auth.c
libeap/src/ap/pmksa_cache_auth.h
libeap/src/ap/rrm.c [new file with mode: 0644]
libeap/src/ap/rrm.h [new file with mode: 0644]
libeap/src/ap/sta_info.c
libeap/src/ap/sta_info.h
libeap/src/ap/taxonomy.c [new file with mode: 0644]
libeap/src/ap/taxonomy.h [new file with mode: 0644]
libeap/src/ap/vlan.c [new file with mode: 0644]
libeap/src/ap/vlan.h [new file with mode: 0644]
libeap/src/ap/vlan_full.c [new file with mode: 0644]
libeap/src/ap/vlan_ifconfig.c [new file with mode: 0644]
libeap/src/ap/vlan_init.c
libeap/src/ap/vlan_init.h
libeap/src/ap/vlan_ioctl.c [new file with mode: 0644]
libeap/src/ap/vlan_util.c
libeap/src/ap/vlan_util.h
libeap/src/ap/wnm_ap.c
libeap/src/ap/wnm_ap.h
libeap/src/ap/wpa_auth.c
libeap/src/ap/wpa_auth.h
libeap/src/ap/wpa_auth_ft.c
libeap/src/ap/wpa_auth_glue.c
libeap/src/ap/wpa_auth_i.h
libeap/src/ap/wpa_auth_ie.c
libeap/src/ap/wps_hostapd.c
libeap/src/common/cli.c [new file with mode: 0644]
libeap/src/common/cli.h [new file with mode: 0644]
libeap/src/common/common_module_tests.c
libeap/src/common/ctrl_iface_common.c [new file with mode: 0644]
libeap/src/common/ctrl_iface_common.h [new file with mode: 0644]
libeap/src/common/defs.h
libeap/src/common/eapol_common.h
libeap/src/common/ieee802_11_common.c
libeap/src/common/ieee802_11_common.h
libeap/src/common/ieee802_11_defs.h
libeap/src/common/ieee802_1x_defs.h
libeap/src/common/linux_bridge.h [new file with mode: 0644]
libeap/src/common/linux_vlan.h [new file with mode: 0644]
libeap/src/common/qca-vendor.h
libeap/src/common/sae.c
libeap/src/common/sae.h
libeap/src/common/version.h
libeap/src/common/wpa_common.c
libeap/src/common/wpa_common.h
libeap/src/common/wpa_ctrl.c
libeap/src/common/wpa_ctrl.h
libeap/src/common/wpa_helpers.c
libeap/src/crypto/Makefile
libeap/src/crypto/aes-cbc.c
libeap/src/crypto/aes-omac1.c
libeap/src/crypto/crypto.h
libeap/src/crypto/crypto_internal.c
libeap/src/crypto/crypto_module_tests.c
libeap/src/crypto/crypto_openssl.c
libeap/src/crypto/dh_group5.c
libeap/src/crypto/dh_groups.c
libeap/src/crypto/fips_prf_openssl.c
libeap/src/crypto/md4-internal.c
libeap/src/crypto/md5-internal.c
libeap/src/crypto/ms_funcs.c
libeap/src/crypto/sha1-internal.c
libeap/src/crypto/sha256-internal.c
libeap/src/crypto/sha256-prf.c
libeap/src/crypto/sha256.h
libeap/src/crypto/sha384-internal.c [new file with mode: 0644]
libeap/src/crypto/sha384_i.h [new file with mode: 0644]
libeap/src/crypto/sha512-internal.c [new file with mode: 0644]
libeap/src/crypto/sha512_i.h [new file with mode: 0644]
libeap/src/crypto/tls.h
libeap/src/crypto/tls_gnutls.c
libeap/src/crypto/tls_internal.c
libeap/src/crypto/tls_none.c
libeap/src/crypto/tls_openssl.c
libeap/src/crypto/tls_openssl.h [new file with mode: 0644]
libeap/src/crypto/tls_openssl_ocsp.c [new file with mode: 0644]
libeap/src/drivers/driver.h
libeap/src/drivers/driver_atheros.c
libeap/src/drivers/driver_bsd.c
libeap/src/drivers/driver_common.c
libeap/src/drivers/driver_hostap.c
libeap/src/drivers/driver_macsec_qca.c
libeap/src/drivers/driver_ndis.c
libeap/src/drivers/driver_nl80211.c
libeap/src/drivers/driver_nl80211.h
libeap/src/drivers/driver_nl80211_capa.c
libeap/src/drivers/driver_nl80211_event.c
libeap/src/drivers/driver_nl80211_monitor.c
libeap/src/drivers/driver_nl80211_scan.c
libeap/src/drivers/driver_privsep.c
libeap/src/drivers/driver_roboswitch.c
libeap/src/drivers/driver_wext.c
libeap/src/drivers/driver_wired.c
libeap/src/drivers/drivers.c
libeap/src/drivers/drivers.mak
libeap/src/drivers/drivers.mk
libeap/src/drivers/nl80211_copy.h
libeap/src/drivers/rfkill.c
libeap/src/eap_common/eap_eke_common.c
libeap/src/eap_common/eap_fast_common.c
libeap/src/eap_common/eap_fast_common.h
libeap/src/eap_common/eap_gpsk_common.c
libeap/src/eap_common/eap_pax_common.c
libeap/src/eap_common/eap_pwd_common.c
libeap/src/eap_common/eap_sake_common.c
libeap/src/eap_common/ikev2_common.c
libeap/src/eap_peer/eap.c
libeap/src/eap_peer/eap_aka.c
libeap/src/eap_peer/eap_config.h
libeap/src/eap_peer/eap_eke.c
libeap/src/eap_peer/eap_fast.c
libeap/src/eap_peer/eap_fast_pac.c
libeap/src/eap_peer/eap_gpsk.c
libeap/src/eap_peer/eap_gtc.c
libeap/src/eap_peer/eap_i.h
libeap/src/eap_peer/eap_ikev2.c
libeap/src/eap_peer/eap_leap.c
libeap/src/eap_peer/eap_md5.c
libeap/src/eap_peer/eap_methods.c
libeap/src/eap_peer/eap_methods.h
libeap/src/eap_peer/eap_mschapv2.c
libeap/src/eap_peer/eap_otp.c
libeap/src/eap_peer/eap_pax.c
libeap/src/eap_peer/eap_peap.c
libeap/src/eap_peer/eap_psk.c
libeap/src/eap_peer/eap_pwd.c
libeap/src/eap_peer/eap_sake.c
libeap/src/eap_peer/eap_sim.c
libeap/src/eap_peer/eap_tls.c
libeap/src/eap_peer/eap_tls_common.c
libeap/src/eap_peer/eap_tnc.c
libeap/src/eap_peer/eap_ttls.c
libeap/src/eap_peer/eap_vendor_test.c
libeap/src/eap_peer/eap_wsc.c
libeap/src/eap_peer/ikev2.c
libeap/src/eap_peer/tncc.c
libeap/src/eap_server/eap_methods.h
libeap/src/eap_server/eap_server_aka.c
libeap/src/eap_server/eap_server_eke.c
libeap/src/eap_server/eap_server_fast.c
libeap/src/eap_server/eap_server_gpsk.c
libeap/src/eap_server/eap_server_gtc.c
libeap/src/eap_server/eap_server_identity.c
libeap/src/eap_server/eap_server_ikev2.c
libeap/src/eap_server/eap_server_md5.c
libeap/src/eap_server/eap_server_methods.c
libeap/src/eap_server/eap_server_mschapv2.c
libeap/src/eap_server/eap_server_pax.c
libeap/src/eap_server/eap_server_peap.c
libeap/src/eap_server/eap_server_psk.c
libeap/src/eap_server/eap_server_pwd.c
libeap/src/eap_server/eap_server_sake.c
libeap/src/eap_server/eap_server_sim.c
libeap/src/eap_server/eap_server_tls.c
libeap/src/eap_server/eap_server_tls_common.c
libeap/src/eap_server/eap_server_tnc.c
libeap/src/eap_server/eap_server_ttls.c
libeap/src/eap_server/eap_server_vendor_test.c
libeap/src/eap_server/eap_server_wsc.c
libeap/src/eap_server/eap_sim_db.c
libeap/src/eap_server/eap_sim_db.h
libeap/src/eap_server/ikev2.c
libeap/src/eap_server/tncs.c
libeap/src/eapol_auth/eapol_auth_sm.c
libeap/src/eapol_auth/eapol_auth_sm_i.h
libeap/src/eapol_supp/eapol_supp_sm.c
libeap/src/fst/fst.c
libeap/src/fst/fst_ctrl_aux.c
libeap/src/fst/fst_ctrl_iface.c
libeap/src/fst/fst_defs.h
libeap/src/fst/fst_group.c
libeap/src/fst/fst_group.h
libeap/src/fst/fst_iface.c
libeap/src/fst/fst_iface.h
libeap/src/fst/fst_session.c
libeap/src/l2_packet/l2_packet_linux.c
libeap/src/l2_packet/l2_packet_pcap.c
libeap/src/p2p/p2p.c
libeap/src/p2p/p2p.h
libeap/src/p2p/p2p_build.c
libeap/src/p2p/p2p_go_neg.c
libeap/src/p2p/p2p_group.c
libeap/src/p2p/p2p_i.h
libeap/src/p2p/p2p_invitation.c
libeap/src/p2p/p2p_parse.c
libeap/src/p2p/p2p_pd.c
libeap/src/p2p/p2p_sd.c
libeap/src/pae/ieee802_1x_cp.c
libeap/src/pae/ieee802_1x_cp.h
libeap/src/pae/ieee802_1x_kay.c
libeap/src/pae/ieee802_1x_kay.h
libeap/src/pae/ieee802_1x_kay_i.h
libeap/src/pae/ieee802_1x_secy_ops.c
libeap/src/pae/ieee802_1x_secy_ops.h
libeap/src/radius/radius.c
libeap/src/radius/radius.h
libeap/src/radius/radius_client.c
libeap/src/radius/radius_client.h
libeap/src/radius/radius_das.c
libeap/src/radius/radius_das.h
libeap/src/rsn_supp/pmksa_cache.c
libeap/src/rsn_supp/pmksa_cache.h
libeap/src/rsn_supp/preauth.c
libeap/src/rsn_supp/preauth.h
libeap/src/rsn_supp/tdls.c
libeap/src/rsn_supp/wpa.c
libeap/src/rsn_supp/wpa.h
libeap/src/rsn_supp/wpa_i.h
libeap/src/rsn_supp/wpa_ie.c
libeap/src/tls/Makefile
libeap/src/tls/asn1.h
libeap/src/tls/pkcs5.c
libeap/src/tls/tlsv1_client.c
libeap/src/tls/tlsv1_client.h
libeap/src/tls/tlsv1_client_i.h
libeap/src/tls/tlsv1_client_ocsp.c [new file with mode: 0644]
libeap/src/tls/tlsv1_client_read.c
libeap/src/tls/tlsv1_client_write.c
libeap/src/tls/tlsv1_common.c
libeap/src/tls/tlsv1_common.h
libeap/src/tls/tlsv1_cred.c
libeap/src/tls/tlsv1_cred.h
libeap/src/tls/tlsv1_server_i.h
libeap/src/tls/tlsv1_server_read.c
libeap/src/tls/tlsv1_server_write.c
libeap/src/tls/x509v3.c
libeap/src/tls/x509v3.h
libeap/src/utils/browser-android.c
libeap/src/utils/common.c
libeap/src/utils/common.h
libeap/src/utils/edit_simple.c
libeap/src/utils/eloop.c
libeap/src/utils/eloop.h
libeap/src/utils/eloop_win.c
libeap/src/utils/ext_password.c
libeap/src/utils/ext_password_i.h
libeap/src/utils/http_curl.c
libeap/src/utils/module_tests.h [new file with mode: 0644]
libeap/src/utils/os.h
libeap/src/utils/os_unix.c
libeap/src/utils/pcsc_funcs.c
libeap/src/utils/platform.h
libeap/src/utils/radiotap.c
libeap/src/utils/radiotap.h
libeap/src/utils/radiotap_iter.h
libeap/src/utils/trace.c
libeap/src/utils/trace.h
libeap/src/utils/utils_module_tests.c
libeap/src/utils/wpa_debug.c
libeap/src/utils/wpabuf.c
libeap/src/utils/wpabuf.h
libeap/src/utils/xml_libxml2.c
libeap/src/wps/wps.c
libeap/src/wps/wps.h
libeap/src/wps/wps_attr_build.c
libeap/src/wps/wps_attr_parse.c
libeap/src/wps/wps_attr_process.c
libeap/src/wps/wps_common.c
libeap/src/wps/wps_defs.h
libeap/src/wps/wps_enrollee.c
libeap/src/wps/wps_i.h
libeap/src/wps/wps_module_tests.c
libeap/src/wps/wps_registrar.c
libeap/src/wps/wps_upnp.c
libeap/src/wps/wps_upnp.h
libeap/src/wps/wps_upnp_i.h
libeap/src/wps/wps_upnp_ssdp.c
libeap/src/wps/wps_upnp_web.c
libeap/tests/hwsim/auth_serv/as.conf
libeap/tests/hwsim/auth_serv/as2.conf
libeap/tests/hwsim/auth_serv/eap_user.conf
libeap/tests/hwsim/auth_serv/eap_user_vlan.conf
libeap/tests/hwsim/auth_serv/ec-ca-openssl.cnf
libeap/tests/hwsim/auth_serv/ec-ca.pem
libeap/tests/hwsim/auth_serv/ec-server.key
libeap/tests/hwsim/auth_serv/ec-server.pem
libeap/tests/hwsim/auth_serv/ec-user.key
libeap/tests/hwsim/auth_serv/ec-user.pem
libeap/tests/hwsim/auth_serv/ec2-ca.pem
libeap/tests/hwsim/auth_serv/ec2-server.key
libeap/tests/hwsim/auth_serv/ec2-server.pem
libeap/tests/hwsim/auth_serv/ec2-user.key
libeap/tests/hwsim/auth_serv/ec2-user.pem
libeap/tests/hwsim/auth_serv/hlr_auc_gw.milenage_db
libeap/tests/hwsim/auth_serv/index-revoked.txt
libeap/tests/hwsim/auth_serv/index.txt
libeap/tests/hwsim/auth_serv/ocsp-req.der
libeap/tests/hwsim/auth_serv/ocsp-responder.pem
libeap/tests/hwsim/auth_serv/ocsp-server-cache.der
libeap/tests/hwsim/auth_serv/server-eku-client-server.pem
libeap/tests/hwsim/auth_serv/server-eku-client.pem
libeap/tests/hwsim/auth_serv/server-no-dnsname.pem
libeap/tests/hwsim/auth_serv/server.pem
libeap/tests/hwsim/auth_serv/server.pkcs12
libeap/tests/hwsim/auth_serv/user.pem
libeap/tests/hwsim/auth_serv/user.pkcs12
libeap/tests/hwsim/auth_serv/user2.pkcs12
libeap/tests/hwsim/auth_serv/user3.pkcs12
libeap/tests/hwsim/example-hostapd.config
libeap/tests/hwsim/example-setup.txt
libeap/tests/hwsim/example-wpa_supplicant.config
libeap/tests/hwsim/fst_module_aux.py
libeap/tests/hwsim/hostapd.py
libeap/tests/hwsim/hostapd.wlan3.vlan
libeap/tests/hwsim/hostapd.wlan4.vlan
libeap/tests/hwsim/hwsim_utils.py
libeap/tests/hwsim/nl80211.py
libeap/tests/hwsim/run-tests.py
libeap/tests/hwsim/start.sh
libeap/tests/hwsim/test_ap_acs.py
libeap/tests/hwsim/test_ap_ciphers.py
libeap/tests/hwsim/test_ap_config.py
libeap/tests/hwsim/test_ap_csa.py
libeap/tests/hwsim/test_ap_dynamic.py
libeap/tests/hwsim/test_ap_eap.py
libeap/tests/hwsim/test_ap_ft.py
libeap/tests/hwsim/test_ap_hs20.py
libeap/tests/hwsim/test_ap_ht.py
libeap/tests/hwsim/test_ap_mixed.py
libeap/tests/hwsim/test_ap_open.py
libeap/tests/hwsim/test_ap_params.py
libeap/tests/hwsim/test_ap_pmf.py
libeap/tests/hwsim/test_ap_psk.py
libeap/tests/hwsim/test_ap_qosmap.py
libeap/tests/hwsim/test_ap_roam.py
libeap/tests/hwsim/test_ap_tdls.py
libeap/tests/hwsim/test_ap_track.py
libeap/tests/hwsim/test_ap_vht.py
libeap/tests/hwsim/test_ap_vlan.py
libeap/tests/hwsim/test_ap_wps.py
libeap/tests/hwsim/test_autoscan.py
libeap/tests/hwsim/test_bgscan.py
libeap/tests/hwsim/test_cfg80211.py
libeap/tests/hwsim/test_connect_cmd.py
libeap/tests/hwsim/test_dbus.py
libeap/tests/hwsim/test_dbus_old.py
libeap/tests/hwsim/test_dfs.py
libeap/tests/hwsim/test_eap_proto.py
libeap/tests/hwsim/test_erp.py
libeap/tests/hwsim/test_ext_password.py
libeap/tests/hwsim/test_fst_config.py
libeap/tests/hwsim/test_fst_module.py
libeap/tests/hwsim/test_gas.py
libeap/tests/hwsim/test_hapd_ctrl.py
libeap/tests/hwsim/test_hostapd_oom.py
libeap/tests/hwsim/test_ibss.py
libeap/tests/hwsim/test_ieee8021x.py
libeap/tests/hwsim/test_monitor_interface.py
libeap/tests/hwsim/test_nfc_p2p.py
libeap/tests/hwsim/test_nfc_wps.py
libeap/tests/hwsim/test_offchannel_tx.py
libeap/tests/hwsim/test_p2p_autogo.py
libeap/tests/hwsim/test_p2p_channel.py
libeap/tests/hwsim/test_p2p_concurrency.py
libeap/tests/hwsim/test_p2p_device.py
libeap/tests/hwsim/test_p2p_discovery.py
libeap/tests/hwsim/test_p2p_ext.py
libeap/tests/hwsim/test_p2p_grpform.py
libeap/tests/hwsim/test_p2p_invitation.py
libeap/tests/hwsim/test_p2p_messages.py
libeap/tests/hwsim/test_p2p_persistent.py
libeap/tests/hwsim/test_p2p_service.py
libeap/tests/hwsim/test_p2p_set.py
libeap/tests/hwsim/test_p2p_wifi_display.py
libeap/tests/hwsim/test_p2ps.py
libeap/tests/hwsim/test_peerkey.py
libeap/tests/hwsim/test_pmksa_cache.py
libeap/tests/hwsim/test_radio_work.py
libeap/tests/hwsim/test_radius.py
libeap/tests/hwsim/test_rfkill.py
libeap/tests/hwsim/test_sae.py
libeap/tests/hwsim/test_scan.py
libeap/tests/hwsim/test_ssid.py
libeap/tests/hwsim/test_sta_dynamic.py
libeap/tests/hwsim/test_suite_b.py
libeap/tests/hwsim/test_tnc.py
libeap/tests/hwsim/test_wep.py
libeap/tests/hwsim/test_wext.py
libeap/tests/hwsim/test_wnm.py
libeap/tests/hwsim/test_wpas_ap.py
libeap/tests/hwsim/test_wpas_config.py
libeap/tests/hwsim/test_wpas_ctrl.py
libeap/tests/hwsim/test_wpas_mesh.py
libeap/tests/hwsim/test_wpas_wmm_ac.py
libeap/tests/hwsim/tshark.py
libeap/tests/hwsim/utils.py
libeap/tests/hwsim/vm/inside.sh
libeap/tests/hwsim/vm/parallel-vm.py
libeap/tests/hwsim/vm/parallel-vm.sh
libeap/tests/hwsim/vm/uevent.sh
libeap/tests/hwsim/vm/vm-run.sh
libeap/tests/hwsim/wlantest.py
libeap/tests/hwsim/wpasupplicant.py
libeap/wlantest/bip.c
libeap/wlantest/ccmp.c
libeap/wlantest/readpcap.c
libeap/wlantest/rx_data.c
libeap/wlantest/test_vectors.c
libeap/wlantest/wlantest.c
libeap/wlantest/wlantest.h
libeap/wlantest/writepcap.c
libeap/wpa_supplicant/Android.mk
libeap/wpa_supplicant/ChangeLog
libeap/wpa_supplicant/Makefile
libeap/wpa_supplicant/README
libeap/wpa_supplicant/README-HS20
libeap/wpa_supplicant/README-P2P
libeap/wpa_supplicant/android.config
libeap/wpa_supplicant/ap.c
libeap/wpa_supplicant/ap.h
libeap/wpa_supplicant/autoscan.c
libeap/wpa_supplicant/autoscan.h
libeap/wpa_supplicant/bgscan.c
libeap/wpa_supplicant/bgscan.h
libeap/wpa_supplicant/bss.c
libeap/wpa_supplicant/bss.h
libeap/wpa_supplicant/config.c
libeap/wpa_supplicant/config.h
libeap/wpa_supplicant/config_file.c
libeap/wpa_supplicant/config_ssid.h
libeap/wpa_supplicant/config_winreg.c
libeap/wpa_supplicant/ctrl_iface.c
libeap/wpa_supplicant/ctrl_iface_udp.c
libeap/wpa_supplicant/ctrl_iface_unix.c
libeap/wpa_supplicant/dbus/dbus-wpa_supplicant.conf
libeap/wpa_supplicant/dbus/dbus_common_i.h
libeap/wpa_supplicant/dbus/dbus_dict_helpers.c
libeap/wpa_supplicant/dbus/dbus_dict_helpers.h
libeap/wpa_supplicant/dbus/dbus_new.c
libeap/wpa_supplicant/dbus/dbus_new.h
libeap/wpa_supplicant/dbus/dbus_new_handlers.c
libeap/wpa_supplicant/dbus/dbus_new_handlers.h
libeap/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
libeap/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
libeap/wpa_supplicant/dbus/dbus_new_handlers_wps.c
libeap/wpa_supplicant/dbus/dbus_new_helpers.c
libeap/wpa_supplicant/dbus/dbus_new_helpers.h
libeap/wpa_supplicant/dbus/dbus_new_introspect.c
libeap/wpa_supplicant/dbus/dbus_old_handlers.c
libeap/wpa_supplicant/defconfig
libeap/wpa_supplicant/doc/docbook/eapol_test.sgml
libeap/wpa_supplicant/doc/docbook/wpa_background.sgml
libeap/wpa_supplicant/doc/docbook/wpa_cli.sgml
libeap/wpa_supplicant/doc/docbook/wpa_gui.sgml
libeap/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
libeap/wpa_supplicant/doc/docbook/wpa_priv.sgml
libeap/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
libeap/wpa_supplicant/driver_i.h
libeap/wpa_supplicant/eapol_test.c
libeap/wpa_supplicant/events.c
libeap/wpa_supplicant/gas_query.c
libeap/wpa_supplicant/gas_query.h
libeap/wpa_supplicant/hs20_supplicant.c
libeap/wpa_supplicant/hs20_supplicant.h
libeap/wpa_supplicant/ibss_rsn.c
libeap/wpa_supplicant/ibss_rsn.h
libeap/wpa_supplicant/interworking.c
libeap/wpa_supplicant/interworking.h
libeap/wpa_supplicant/main.c
libeap/wpa_supplicant/mesh.c
libeap/wpa_supplicant/mesh.h
libeap/wpa_supplicant/mesh_mpm.c
libeap/wpa_supplicant/mesh_mpm.h
libeap/wpa_supplicant/mesh_rsn.c
libeap/wpa_supplicant/mesh_rsn.h
libeap/wpa_supplicant/notify.c
libeap/wpa_supplicant/notify.h
libeap/wpa_supplicant/offchannel.c
libeap/wpa_supplicant/p2p_supplicant.c
libeap/wpa_supplicant/p2p_supplicant.h
libeap/wpa_supplicant/p2p_supplicant_sd.c
libeap/wpa_supplicant/scan.c
libeap/wpa_supplicant/scan.h
libeap/wpa_supplicant/sme.c
libeap/wpa_supplicant/systemd/wpa_supplicant.service.in
libeap/wpa_supplicant/tests/link_test.c [deleted file]
libeap/wpa_supplicant/tests/test_eap_sim_common.c [deleted file]
libeap/wpa_supplicant/tests/test_wpa.c [deleted file]
libeap/wpa_supplicant/wmm_ac.h
libeap/wpa_supplicant/wnm_sta.c
libeap/wpa_supplicant/wnm_sta.h
libeap/wpa_supplicant/wpa_cli.c
libeap/wpa_supplicant/wpa_priv.c
libeap/wpa_supplicant/wpa_supplicant.c
libeap/wpa_supplicant/wpa_supplicant.conf
libeap/wpa_supplicant/wpa_supplicant_i.h
libeap/wpa_supplicant/wpas_glue.c
libeap/wpa_supplicant/wpas_kay.c
libeap/wpa_supplicant/wpas_module_tests.c
libeap/wpa_supplicant/wps_supplicant.c
libeap/wpa_supplicant/wps_supplicant.h
libeap/wpaspy/test.py
libeap/wpaspy/wpaspy.py
tests/hwsim/auth_serv/ca-key.pem [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-server/ca-and-root.pem [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-server/cacert.pem [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-server/careq.pem [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-server/index.txt [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-server/index.txt.attr [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-server/newcerts/8020A0407F798AB8.pem [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-server/newcerts/8020A0407F798AB9.pem [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-server/private/cakey.pem [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-server/serial [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-server/server-revoked.key [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-server/server-revoked.pem [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-server/server-revoked.req [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-server/server-revoked_and_ica.pem [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-server/server.key [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-server/server.pem [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-server/server.req [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-server/server_and_ica.pem [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-user/ca-and-root.pem [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-user/cacert.pem [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-user/careq.pem [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-user/index.txt [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-user/index.txt.attr [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-user/newcerts/E153BA3A7605DA1E.pem [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-user/private/cakey.pem [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-user/serial [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-user/user.key [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-user/user.pem [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-user/user.req [new file with mode: 0644]
tests/hwsim/auth_serv/iCA-user/user_and_ica.pem [new file with mode: 0644]
tests/hwsim/auth_serv/ica-generate.sh [new file with mode: 0755]
tests/hwsim/auth_serv/ocsp-multi-server-cache.der [new file with mode: 0644]
tests/hwsim/auth_serv/rootCA/index.txt [new file with mode: 0644]
tests/hwsim/auth_serv/rootCA/index.txt.attr [new file with mode: 0644]
tests/hwsim/auth_serv/rootCA/serial [new file with mode: 0644]
tests/hwsim/auth_serv/server-extra.pkcs12 [new file with mode: 0644]
tests/hwsim/auth_serv/sha384-server.key [new file with mode: 0644]
tests/hwsim/auth_serv/sha384-server.pem [new file with mode: 0644]
tests/hwsim/auth_serv/sha384-user.key [new file with mode: 0644]
tests/hwsim/auth_serv/sha384-user.pem [new file with mode: 0644]
tests/hwsim/auth_serv/sha512-ca.key [new file with mode: 0644]
tests/hwsim/auth_serv/sha512-ca.pem [new file with mode: 0644]
tests/hwsim/auth_serv/sha512-generate.sh [new file with mode: 0755]
tests/hwsim/auth_serv/sha512-server.key [new file with mode: 0644]
tests/hwsim/auth_serv/sha512-server.pem [new file with mode: 0644]
tests/hwsim/auth_serv/sha512-user.key [new file with mode: 0644]
tests/hwsim/auth_serv/sha512-user.pem [new file with mode: 0644]
tests/hwsim/auth_serv/user.key.pkcs8 [new file with mode: 0644]
tests/hwsim/auth_serv/user.key.pkcs8.pkcs5v15 [new file with mode: 0644]
tests/hwsim/multi-bss-iface-per_sta_vif.conf [new file with mode: 0644]
tests/hwsim/p2p_utils.py [new file with mode: 0644]
tests/hwsim/remotehost.py [new file with mode: 0644]
tests/hwsim/test_hs20_filter.py [new file with mode: 0644]
tests/hwsim/test_mbo.py [new file with mode: 0644]
tests/hwsim/test_rrm.py [new file with mode: 0644]
tests/hwsim/test_wmediumd.py [new file with mode: 0644]
tests/hwsim/wps-ctrl-cred [new file with mode: 0644]
tests/hwsim/wps-ctrl-cred2 [new file with mode: 0644]
tests/remote/config.py [new file with mode: 0644]
tests/remote/hwsim_wrapper.py [new file with mode: 0644]
tests/remote/monitor.py [new file with mode: 0644]
tests/remote/run-tests.py [new file with mode: 0755]
tests/remote/rutils.py [new file with mode: 0644]
tests/remote/test_devices.py [new file with mode: 0644]
tests/remote/test_example.py [new file with mode: 0644]
wpa_supplicant/binder/.clang-format [new file with mode: 0644]
wpa_supplicant/binder/binder.cpp [new file with mode: 0644]
wpa_supplicant/binder/binder.h [new file with mode: 0644]
wpa_supplicant/binder/binder_constants.cpp [new file with mode: 0644]
wpa_supplicant/binder/binder_constants.h [new file with mode: 0644]
wpa_supplicant/binder/binder_i.h [new file with mode: 0644]
wpa_supplicant/binder/binder_manager.cpp [new file with mode: 0644]
wpa_supplicant/binder/binder_manager.h [new file with mode: 0644]
wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl [new file with mode: 0644]
wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl [new file with mode: 0644]
wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl [new file with mode: 0644]
wpa_supplicant/binder/iface.cpp [new file with mode: 0644]
wpa_supplicant/binder/iface.h [new file with mode: 0644]
wpa_supplicant/binder/supplicant.cpp [new file with mode: 0644]
wpa_supplicant/binder/supplicant.h [new file with mode: 0644]
wpa_supplicant/libwpa_test.c [new file with mode: 0644]
wpa_supplicant/mbo.c [new file with mode: 0644]

index b6d0508..1653c29 100644 (file)
@@ -14,6 +14,7 @@ build-aux
 mech_eap.spec
 mech_eap*tar*
 *.lo
+*.a
 *.o
 *.d
 *.gcno
@@ -37,6 +38,8 @@ wpa_supplicant/wpa_gui/Makefile
 wpa_supplicant/wpa_gui/wpa_gui
 wpa_supplicant/wpa_gui-qt4/Makefile
 wpa_supplicant/wpa_gui-qt4/wpa_gui
+wpa_supplicant/libwpa_test1
+wpa_supplicant/libwpa_test2
 hostapd/hostapd
 hostapd/hostapd_cli
 hostapd/hlr_auc_gw
index ca09bae..76600bc 100644 (file)
@@ -29,6 +29,34 @@ using your real name. Pseudonyms or anonymous contributions cannot
 unfortunately be accepted.
 
 
+The preferred method of submitting the contribution to the project is by
+email to the hostap mailing list:
+hostap@lists.infradead.org
+Note that the list may require subscription before accepting message
+without moderation. You can subscribe to the list at this address:
+http://lists.infradead.org/mailman/listinfo/hostap
+
+The message should contain an inlined patch against the current
+development branch (i.e., the master branch of
+git://w1.fi/hostap.git). Please make sure the software you use for
+sending the patch does not corrupt whitespace. If that cannot be fixed
+for some reason, it is better to include an attached version of the
+patch file than just send a whitespace damaged version in the message
+body.
+
+The patches should be separate logical changes rather than doing
+everything in a single patch. In other words, please keep cleanup, new
+features, and bug fixes all in their own patches. Each patch needs a
+commit log that describes the changes (what the changes fix, what
+functionality is added, why the changes are useful, etc.).
+
+Please try to follow the coding style used in the project.
+
+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.
+
+
 History of license and contributions terms
 ------------------------------------------
 
@@ -112,7 +140,7 @@ The license terms used for hostap.git files
 
 Modified BSD license (no advertisement clause):
 
-Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/hostapd/hostapd.android.rc b/hostapd/hostapd.android.rc
new file mode 100644 (file)
index 0000000..83e8d87
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# 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 /system/bin/hostapd \
+        -e /data/misc/wifi/entropy.bin \
+        /data/misc/wifi/hostapd.conf
+    class main
+    user wifi
+    writepid /data/misc/wifi/hostapd.pid
+    group wifi
+    disabled
+    oneshot
index 5962e2f..7efce0d 100644 (file)
@@ -1,7 +1,7 @@
 wpa_supplicant and hostapd
 --------------------------
 
-Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 
index 07d1d25..9685f58 100644 (file)
@@ -1,7 +1,7 @@
 wpa_supplicant and hostapd
 --------------------------
 
-Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 These programs are licensed under the BSD license (the one with
index 4714553..3aa9bf3 100755 (executable)
@@ -30,13 +30,13 @@ mkdir $TMP
 mkdir -p $RELDIR
 
 git archive --format=tar --prefix=wpa-$VER/ HEAD \
-       README COPYING CONTRIBUTIONS patches src wpa_supplicant hostapd hs20 |
+       README COPYING CONTRIBUTIONS src wpa_supplicant hostapd hs20 |
        gzip > $RELDIR/wpa-$VER.tar.gz
 git archive --format=tar --prefix=hostapd-$VER/ HEAD \
-       README COPYING CONTRIBUTIONS patches src hostapd |
+       README COPYING CONTRIBUTIONS src hostapd |
        gzip > $RELDIR/hostapd-$VER.tar.gz
 git archive --format=tar --prefix=wpa_supplicant-$VER/ HEAD \
-       README COPYING CONTRIBUTIONS patches src wpa_supplicant hs20/client |
+       README COPYING CONTRIBUTIONS src wpa_supplicant hs20/client |
        tar --directory=$TMP -xf -
 
 cd $TMP
index be8916f..7dccdc7 100644 (file)
@@ -557,7 +557,7 @@ Device Address>" to indicate the entry following the specified peer
 
 Enable/disable extended listen timing. Without parameters, this
 command disables extended listen timing. When enabling the feature,
-two parameters are used: availibility period and availability interval
+two parameters are used: availability period and availability interval
 (both in milliseconds and with range of 1-65535).
 
 
index 9430632..b0e67d4 100644 (file)
@@ -97,6 +97,11 @@ registered in the bus with fi.w1.wpa_supplicant1 name.
          <dd>Getting an interface object path failed for an unknown reason.</dd>
        </dl>
       </li>
+
+      <li>
+       <h3>ExpectDisconnect ( ) --> nothing</h3>
+       <p>Notify wpa_supplicant of an externally triggered disconnection, e.g., due to system suspend.</p>
+      </li>
     </ul>
 
 \subsection dbus_main_properties Properties
@@ -451,6 +456,62 @@ fi.w1.wpa_supplicant1.CreateInterface.
        </dl>
       </li>
       <li>
+       <h3>VendorElemAdd ( i: frame_id, ay: ielems ) --> nothing</h3>
+       <p>Add Vendor Elements to corresponding frame ID.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>i : frame_id</dt>
+         <dd>Frame ID for which Vendor specific IE is to be added.</dd>
+         <dt>ay : ielems</dt>
+         <dd>Information Element(s).</dd>
+       </dl>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+         <dd>The "ielems" argument is not a properly formatted or size mismatch.</dd>
+         <dt>fi.w1.wpa_supplicant1.NoMemory</dt>
+         <dd>Needed memory was not possible to get allocated.</dd>
+       </dl>
+      </li>
+      <li>
+       <h3>VendorElemGet ( i: frame_id ) --> ay: ielems</h3>
+       <p>Get Vendor Elements of corresponding frame ID.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>i : frame_id</dt>
+         <dd>Frame ID for which Vendor specific IE is being queried.</dd>
+         <dt>ay : ielems</dt>
+         <dd>Information Element(s).</dd>
+       </dl>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+         <dd>The "frame_id" argument is not valid.</dd>
+       </dl>
+      </li>
+      <li>
+       <h3>VendorElemRem ( i: frame_id, ay: ielems ) --> nothing</h3>
+       <p>Remove Vendor Elements of corresponding frame ID.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>i : frame_id</dt>
+         <dd>Frame ID for which Vendor specific IE is to be removed.</dd>
+         <dt>ay : ielems</dt>
+         <dd>Information Element(s) OR * to remove all.</dd>
+       </dl>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+         <dd>The "ielems" argument is not a properly formatted or size mismatch.</dd>
+         <dt>fi.w1.wpa_supplicant1.NoMemory</dt>
+         <dd>Needed memory was not possible to get allocated.</dd>
+       </dl>
+      </li>
+      <li>
+       <h3>SaveConfig ( ) --> nothing</h3>
+       <p>Save configuration to the configuration file.</p>
+      </li>
+      <li>
        <h3>EAPLogoff ( ) --> nothing</h3>
        <p>IEEE 802.1X EAPOL state machine logoff.</p>
       </li>
@@ -620,6 +681,11 @@ fi.w1.wpa_supplicant1.CreateInterface.
       </li>
 
       <li>
+       <h3>ConfigFile - s - (read)</h3>
+       <p>Configuration file path. Returns an empty string if no configuration file is in use.</p>
+      </li>
+
+      <li>
        <h3>CurrentBSS - o - (read)</h3>
        <p>Path to D-Bus object representing BSS which wpa_supplicant is associated with, or "/" if is not associated at all.</p>
       </li>
@@ -673,6 +739,256 @@ fi.w1.wpa_supplicant1.CreateInterface.
        <h3>DisconnectReason - i - (read)</h3>
        <p>The most recent IEEE 802.11 reason code for disconnect. Negative value indicates locally generated disconnection.</p>
       </li>
+
+      <li>
+       <h3>AssocStatusCode - i - (read)</h3>
+       <p>The most recent IEEE 802.11 status code for association rejection.</p>
+      </li>
+
+      <li>
+       <h3>EapolVersion - s - (read/write)</h3>
+       <p>IEEE 802.1X/EAPOL version number</p>
+      </li>
+
+      <li>
+       <h3>Bgscan - s - (read/write)</h3>
+       <p>Background scan and roaming parameters or an empty string if none</p>
+      </li>
+
+      <li>
+       <h3>DisableScanOffload - s - (read/write)</h3>
+       <p>Disable automatic offloading of scan requests</p>
+      </li>
+
+      <li>
+       <h3>OpenscEnginePath - s - (read/write)</h3>
+       <p>Path to the OpenSSL engine for opensc</p>
+      </li>
+
+      <li>
+       <h3>OpensslCiphers - s - (read/write)</h3>
+       <p>OpenSSL cipher string</p>
+      </li>
+
+      <li>
+       <h3>PcscReader - s - (read/write)</h3>
+       <p>PC/SC reader name prefix</p>
+      </li>
+
+      <li>
+       <h3>PcscPin - s - (read/write)</h3>
+       <p>PIN for USIM, GSM SIM, and smartcards</p>
+      </li>
+
+      <li>
+       <h3>ExternalSim - s - (read/write)</h3>
+       <p>Use external processing for SIM/USIM operations</p>
+      </li>
+
+      <li>
+       <h3>DriverParam - s - (read/write)</h3>
+       <p>Driver interface parameters</p>
+      </li>
+
+      <li>
+       <h3>Dot11RSNAConfigPMKLifetime - s - (read/write)</h3>
+       <p>Maximum lifetime of a PMK</p>
+      </li>
+
+      <li>
+       <h3>Dot11RSNAConfigPMKReauthThreshold - s - (read/write)</h3>
+       <p>PMK re-authentication threshold</p>
+      </li>
+
+      <li>
+       <h3>Dot11RSNAConfigSATimeout - s - (read/write)</h3>
+       <p>Security association timeout</p>
+      </li>
+
+      <li>
+       <h3>BssMaxCount - s - (read/write)</h3>
+       <p>Maximum number of BSS entries to keep in memory</p>
+      </li>
+
+      <li>
+       <h3>FilterSsids - s - (read/write)</h3>
+       <p>SSID-based scan result filtering</p>
+      </li>
+
+      <li>
+       <h3>FilterRssi - s - (read/write)</h3>
+       <p>RSSI-based scan result filtering</p>
+      </li>
+
+      <li>
+       <h3>MaxNumSta - s - (read/write)</h3>
+       <p>Maximum number of STAs in an AP/P2P GO</p>
+      </li>
+
+      <li>
+       <h3>DisassocLowAck - s - (read/write)</h3>
+       <p>Disassocicate stations with massive packet loss</p>
+      </li>
+
+      <li>
+       <h3>Interworking - s - (read/write)</h3>
+       <p>Whether Interworking (IEEE 802.11u) is enabled</p>
+      </li>
+
+      <li>
+       <h3>Hessid - s - (read/write)</h3>
+       <p>Homogenous ESS identifier</p>
+      </li>
+
+      <li>
+       <h3>AccessNetworkType - s - (read/write)</h3>
+       <p>Access Network Type</p>
+      </li>
+
+      <li>
+       <h3>PbcInM1 - s - (read/write)</h3>
+       <p>AP mode WPS probing workaround for PBC with Windows 7</p>
+      </li>
+
+      <li>
+       <h3>Autoscan - s - (read/write)</h3>
+       <p>Automatic scan parameters or an empty string if none</p>
+      </li>
+
+      <li>
+       <h3>WpsNfcDevPwId - s - (read/write)</h3>
+       <p>NFC Device Password ID for password token</p>
+      </li>
+
+      <li>
+       <h3>WpsNfcDhPubkey - s - (read/write)</h3>
+       <p>NFC DH Public Key for password token</p>
+      </li>
+
+      <li>
+       <h3>WpsNfcDhPrivkey - s - (read/write)</h3>
+       <p>NFC DH Private Key for password token</p>
+      </li>
+
+      <li>
+       <h3>WpsNfcDevPw - s - (read/write)</h3>
+       <p>NFC Device Password for password token</p>
+      </li>
+
+      <li>
+       <h3>ExtPasswordBackend - s - (read/write)</h3>
+       <p>External password backend or an empty string if none</p>
+      </li>
+
+      <li>
+       <h3>P2pGoMaxInactivity - s - (read/write)</h3>
+       <p>Timeout in seconds to detect STA inactivity</p>
+      </li>
+
+      <li>
+       <h3>AutoInterworking - s - (read/write)</h3>
+       <p>Whether to use network selection automatically</p>
+      </li>
+
+      <li>
+       <h3>Okc - s - (read/write)</h3>
+       <p>Whether to enable opportunistic key caching by default</p>
+      </li>
+
+      <li>
+       <h3>Pmf - s - (read/write)</h3>
+       <p>Whether to enable/require PMF by default</p>
+      </li>
+
+      <li>
+       <h3>SaeGroups - s - (read/write)</h3>
+       <p>Preference list of enabled groups for SAE</p>
+      </li>
+
+      <li>
+       <h3>DtimPeriod - s - (read/write)</h3>
+       <p>Default DTIM period in Beacon intervals</p>
+      </li>
+
+      <li>
+       <h3>BeaconInt - s - (read/write)</h3>
+       <p>Default Beacon interval in TU</p>
+      </li>
+
+      <li>
+       <h3>IgnoreOldScanRes - s - (read/write)</h3>
+       <p>Ignore scan results older than request</p>
+      </li>
+
+      <li>
+       <h3>FreqList - s - (read/write)</h3>
+       <p>Array of allowed scan frequencies or an empty string for all</p>
+      </li>
+
+      <li>
+       <h3>ScanCurFreq - s - (read/write)</h3>
+       <p>Whether to scan only the current channel</p>
+      </li>
+
+      <li>
+       <h3>SchedScanInterval - s - (read/write)</h3>
+       <p>schedule scan interval</p>
+      </li>
+
+      <li>
+       <h3>TdlsExternalControl - s - (read/write)</h3>
+       <p>External control for TDLS setup requests</p>
+      </li>
+
+      <li>
+       <h3>OsuDir - s - (read/write)</h3>
+       <p>OSU provider information directory</p>
+      </li>
+
+      <li>
+       <h3>WowlanTriggers - s - (read/write)</h3>
+       <p>Wake-on-WLAN triggers</p>
+      </li>
+
+      <li>
+       <h3>P2pSearchDelay - s - (read/write)</h3>
+       <p>Extra delay between concurrent search iterations</p>
+      </li>
+
+      <li>
+       <h3>MacAddr - s - (read/write)</h3>
+       <p>MAC address policy default</p>
+      </li>
+
+      <li>
+       <h3>RandAddrLifetime - s - (read/write)</h3>
+       <p>Lifetime of random MAC address in seconds</p>
+      </li>
+
+      <li>
+       <h3>PreassocMacAddr - s - (read/write)</h3>
+       <p>Pre-association MAC address policy</p>
+      </li>
+
+      <li>
+       <h3>KeyMgmtOffload - s - (read/write)</h3>
+       <p>Use key management offload</p>
+      </li>
+
+      <li>
+       <h3>PassiveScan - s - (read/write)</h3>
+       <p>Whether to force passive scan for network connection</p>
+      </li>
+
+      <li>
+       <h3>ReassocSameBssOptim - s - (read/write)</h3>
+       <p>Whether to optimize reassoc-to-same-BSS</p>
+      </li>
+
+      <li>
+       <h3>WpsPriority - s - (read/write)</h3>
+       <p>Priority for the networks added through WPS</p>
+      </li>
     </ul>
 
 \subsection dbus_interface_signals Signals
@@ -1321,6 +1637,20 @@ Interface for performing P2P (Wi-Fi Peer-to-Peer) P2P Device operations.
   </li>
 
   <li>
+    <h3>DeviceFoundProperties ( o : path, a{sv} : properties )</h3>
+    <p>A new peer device has been found.</p>
+    <h4>Arguments</h4>
+    <dl>
+      <dt>o : path</dt>
+      <dd>A D-Bus path to an object representing the found peer device.</dd>
+    </dl>
+    <dl>
+      <dt>a{sv} : properties</dt>
+      <dd>A dictionary containing properties of the found peer device.</dd>
+    </dl>
+  </li>
+
+  <li>
     <h3>DeviceLost ( o : path )</h3>
   </li>
 
index 06be6a5..c519094 100644 (file)
@@ -31,7 +31,7 @@ PROJECT_NAME           = "wpa_supplicant / hostapd"
 # This could be handy for archiving the generated documentation or
 # if some version control system is used.
 
-PROJECT_NUMBER         = 2.4
+PROJECT_NUMBER         = 2.6
 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
 # base path where the generated documentation will be put.
index c1a81db..f46d1b8 100644 (file)
@@ -313,7 +313,7 @@ services. This value is included in all SD request and response
 frames. The value received from the peers will be included in the
 \ref p2p_config::sd_request() and \ref p2p_config::sd_response() callbacks. The
 value to be sent to the peers is incremented with a call to
-\ref p2p_sd_service_update() whenever availibility of the local services
+\ref p2p_sd_service_update() whenever availability of the local services
 changes.
 
 
index 5885f2b..ea3a39a 100644 (file)
@@ -46,7 +46,6 @@ endif
 INCLUDES = $(LOCAL_PATH)
 INCLUDES += $(LOCAL_PATH)/src
 INCLUDES += $(LOCAL_PATH)/src/utils
-INCLUDES += external/openssl/include
 INCLUDES += system/security/keystore/include
 ifdef CONFIG_DRIVER_NL80211
 ifneq ($(wildcard external/libnl),)
@@ -97,6 +96,8 @@ 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 =
@@ -176,17 +177,25 @@ ifdef CONFIG_NO_VLAN
 L_CFLAGS += -DCONFIG_NO_VLAN
 else
 OBJS += src/ap/vlan_init.c
-ifdef CONFIG_VLAN_NETLINK
+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
-L_CFLAGS += -DCONFIG_VLAN_NETLINK
 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
@@ -262,6 +271,11 @@ ifdef CONFIG_IEEE80211AC
 L_CFLAGS += -DCONFIG_IEEE80211AC
 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
@@ -555,6 +569,7 @@ 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
@@ -651,6 +666,8 @@ 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
@@ -809,6 +826,16 @@ L_CFLAGS += -DCONFIG_SHA384
 OBJS += src/crypto/sha384-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_DH_GROUPS
 OBJS += src/crypto/dh_groups.c
 endif
@@ -850,12 +877,6 @@ ifdef CONFIG_DRIVER_RADIUS_ACL
 L_CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL
 endif
 
-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
-endif
-
 ifdef NEED_BASE64
 OBJS += src/utils/base64.c
 endif
@@ -926,7 +947,10 @@ ifdef CONFIG_ANDROID_LOG
 L_CFLAGS += -DCONFIG_ANDROID_LOG
 endif
 
-OBJS_c = hostapd_cli.c src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c
+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
@@ -971,6 +995,7 @@ 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)
index af54e1e..d2b669b 100644 (file)
@@ -1,5 +1,78 @@
 ChangeLog for hostapd
 
+2016-10-02 - v2.6
+       * fixed EAP-pwd last fragment validation
+         [http://w1.fi/security/2015-7/] (CVE-2015-5314)
+       * fixed WPS configuration update vulnerability with malformed passphrase
+         [http://w1.fi/security/2016-1/] (CVE-2016-4476)
+       * extended channel switch support for VHT bandwidth changes
+       * added support for configuring new ANQP-elements with
+         anqp_elem=<InfoID>:<hexdump of payload>
+       * fixed Suite B 192-bit AKM to use proper PMK length
+         (note: this makes old releases incompatible with the fixed behavior)
+       * added no_probe_resp_if_max_sta=1 parameter to disable Probe Response
+         frame sending for not-associated STAs if max_num_sta limit has been
+         reached
+       * added option (-S as command line argument) to request all interfaces
+         to be started at the same time
+       * modified rts_threshold and fragm_threshold configuration parameters
+         to allow -1 to be used to disable RTS/fragmentation
+       * EAP-pwd: added support for Brainpool Elliptic Curves
+         (with OpenSSL 1.0.2 and newer)
+       * fixed EAPOL reauthentication after FT protocol run
+       * fixed FTIE generation for 4-way handshake after FT protocol run
+       * fixed and improved various FST operations
+       * TLS server
+         - support SHA384 and SHA512 hashes
+         - support TLS v1.2 signature algorithm with SHA384 and SHA512
+         - support PKCS #5 v2.0 PBES2
+         - support PKCS #5 with PKCS #12 style key decryption
+         - minimal support for PKCS #12
+         - support OCSP stapling (including ocsp_multi)
+       * added support for OpenSSL 1.1 API changes
+         - drop support for OpenSSL 0.9.8
+         - drop support for OpenSSL 1.0.0
+       * EAP-PEAP: support fast-connect crypto binding
+       * RADIUS
+         - fix Called-Station-Id to not escape SSID
+         - add Event-Timestamp to all Accounting-Request packets
+         - add Acct-Session-Id to Accounting-On/Off
+         - add Acct-Multi-Session-Id  ton Access-Request packets
+         - add Service-Type (= Frames)
+         - allow server to provide PSK instead of passphrase for WPA-PSK
+           Tunnel_password case
+         - update full message for interim accounting updates
+         - add Acct-Delay-Time into Accounting messages
+         - add require_message_authenticator configuration option to require
+           CoA/Disconnect-Request packets to be authenticated
+       * started to postpone WNM-Notification frame sending by 100 ms so that
+         the STA has some more time to configure the key before this frame is
+         received after the 4-way handshake
+       * VHT: added interoperability workaround for 80+80 and 160 MHz channels
+       * extended VLAN support (per-STA vif, etc.)
+       * fixed PMKID derivation with SAE
+       * nl80211
+         - added support for full station state operations
+         - fix IEEE 802.1X/WEP EAP reauthentication and rekeying to use
+           unencrypted EAPOL frames
+       * added initial MBO support; number of extensions to WNM BSS Transition
+         Management
+       * added initial functionality for location related operations
+       * added assocresp_elements parameter to allow vendor specific elements
+         to be added into (Re)Association Response frames
+       * improved Public Action frame addressing
+         - use Address 3 = wildcard BSSID in GAS response if a query from an
+           unassociated STA used that address
+         - fix TX status processing for Address 3 = wildcard BSSID
+         - add gas_address3 configuration parameter to control Address 3
+           behavior
+       * added command line parameter -i to override interface parameter in
+         hostapd.conf
+       * added command completion support to hostapd_cli
+       * added passive client taxonomy determination (CONFIG_TAXONOMY=y
+         compile option and "SIGNATURE <addr>" control interface command)
+       * number of small fixes
+
 2015-09-27 - v2.5
        * fixed WPS UPnP vulnerability with HTTP chunked transfer encoding
          [http://w1.fi/security/2015-2/] (CVE-2015-4141)
index a812b9d..46dffe5 100644 (file)
@@ -6,18 +6,39 @@ ifndef CFLAGS
 CFLAGS = -MMD -O2 -Wall -g
 endif
 
+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
+endif
+
 CFLAGS += $(EXTRA_CFLAGS)
 CFLAGS += -I$(abspath ../src)
 CFLAGS += -I$(abspath ../src/utils)
 
 export BINDIR ?= /usr/local/bin/
 
-# Uncomment following line and set the path to your kernel tree include
-# directory if your C library does not include all header files.
-# CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include
-
 -include .config
 
+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
@@ -63,8 +84,13 @@ 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 ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).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
@@ -74,6 +100,11 @@ 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
@@ -115,6 +146,10 @@ 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
@@ -165,22 +200,53 @@ ifdef CONFIG_NO_VLAN
 CFLAGS += -DCONFIG_NO_VLAN
 else
 OBJS += ../src/ap/vlan_init.o
-ifdef CONFIG_VLAN_NETLINK
+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
-CFLAGS += -DCONFIG_VLAN_NETLINK
 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
 
-CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
+ifndef CONFIG_NO_CTRL_IFACE
+CFLAGS += -DCONFIG_CTRL_IFACE
+endif
 
 ifdef CONFIG_IAPP
 CFLAGS += -DCONFIG_IAPP
@@ -252,6 +318,11 @@ ifdef CONFIG_IEEE80211AC
 CFLAGS += -DCONFIG_IEEE80211AC
 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)
@@ -534,6 +605,7 @@ endif
 ifeq ($(CONFIG_TLS), 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
@@ -634,6 +706,8 @@ 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
@@ -794,6 +868,16 @@ CFLAGS += -DCONFIG_SHA384
 OBJS += ../src/crypto/sha384-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_DH_GROUPS
 OBJS += ../src/crypto/dh_groups.o
 endif
@@ -835,12 +919,6 @@ ifdef CONFIG_DRIVER_RADIUS_ACL
 CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL
 endif
 
-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
-endif
-
 ifdef NEED_BASE64
 OBJS += ../src/utils/base64.o
 endif
index 366b199..5d5fd36 100644 (file)
@@ -2,7 +2,7 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
          Authenticator and RADIUS authentication server
 ================================================================
 
-Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 This program is licensed under the BSD license (the one with
index 0b1d7c7..e382c40 100644 (file)
@@ -25,6 +25,9 @@
 #LIBS += -L$(LIBNL)/lib
 CONFIG_LIBNL20=y
 
+# QCA vendor extensions to nl80211
+CONFIG_DRIVER_NL80211_QCA=y
+
 # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
 #CONFIG_DRIVER_BSD=y
 #CFLAGS += -I/usr/local/include
@@ -191,3 +194,8 @@ CONFIG_AP=y
 
 # Enable Fast Session Transfer (FST)
 #CONFIG_FST=y
+
+# Multiband Operation support
+# These extentions facilitate efficient use of multiple frequency bands
+# available to the AP and the devices that may associate with it.
+#CONFIG_MBO=y
index 82ac61d..5079f69 100644 (file)
@@ -97,6 +97,8 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
                }
 
                vlan->vlan_id = vlan_id;
+               vlan->vlan_desc.untagged = vlan_id;
+               vlan->vlan_desc.notempty = !!vlan_id;
                os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
                vlan->next = bss->vlan;
                bss->vlan = vlan;
@@ -197,7 +199,10 @@ static int hostapd_config_read_maclist(const char *fname,
 
                *acl = newacl;
                os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
-               (*acl)[*num].vlan_id = vlan_id;
+               os_memset(&(*acl)[*num].vlan_id, 0,
+                         sizeof((*acl)[*num].vlan_id));
+               (*acl)[*num].vlan_id.untagged = vlan_id;
+               (*acl)[*num].vlan_id.notempty = !!vlan_id;
                (*num)++;
        }
 
@@ -631,8 +636,7 @@ hostapd_parse_radius_attr(const char *value)
 }
 
 
-static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
-                                   const char *val)
+static int hostapd_parse_das_client(struct hostapd_bss_config *bss, char *val)
 {
        char *secret;
 
@@ -640,7 +644,7 @@ static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
        if (secret == NULL)
                return -1;
 
-       secret++;
+       *secret++ = '\0';
 
        if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
                return -1;
@@ -1519,6 +1523,54 @@ fail:
 }
 
 
+static int parse_anqp_elem(struct hostapd_bss_config *bss, char *buf, int line)
+{
+       char *delim;
+       u16 infoid;
+       size_t len;
+       struct wpabuf *payload;
+       struct anqp_element *elem;
+
+       delim = os_strchr(buf, ':');
+       if (!delim)
+               return -1;
+       delim++;
+       infoid = atoi(buf);
+       len = os_strlen(delim);
+       if (len & 1)
+               return -1;
+       len /= 2;
+       payload = wpabuf_alloc(len);
+       if (!payload)
+               return -1;
+       if (hexstr2bin(delim, wpabuf_put(payload, len), len) < 0) {
+               wpabuf_free(payload);
+               return -1;
+       }
+
+       dl_list_for_each(elem, &bss->anqp_elem, struct anqp_element, list) {
+               if (elem->infoid == infoid) {
+                       /* Update existing entry */
+                       wpabuf_free(elem->payload);
+                       elem->payload = payload;
+                       return 0;
+               }
+       }
+
+       /* Add a new entry */
+       elem = os_zalloc(sizeof(*elem));
+       if (!elem) {
+               wpabuf_free(payload);
+               return -1;
+       }
+       elem->infoid = infoid;
+       elem->payload = payload;
+       dl_list_add(&bss->anqp_elem, &elem->list);
+
+       return 0;
+}
+
+
 static int parse_qos_map_set(struct hostapd_bss_config *bss,
                             char *buf, int line)
 {
@@ -1867,31 +1919,6 @@ static int hs20_parse_osu_service_desc(struct hostapd_bss_config *bss,
 #endif /* CONFIG_HS20 */
 
 
-#ifdef CONFIG_WPS_NFC
-static struct wpabuf * hostapd_parse_bin(const char *buf)
-{
-       size_t len;
-       struct wpabuf *ret;
-
-       len = os_strlen(buf);
-       if (len & 0x01)
-               return NULL;
-       len /= 2;
-
-       ret = wpabuf_alloc(len);
-       if (ret == NULL)
-               return NULL;
-
-       if (hexstr2bin(buf, wpabuf_put(ret, len), len)) {
-               wpabuf_free(ret);
-               return NULL;
-       }
-
-       return ret;
-}
-#endif /* CONFIG_WPS_NFC */
-
-
 #ifdef CONFIG_ACS
 static int hostapd_config_parse_acs_chan_bias(struct hostapd_config *conf,
                                              char *pos)
@@ -1934,6 +1961,31 @@ fail:
 #endif /* CONFIG_ACS */
 
 
+static int parse_wpabuf_hex(int line, const char *name, struct wpabuf **buf,
+                           const char *val)
+{
+       struct wpabuf *elems;
+
+       if (val[0] == '\0') {
+               wpabuf_free(*buf);
+               *buf = NULL;
+               return 0;
+       }
+
+       elems = wpabuf_parse_bin(val);
+       if (!elems) {
+               wpa_printf(MSG_ERROR, "Line %d: Invalid %s '%s'",
+                          line, name, val);
+               return -1;
+       }
+
+       wpabuf_free(*buf);
+       *buf = elems;
+
+       return 0;
+}
+
+
 static int hostapd_config_fill(struct hostapd_config *conf,
                               struct hostapd_bss_config *bss,
                               const char *buf, char *pos, int line)
@@ -2084,6 +2136,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
        } else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
                os_free(bss->ocsp_stapling_response);
                bss->ocsp_stapling_response = os_strdup(pos);
+       } else if (os_strcmp(buf, "ocsp_stapling_response_multi") == 0) {
+               os_free(bss->ocsp_stapling_response_multi);
+               bss->ocsp_stapling_response_multi = os_strdup(pos);
        } else if (os_strcmp(buf, "dh_file") == 0) {
                os_free(bss->dh_file);
                bss->dh_file = os_strdup(pos);
@@ -2139,6 +2194,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
        } else if (os_strcmp(buf, "eap_sim_db") == 0) {
                os_free(bss->eap_sim_db);
                bss->eap_sim_db = os_strdup(pos);
+       } else if (os_strcmp(buf, "eap_sim_db_timeout") == 0) {
+               bss->eap_sim_db_timeout = atoi(pos);
        } else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
                bss->eap_sim_aka_result_ind = atoi(pos);
 #endif /* EAP_SERVER_SIM */
@@ -2353,6 +2410,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                bss->radius_das_time_window = atoi(pos);
        } else if (os_strcmp(buf, "radius_das_require_event_timestamp") == 0) {
                bss->radius_das_require_event_timestamp = atoi(pos);
+       } else if (os_strcmp(buf, "radius_das_require_message_authenticator") ==
+                  0) {
+               bss->radius_das_require_message_authenticator = atoi(pos);
 #endif /* CONFIG_NO_RADIUS */
        } else if (os_strcmp(buf, "auth_algs") == 0) {
                bss->auth_algs = atoi(pos);
@@ -2644,7 +2704,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                }
        } else if (os_strcmp(buf, "rts_threshold") == 0) {
                conf->rts_threshold = atoi(pos);
-               if (conf->rts_threshold < 0 || conf->rts_threshold > 2347) {
+               if (conf->rts_threshold < -1 || conf->rts_threshold > 65535) {
                        wpa_printf(MSG_ERROR,
                                   "Line %d: invalid rts_threshold %d",
                                   line, conf->rts_threshold);
@@ -2652,8 +2712,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                }
        } else if (os_strcmp(buf, "fragm_threshold") == 0) {
                conf->fragm_threshold = atoi(pos);
-               if (conf->fragm_threshold < 256 ||
-                   conf->fragm_threshold > 2346) {
+               if (conf->fragm_threshold == -1) {
+                       /* allow a value of -1 */
+               } else if (conf->fragm_threshold < 256 ||
+                          conf->fragm_threshold > 2346) {
                        wpa_printf(MSG_ERROR,
                                   "Line %d: invalid fragm_threshold %d",
                                   line, conf->fragm_threshold);
@@ -2686,6 +2748,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        conf->preamble = LONG_PREAMBLE;
        } else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
                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);
        } else if (os_strcmp(buf, "wep_default_key") == 0) {
                bss->ssid.wep.idx = atoi(pos);
                if (bss->ssid.wep.idx > 3) {
@@ -2707,6 +2771,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 #ifndef CONFIG_NO_VLAN
        } else if (os_strcmp(buf, "dynamic_vlan") == 0) {
                bss->ssid.dynamic_vlan = atoi(pos);
+       } else if (os_strcmp(buf, "per_sta_vif") == 0) {
+               bss->ssid.per_sta_vif = atoi(pos);
        } else if (os_strcmp(buf, "vlan_file") == 0) {
                if (hostapd_config_read_vlan_file(bss, pos)) {
                        wpa_printf(MSG_ERROR, "Line %d: failed to read VLAN file '%s'",
@@ -2762,6 +2828,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                                   line);
                        return 1;
                }
+       } 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);
@@ -2827,6 +2895,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
        } else if (os_strcmp(buf, "vendor_vht") == 0) {
                bss->vendor_vht = atoi(pos);
+       } else if (os_strcmp(buf, "use_sta_nsts") == 0) {
+               bss->use_sta_nsts = atoi(pos);
 #endif /* CONFIG_IEEE80211AC */
        } else if (os_strcmp(buf, "max_listen_interval") == 0) {
                bss->max_listen_interval = atoi(pos);
@@ -2965,15 +3035,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                bss->wps_nfc_pw_from_config = 1;
        } else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) {
                wpabuf_free(bss->wps_nfc_dh_pubkey);
-               bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos);
+               bss->wps_nfc_dh_pubkey = wpabuf_parse_bin(pos);
                bss->wps_nfc_pw_from_config = 1;
        } else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) {
                wpabuf_free(bss->wps_nfc_dh_privkey);
-               bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos);
+               bss->wps_nfc_dh_privkey = wpabuf_parse_bin(pos);
                bss->wps_nfc_pw_from_config = 1;
        } else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) {
                wpabuf_free(bss->wps_nfc_dev_pw);
-               bss->wps_nfc_dev_pw = hostapd_parse_bin(pos);
+               bss->wps_nfc_dev_pw = wpabuf_parse_bin(pos);
                bss->wps_nfc_pw_from_config = 1;
 #endif /* CONFIG_WPS_NFC */
 #endif /* CONFIG_WPS */
@@ -3136,6 +3206,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
        } else if (os_strcmp(buf, "nai_realm") == 0) {
                if (parse_nai_realm(bss, pos, line) < 0)
                        return 1;
+       } else if (os_strcmp(buf, "anqp_elem") == 0) {
+               if (parse_anqp_elem(bss, pos, line) < 0)
+                       return 1;
        } else if (os_strcmp(buf, "gas_frag_limit") == 0) {
                bss->gas_frag_limit = atoi(pos);
        } else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
@@ -3149,13 +3222,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                os_free(bss->dump_msk_file);
                bss->dump_msk_file = os_strdup(pos);
 #endif /* CONFIG_RADIUS_TEST */
+#ifdef CONFIG_PROXYARP
+       } else if (os_strcmp(buf, "proxy_arp") == 0) {
+               bss->proxy_arp = atoi(pos);
+#endif /* CONFIG_PROXYARP */
 #ifdef CONFIG_HS20
        } else if (os_strcmp(buf, "hs20") == 0) {
                bss->hs20 = atoi(pos);
        } else if (os_strcmp(buf, "disable_dgaf") == 0) {
                bss->disable_dgaf = atoi(pos);
-       } else if (os_strcmp(buf, "proxy_arp") == 0) {
-               bss->proxy_arp = atoi(pos);
        } else if (os_strcmp(buf, "na_mcast_to_ucast") == 0) {
                bss->na_mcast_to_ucast = atoi(pos);
        } else if (os_strcmp(buf, "osen") == 0) {
@@ -3231,6 +3306,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
        } else if (os_strcmp(buf, "subscr_remediation_method") == 0) {
                bss->subscr_remediation_method = atoi(pos);
 #endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+       } else if (os_strcmp(buf, "mbo") == 0) {
+               bss->mbo_enabled = atoi(pos);
+#endif /* CONFIG_MBO */
 #ifdef CONFIG_TESTING_OPTIONS
 #define PARSE_TEST_PROBABILITY(_val)                           \
        } else if (os_strcmp(buf, #_val) == 0) {                \
@@ -3249,6 +3328,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
        PARSE_TEST_PROBABILITY(ignore_assoc_probability)
        PARSE_TEST_PROBABILITY(ignore_reassoc_probability)
        PARSE_TEST_PROBABILITY(corrupt_gtk_rekey_mic_probability)
+       } else if (os_strcmp(buf, "ecsa_ie_only") == 0) {
+               conf->ecsa_ie_only = atoi(pos);
        } else if (os_strcmp(buf, "bss_load_test") == 0) {
                WPA_PUT_LE16(bss->bss_load_test, atoi(pos));
                pos = os_strchr(pos, ':');
@@ -3269,7 +3350,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                WPA_PUT_LE16(&bss->bss_load_test[3], atoi(pos));
                bss->bss_load_test_set = 1;
        } else if (os_strcmp(buf, "radio_measurements") == 0) {
-               bss->radio_measurements = atoi(pos);
+               /*
+                * DEPRECATED: This parameter will be removed in the future.
+                * Use rrm_neighbor_report instead.
+                */
+               int val = atoi(pos);
+
+               if (val & BIT(0))
+                       bss->radio_measurements[0] |=
+                               WLAN_RRM_CAPS_NEIGHBOR_REPORT;
        } else if (os_strcmp(buf, "own_ie_override") == 0) {
                struct wpabuf *tmp;
                size_t len = os_strlen(pos) / 2;
@@ -3290,35 +3379,11 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                bss->own_ie_override = tmp;
 #endif /* CONFIG_TESTING_OPTIONS */
        } else if (os_strcmp(buf, "vendor_elements") == 0) {
-               struct wpabuf *elems;
-               size_t len = os_strlen(pos);
-               if (len & 0x01) {
-                       wpa_printf(MSG_ERROR,
-                                  "Line %d: Invalid vendor_elements '%s'",
-                                  line, pos);
-                       return 1;
-               }
-               len /= 2;
-               if (len == 0) {
-                       wpabuf_free(bss->vendor_elements);
-                       bss->vendor_elements = NULL;
-                       return 0;
-               }
-
-               elems = wpabuf_alloc(len);
-               if (elems == NULL)
+               if (parse_wpabuf_hex(line, buf, &bss->vendor_elements, pos))
                        return 1;
-
-               if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
-                       wpabuf_free(elems);
-                       wpa_printf(MSG_ERROR,
-                                  "Line %d: Invalid vendor_elements '%s'",
-                                  line, pos);
+       } else if (os_strcmp(buf, "assocresp_elements") == 0) {
+               if (parse_wpabuf_hex(line, buf, &bss->assocresp_elements, pos))
                        return 1;
-               }
-
-               wpabuf_free(bss->vendor_elements);
-               bss->vendor_elements = elems;
        } else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
                bss->sae_anti_clogging_threshold = atoi(pos);
        } else if (os_strcmp(buf, "sae_groups") == 0) {
@@ -3391,7 +3456,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        return -1;
                }
                val = strtol(pos, &endp, 0);
-               if (*endp || val < 1 || val > FST_MAX_LLT_MS) {
+               if (*endp || val < 1 ||
+                   (unsigned long int) val > FST_MAX_LLT_MS) {
                        wpa_printf(MSG_ERROR,
                                   "Line %d: Invalid fst_llt %ld (%s) (expected 1..%u)",
                                   line, val, pos, FST_MAX_LLT_MS);
@@ -3409,6 +3475,22 @@ static int hostapd_config_fill(struct hostapd_config *conf,
        } else if (os_strcmp(buf, "no_auth_if_seen_on") == 0) {
                os_free(bss->no_auth_if_seen_on);
                bss->no_auth_if_seen_on = os_strdup(pos);
+       } else if (os_strcmp(buf, "lci") == 0) {
+               wpabuf_free(conf->lci);
+               conf->lci = wpabuf_parse_bin(pos);
+       } else if (os_strcmp(buf, "civic") == 0) {
+               wpabuf_free(conf->civic);
+               conf->civic = wpabuf_parse_bin(pos);
+       } else if (os_strcmp(buf, "rrm_neighbor_report") == 0) {
+               if (atoi(pos))
+                       bss->radio_measurements[0] |=
+                               WLAN_RRM_CAPS_NEIGHBOR_REPORT;
+       } else if (os_strcmp(buf, "gas_address3") == 0) {
+               bss->gas_address3 = atoi(pos);
+       } else if (os_strcmp(buf, "ftm_responder") == 0) {
+               bss->ftm_responder = atoi(pos);
+       } else if (os_strcmp(buf, "ftm_initiator") == 0) {
+               bss->ftm_initiator = atoi(pos);
        } else {
                wpa_printf(MSG_ERROR,
                           "Line %d: unknown configuration item '%s'",
@@ -3429,7 +3511,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
 {
        struct hostapd_config *conf;
        FILE *f;
-       char buf[512], *pos;
+       char buf[4096], *pos;
        int line = 0;
        int errors = 0;
        size_t i;
index cb6fb17..d7db4a7 100644 (file)
 #include <sys/stat.h>
 #include <stddef.h>
 
+#ifdef CONFIG_CTRL_IFACE_UDP
+#include <netdb.h>
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
 #include "utils/common.h"
 #include "utils/eloop.h"
+#include "utils/module_tests.h"
 #include "common/version.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ctrl_iface_common.h"
 #include "crypto/tls.h"
 #include "drivers/driver.h"
 #include "eapol_auth/eapol_auth_sm.h"
@@ -42,6 +48,8 @@
 #include "ap/wnm_ap.h"
 #include "ap/wpa_auth.h"
 #include "ap/beacon.h"
+#include "ap/neighbor_db.h"
+#include "ap/rrm.h"
 #include "wps/wps_defs.h"
 #include "wps/wps.h"
 #include "fst/fst_ctrl_iface.h"
 
 #define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
 
-struct wpa_ctrl_dst {
-       struct wpa_ctrl_dst *next;
-       struct sockaddr_un addr;
-       socklen_t addrlen;
-       int debug_level;
-       int errors;
-};
-
+#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
+#define HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT   50
+#endif /* CONFIG_CTRL_IFACE_UDP */
 
 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
                                    enum wpa_msg_type type,
@@ -66,81 +75,27 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
 
 
 static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
-                                    struct sockaddr_un *from,
+                                    struct sockaddr_storage *from,
                                     socklen_t fromlen)
 {
-       struct wpa_ctrl_dst *dst;
-
-       dst = os_zalloc(sizeof(*dst));
-       if (dst == NULL)
-               return -1;
-       os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
-       dst->addrlen = fromlen;
-       dst->debug_level = MSG_INFO;
-       dst->next = hapd->ctrl_dst;
-       hapd->ctrl_dst = dst;
-       wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
-                   (u8 *) from->sun_path,
-                   fromlen - offsetof(struct sockaddr_un, sun_path));
-       return 0;
+       return ctrl_iface_attach(&hapd->ctrl_dst, from, fromlen);
 }
 
 
 static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
-                                    struct sockaddr_un *from,
+                                    struct sockaddr_storage *from,
                                     socklen_t fromlen)
 {
-       struct wpa_ctrl_dst *dst, *prev = NULL;
-
-       dst = hapd->ctrl_dst;
-       while (dst) {
-               if (fromlen == dst->addrlen &&
-                   os_memcmp(from->sun_path, dst->addr.sun_path,
-                             fromlen - offsetof(struct sockaddr_un, sun_path))
-                   == 0) {
-                       wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
-                                   (u8 *) from->sun_path,
-                                   fromlen -
-                                   offsetof(struct sockaddr_un, sun_path));
-                       if (prev == NULL)
-                               hapd->ctrl_dst = dst->next;
-                       else
-                               prev->next = dst->next;
-                       os_free(dst);
-                       return 0;
-               }
-               prev = dst;
-               dst = dst->next;
-       }
-       return -1;
+       return ctrl_iface_detach(&hapd->ctrl_dst, from, fromlen);
 }
 
 
 static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
-                                   struct sockaddr_un *from,
+                                   struct sockaddr_storage *from,
                                    socklen_t fromlen,
                                    char *level)
 {
-       struct wpa_ctrl_dst *dst;
-
-       wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
-
-       dst = hapd->ctrl_dst;
-       while (dst) {
-               if (fromlen == dst->addrlen &&
-                   os_memcmp(from->sun_path, dst->addr.sun_path,
-                             fromlen - offsetof(struct sockaddr_un, sun_path))
-                   == 0) {
-                       wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
-                                   "level", (u8 *) from->sun_path, fromlen -
-                                   offsetof(struct sockaddr_un, sun_path));
-                       dst->debug_level = atoi(level);
-                       return 0;
-               }
-               dst = dst->next;
-       }
-
-       return -1;
+       return ctrl_iface_level(&hapd->ctrl_dst, from, fromlen, level);
 }
 
 
@@ -884,6 +839,8 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
        int ret;
        u8 nei_rep[1000];
        u8 *nei_pos = nei_rep;
+       u8 mbo[10];
+       size_t mbo_len = 0;
 
        if (hwaddr_aton(cmd, addr)) {
                wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
@@ -1049,10 +1006,66 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
        if (os_strstr(cmd, " disassoc_imminent=1"))
                req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
 
+#ifdef CONFIG_MBO
+       pos = os_strstr(cmd, "mbo=");
+       if (pos) {
+               unsigned int mbo_reason, cell_pref, reassoc_delay;
+               u8 *mbo_pos = mbo;
+
+               ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason,
+                            &reassoc_delay, &cell_pref);
+               if (ret != 3) {
+                       wpa_printf(MSG_DEBUG,
+                                  "MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
+                       return -1;
+               }
+
+               if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
+                       wpa_printf(MSG_DEBUG,
+                                  "Invalid MBO transition reason code %u",
+                                  mbo_reason);
+                       return -1;
+               }
+
+               /* Valid values for Cellular preference are: 0, 1, 255 */
+               if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) {
+                       wpa_printf(MSG_DEBUG,
+                                  "Invalid MBO cellular capability %u",
+                                  cell_pref);
+                       return -1;
+               }
+
+               if (reassoc_delay > 65535 ||
+                   (reassoc_delay &&
+                    !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) {
+                       wpa_printf(MSG_DEBUG,
+                                  "MBO: Assoc retry delay is only valid in disassoc imminent mode");
+                       return -1;
+               }
+
+               *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
+               *mbo_pos++ = 1;
+               *mbo_pos++ = mbo_reason;
+               *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
+               *mbo_pos++ = 1;
+               *mbo_pos++ = cell_pref;
+
+               if (reassoc_delay) {
+                       *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
+                       *mbo_pos++ = 2;
+                       WPA_PUT_LE16(mbo_pos, reassoc_delay);
+                       mbo_pos += 2;
+               }
+
+               mbo_len = mbo_pos - mbo;
+       }
+#endif /* CONFIG_MBO */
+
        ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
                                  valid_int, bss_term_dur, url,
                                  nei_pos > nei_rep ? nei_rep : NULL,
-                                 nei_pos - nei_rep);
+                                 nei_pos - nei_rep, mbo_len ? mbo : NULL,
+                                 mbo_len);
        os_free(url);
        return ret;
 }
@@ -1320,9 +1333,28 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
        } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
                hapd->ext_eapol_frame_io = atoi(value);
 #endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_MBO
+       } else if (os_strcasecmp(cmd, "mbo_assoc_disallow") == 0) {
+               int val;
+
+               if (!hapd->conf->mbo_enabled)
+                       return -1;
+
+               val = atoi(value);
+               if (val < 0 || val > 1)
+                       return -1;
+
+               hapd->mbo_assoc_disallow = val;
+               ieee802_11_update_beacons(hapd->iface);
+
+               /*
+                * TODO: Need to configure drivers that do AP MLME offload with
+                * disallowing station logic.
+                */
+#endif /* CONFIG_MBO */
        } else {
                struct sta_info *sta;
-               int vlan_id;
+               struct vlan_description vlan_id;
 
                ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
                if (ret)
@@ -1334,7 +1366,8 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
                                            hapd->conf->deny_mac,
                                            hapd->conf->num_deny_mac, sta->addr,
                                            &vlan_id) &&
-                                   (!vlan_id || vlan_id == sta->vlan_id))
+                                   (!vlan_id.notempty ||
+                                    !vlan_compare(&vlan_id, sta->vlan_desc)))
                                        ap_sta_disconnect(
                                                hapd, sta, sta->addr,
                                                WLAN_REASON_UNSPECIFIED);
@@ -1346,7 +1379,8 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
                                            hapd->conf->accept_mac,
                                            hapd->conf->num_accept_mac,
                                            sta->addr, &vlan_id) ||
-                                   (vlan_id && vlan_id != sta->vlan_id))
+                                   (vlan_id.notempty &&
+                                    vlan_compare(&vlan_id, sta->vlan_desc)))
                                        ap_sta_disconnect(
                                                hapd, sta, sta->addr,
                                                WLAN_REASON_UNSPECIFIED);
@@ -1557,8 +1591,8 @@ static u16 ipv4_hdr_checksum(const void *buf, size_t len)
 #define HWSIM_PACKETLEN 1500
 #define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
 
-void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
-                         size_t len)
+static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
+                                size_t len)
 {
        struct hostapd_data *hapd = ctx;
        const struct ether_header *eth;
@@ -1745,8 +1779,6 @@ done:
 static int hostapd_ctrl_test_alloc_fail(struct hostapd_data *hapd, char *cmd)
 {
 #ifdef WPA_TRACE_BFD
-       extern char wpa_trace_fail_func[256];
-       extern unsigned int wpa_trace_fail_after;
        char *pos;
 
        wpa_trace_fail_after = atoi(cmd);
@@ -1770,9 +1802,6 @@ static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd,
                                       char *buf, size_t buflen)
 {
 #ifdef WPA_TRACE_BFD
-       extern char wpa_trace_fail_func[256];
-       extern unsigned int wpa_trace_fail_after;
-
        return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
                           wpa_trace_fail_func);
 #else /* WPA_TRACE_BFD */
@@ -1784,8 +1813,6 @@ static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd,
 static int hostapd_ctrl_test_fail(struct hostapd_data *hapd, char *cmd)
 {
 #ifdef WPA_TRACE_BFD
-       extern char wpa_trace_test_fail_func[256];
-       extern unsigned int wpa_trace_test_fail_after;
        char *pos;
 
        wpa_trace_test_fail_after = atoi(cmd);
@@ -1809,9 +1836,6 @@ static int hostapd_ctrl_get_fail(struct hostapd_data *hapd,
                                 char *buf, size_t buflen)
 {
 #ifdef WPA_TRACE_BFD
-       extern char wpa_trace_test_fail_func[256];
-       extern unsigned int wpa_trace_test_fail_after;
-
        return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
                           wpa_trace_test_fail_func);
 #else /* WPA_TRACE_BFD */
@@ -1875,13 +1899,13 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
 
        /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
        vendor_id = strtoul(cmd, &pos, 16);
-       if (!isblank(*pos))
+       if (!isblank((unsigned char) *pos))
                return -EINVAL;
 
        subcmd = strtoul(pos, &pos, 10);
 
        if (*pos != '\0') {
-               if (!isblank(*pos++))
+               if (!isblank((unsigned char) *pos++))
                        return -EINVAL;
                data_len = os_strlen(pos);
        }
@@ -2016,6 +2040,9 @@ static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd,
        struct hostapd_sta_info *info;
        struct os_reltime now;
 
+       if (!iface->num_sta_seen)
+               return 0;
+
        sta_track_expire(iface, 0);
 
        pos = buf;
@@ -2040,10 +2067,228 @@ static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd,
 #endif /* NEED_AP_MLME */
 
 
+static int hostapd_ctrl_iface_req_lci(struct hostapd_data *hapd,
+                                     const char *cmd)
+{
+       u8 addr[ETH_ALEN];
+
+       if (hwaddr_aton(cmd, addr)) {
+               wpa_printf(MSG_INFO, "CTRL: REQ_LCI: Invalid MAC address");
+               return -1;
+       }
+
+       return hostapd_send_lci_req(hapd, addr);
+}
+
+
+static int hostapd_ctrl_iface_req_range(struct hostapd_data *hapd, char *cmd)
+{
+       u8 addr[ETH_ALEN];
+       char *token, *context = NULL;
+       int random_interval, min_ap;
+       u8 responders[ETH_ALEN * RRM_RANGE_REQ_MAX_RESPONDERS];
+       unsigned int n_responders;
+
+       token = str_token(cmd, " ", &context);
+       if (!token || hwaddr_aton(token, addr)) {
+               wpa_printf(MSG_INFO,
+                          "CTRL: REQ_RANGE - Bad destination address");
+               return -1;
+       }
+
+       token = str_token(cmd, " ", &context);
+       if (!token)
+               return -1;
+
+       random_interval = atoi(token);
+       if (random_interval < 0 || random_interval > 0xffff)
+               return -1;
+
+       token = str_token(cmd, " ", &context);
+       if (!token)
+               return -1;
+
+       min_ap = atoi(token);
+       if (min_ap <= 0 || min_ap > WLAN_RRM_RANGE_REQ_MAX_MIN_AP)
+               return -1;
+
+       n_responders = 0;
+       while ((token = str_token(cmd, " ", &context))) {
+               if (n_responders == RRM_RANGE_REQ_MAX_RESPONDERS) {
+                       wpa_printf(MSG_INFO,
+                                  "CTRL: REQ_RANGE: Too many responders");
+                       return -1;
+               }
+
+               if (hwaddr_aton(token, responders + n_responders * ETH_ALEN)) {
+                       wpa_printf(MSG_INFO,
+                                  "CTRL: REQ_RANGE: Bad responder address");
+                       return -1;
+               }
+
+               n_responders++;
+       }
+
+       if (!n_responders) {
+               wpa_printf(MSG_INFO,
+                          "CTRL: REQ_RANGE - No FTM responder address");
+               return -1;
+       }
+
+       return hostapd_send_range_req(hapd, addr, random_interval, min_ap,
+                                     responders, n_responders);
+}
+
+
+static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
+{
+       struct wpa_ssid_value ssid;
+       u8 bssid[ETH_ALEN];
+       struct wpabuf *nr, *lci = NULL, *civic = NULL;
+       char *tmp;
+       int ret;
+
+       if (!(hapd->conf->radio_measurements[0] &
+             WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
+               wpa_printf(MSG_ERROR,
+                          "CTRL: SET_NEIGHBOR: Neighbor report is not enabled");
+               return -1;
+       }
+
+       if (hwaddr_aton(buf, bssid)) {
+               wpa_printf(MSG_ERROR, "CTRL: SET_NEIGHBOR: Bad BSSID");
+               return -1;
+       }
+
+       tmp = os_strstr(buf, "ssid=");
+       if (!tmp || ssid_parse(tmp + 5, &ssid)) {
+               wpa_printf(MSG_ERROR,
+                          "CTRL: SET_NEIGHBOR: Bad or missing SSID");
+               return -1;
+       }
+       buf = os_strchr(tmp + 6, tmp[5] == '"' ? '"' : ' ');
+       if (!buf)
+               return -1;
+
+       tmp = os_strstr(buf, "nr=");
+       if (!tmp) {
+               wpa_printf(MSG_ERROR,
+                          "CTRL: SET_NEIGHBOR: Missing Neighbor Report element");
+               return -1;
+       }
+
+       buf = os_strchr(tmp, ' ');
+       if (buf)
+               *buf++ = '\0';
+
+       nr = wpabuf_parse_bin(tmp + 3);
+       if (!nr) {
+               wpa_printf(MSG_ERROR,
+                          "CTRL: SET_NEIGHBOR: Bad Neighbor Report element");
+               return -1;
+       }
+
+       if (!buf)
+               goto set;
+
+       tmp = os_strstr(buf, "lci=");
+       if (tmp) {
+               buf = os_strchr(tmp, ' ');
+               if (buf)
+                       *buf++ = '\0';
+               lci = wpabuf_parse_bin(tmp + 4);
+               if (!lci) {
+                       wpa_printf(MSG_ERROR,
+                                  "CTRL: SET_NEIGHBOR: Bad LCI subelement");
+                       wpabuf_free(nr);
+                       return -1;
+               }
+       }
+
+       if (!buf)
+               goto set;
+
+       tmp = os_strstr(buf, "civic=");
+       if (tmp) {
+               buf = os_strchr(tmp, ' ');
+               if (buf)
+                       *buf++ = '\0';
+               civic = wpabuf_parse_bin(tmp + 6);
+               if (!civic) {
+                       wpa_printf(MSG_ERROR,
+                                  "CTRL: SET_NEIGHBOR: Bad civic subelement");
+                       wpabuf_free(nr);
+                       wpabuf_free(lci);
+                       return -1;
+               }
+       }
+
+set:
+       ret = hostapd_neighbor_set(hapd, bssid, &ssid, nr, lci, civic);
+
+       wpabuf_free(nr);
+       wpabuf_free(lci);
+       wpabuf_free(civic);
+
+       return ret;
+}
+
+
+static int hostapd_ctrl_iface_remove_neighbor(struct hostapd_data *hapd,
+                                             char *buf)
+{
+       struct wpa_ssid_value ssid;
+       u8 bssid[ETH_ALEN];
+       char *tmp;
+
+       if (hwaddr_aton(buf, bssid)) {
+               wpa_printf(MSG_ERROR, "CTRL: REMOVE_NEIGHBOR: Bad BSSID");
+               return -1;
+       }
+
+       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;
+       }
+
+       return hostapd_neighbor_remove(hapd, bssid, &ssid);
+}
+
+
+static int hostapd_ctrl_driver_flags(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_flags);
+       if (os_snprintf_error(buflen, ret))
+               return -1;
+
+       pos = buf + ret;
+       end = buf + buflen;
+
+       for (i = 0; i < 64; i++) {
+               if (iface->drv_flags & (1LLU << i)) {
+                       ret = os_snprintf(pos, end - pos, "%s\n",
+                                         driver_flag_to_string(1LLU << i));
+                       if (os_snprintf_error(end - pos, ret))
+                               return -1;
+                       pos += ret;
+               }
+       }
+
+       return pos - buf;
+}
+
+
 static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
                                              char *buf, char *reply,
                                              int reply_size,
-                                             struct sockaddr_un *from,
+                                             struct sockaddr_storage *from,
                                              socklen_t fromlen)
 {
        int reply_len, res;
@@ -2122,6 +2367,14 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
        } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
                if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
                        reply_len = -1;
+#ifdef CONFIG_TAXONOMY
+       } else if (os_strncmp(buf, "SIGNATURE ", 10) == 0) {
+               reply_len = hostapd_ctrl_iface_signature(hapd, buf + 10,
+                                                        reply, reply_size);
+#endif /* CONFIG_TAXONOMY */
+       } else if (os_strncmp(buf, "POLL_STA ", 9) == 0) {
+               if (hostapd_ctrl_iface_poll_sta(hapd, buf + 9))
+                       reply_len = -1;
        } else if (os_strcmp(buf, "STOP_AP") == 0) {
                if (hostapd_ctrl_iface_stop_ap(hapd))
                        reply_len = -1;
@@ -2276,6 +2529,26 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
                reply_len = hostapd_ctrl_iface_track_sta_list(
                        hapd, reply, reply_size);
 #endif /* NEED_AP_MLME */
+       } else if (os_strcmp(buf, "PMKSA") == 0) {
+               reply_len = hostapd_ctrl_iface_pmksa_list(hapd, reply,
+                                                         reply_size);
+       } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
+               hostapd_ctrl_iface_pmksa_flush(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_strncmp(buf, "REMOVE_NEIGHBOR ", 16) == 0) {
+               if (hostapd_ctrl_iface_remove_neighbor(hapd, buf + 16))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "REQ_LCI ", 8) == 0) {
+               if (hostapd_ctrl_iface_req_lci(hapd, buf + 8))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "REQ_RANGE ", 10) == 0) {
+               if (hostapd_ctrl_iface_req_range(hapd, buf + 10))
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
+               reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply,
+                                                     reply_size);
        } else {
                os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
                reply_len = 16;
@@ -2296,12 +2569,15 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
        struct hostapd_data *hapd = eloop_ctx;
        char buf[4096];
        int res;
-       struct sockaddr_un from;
+       struct sockaddr_storage from;
        socklen_t fromlen = sizeof(from);
-       char *reply;
+       char *reply, *pos = buf;
        const int reply_size = 4096;
        int reply_len;
        int level = MSG_DEBUG;
+#ifdef CONFIG_CTRL_IFACE_UDP
+       unsigned char lcookie[COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
 
        res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
                       (struct sockaddr *) &from, &fromlen);
@@ -2311,9 +2587,6 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
                return;
        }
        buf[res] = '\0';
-       if (os_strcmp(buf, "PING") == 0)
-               level = MSG_EXCESSIVE;
-       wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res);
 
        reply = os_malloc(reply_size);
        if (reply == NULL) {
@@ -2325,10 +2598,46 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
                return;
        }
 
-       reply_len = hostapd_ctrl_iface_receive_process(hapd, buf,
+#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;
+               goto done;
+       }
+
+       if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
+           hexstr2bin(buf + 7, lcookie, 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) {
+               wpa_printf(MSG_DEBUG,
+                          "CTRL: Invalid cookie in the request - drop request");
+               os_free(reply);
+               return;
+       }
+
+       pos = buf + 7 + 2 * COOKIE_LEN;
+       while (*pos == ' ')
+               pos++;
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
+       if (os_strcmp(pos, "PING") == 0)
+               level = MSG_EXCESSIVE;
+       wpa_hexdump_ascii(level, "RX ctrl_iface", pos, res);
+
+       reply_len = hostapd_ctrl_iface_receive_process(hapd, pos,
                                                       reply, reply_size,
                                                       &from, fromlen);
 
+#ifdef CONFIG_CTRL_IFACE_UDP
+done:
+#endif /* CONFIG_CTRL_IFACE_UDP */
        if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
                   fromlen) < 0) {
                wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
@@ -2338,6 +2647,7 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
 }
 
 
+#ifndef CONFIG_CTRL_IFACE_UDP
 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
 {
        char *buf;
@@ -2357,6 +2667,7 @@ static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
        buf[len - 1] = '\0';
        return buf;
 }
+#endif /* CONFIG_CTRL_IFACE_UDP */
 
 
 static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
@@ -2372,6 +2683,99 @@ static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
 
 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
 {
+#ifdef CONFIG_CTRL_IFACE_UDP
+       int port = HOSTAPD_CTRL_IFACE_PORT;
+       char p[32] = { 0 };
+       char port_str[40], *tmp;
+       char *pos;
+       struct addrinfo hints = { 0 }, *res, *saveres;
+       int n;
+
+       if (hapd->ctrl_sock > -1) {
+               wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
+               return 0;
+       }
+
+       if (hapd->conf->ctrl_interface == NULL)
+               return 0;
+
+       pos = os_strstr(hapd->conf->ctrl_interface, "udp:");
+       if (pos) {
+               pos += 4;
+               port = atoi(pos);
+               if (port <= 0) {
+                       wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port");
+                       goto fail;
+               }
+       }
+
+       dl_list_init(&hapd->ctrl_dst);
+       hapd->ctrl_sock = -1;
+       os_get_random(cookie, COOKIE_LEN);
+
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+       hints.ai_flags = AI_PASSIVE;
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       hints.ai_family = AF_INET6;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+       hints.ai_family = AF_INET;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+       hints.ai_socktype = SOCK_DGRAM;
+
+try_again:
+       os_snprintf(p, sizeof(p), "%d", port);
+       n = getaddrinfo(NULL, p, &hints, &res);
+       if (n) {
+               wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
+               goto fail;
+       }
+
+       saveres = res;
+       hapd->ctrl_sock = socket(res->ai_family, res->ai_socktype,
+                                res->ai_protocol);
+       if (hapd->ctrl_sock < 0) {
+               wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
+               goto fail;
+       }
+
+       if (bind(hapd->ctrl_sock, res->ai_addr, res->ai_addrlen) < 0) {
+               port--;
+               if ((HOSTAPD_CTRL_IFACE_PORT - port) <
+                   HOSTAPD_CTRL_IFACE_PORT_LIMIT && !pos)
+                       goto try_again;
+               wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
+               goto fail;
+       }
+
+       freeaddrinfo(saveres);
+
+       os_snprintf(port_str, sizeof(port_str), "udp:%d", port);
+       tmp = os_strdup(port_str);
+       if (tmp) {
+               os_free(hapd->conf->ctrl_interface);
+               hapd->conf->ctrl_interface = tmp;
+       }
+       wpa_printf(MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
+
+       if (eloop_register_read_sock(hapd->ctrl_sock,
+                                    hostapd_ctrl_iface_receive, hapd, NULL) <
+           0) {
+               hostapd_ctrl_iface_deinit(hapd);
+               return -1;
+       }
+
+       hapd->msg_ctx = hapd;
+       wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
+
+       return 0;
+
+fail:
+       if (hapd->ctrl_sock >= 0)
+               close(hapd->ctrl_sock);
+       return -1;
+#else /* CONFIG_CTRL_IFACE_UDP */
        struct sockaddr_un addr;
        int s = -1;
        char *fname = NULL;
@@ -2381,6 +2785,8 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
                return 0;
        }
 
+       dl_list_init(&hapd->ctrl_dst);
+
        if (hapd->conf->ctrl_interface == NULL)
                return 0;
 
@@ -2520,6 +2926,7 @@ fail:
                os_free(fname);
        }
        return -1;
+#endif /* CONFIG_CTRL_IFACE_UDP */
 }
 
 
@@ -2528,10 +2935,14 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
        struct wpa_ctrl_dst *dst, *prev;
 
        if (hapd->ctrl_sock > -1) {
+#ifndef CONFIG_CTRL_IFACE_UDP
                char *fname;
+#endif /* !CONFIG_CTRL_IFACE_UDP */
+
                eloop_unregister_read_sock(hapd->ctrl_sock);
                close(hapd->ctrl_sock);
                hapd->ctrl_sock = -1;
+#ifndef CONFIG_CTRL_IFACE_UDP
                fname = hostapd_ctrl_iface_path(hapd);
                if (fname)
                        unlink(fname);
@@ -2550,15 +2961,12 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
                                           strerror(errno));
                        }
                }
+#endif /* !CONFIG_CTRL_IFACE_UDP */
        }
 
-       dst = hapd->ctrl_dst;
-       hapd->ctrl_dst = NULL;
-       while (dst) {
-               prev = dst;
-               dst = dst->next;
-               os_free(prev);
-       }
+       dl_list_for_each_safe(dst, prev, &hapd->ctrl_dst, struct wpa_ctrl_dst,
+                             list)
+               os_free(dst);
 
 #ifdef CONFIG_TESTING_OPTIONS
        l2_packet_deinit(hapd->l2_test);
@@ -2590,54 +2998,18 @@ static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
 
 
 static int hostapd_global_ctrl_iface_attach(struct hapd_interfaces *interfaces,
-                                           struct sockaddr_un *from,
+                                           struct sockaddr_storage *from,
                                            socklen_t fromlen)
 {
-       struct wpa_ctrl_dst *dst;
-
-       dst = os_zalloc(sizeof(*dst));
-       if (dst == NULL)
-               return -1;
-       os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
-       dst->addrlen = fromlen;
-       dst->debug_level = MSG_INFO;
-       dst->next = interfaces->global_ctrl_dst;
-       interfaces->global_ctrl_dst = dst;
-       wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached (global)",
-                   from->sun_path,
-                   fromlen - offsetof(struct sockaddr_un, sun_path));
-       return 0;
+       return ctrl_iface_attach(&interfaces->global_ctrl_dst, from, fromlen);
 }
 
 
 static int hostapd_global_ctrl_iface_detach(struct hapd_interfaces *interfaces,
-                                           struct sockaddr_un *from,
+                                           struct sockaddr_storage *from,
                                            socklen_t fromlen)
 {
-       struct wpa_ctrl_dst *dst, *prev = NULL;
-
-       dst = interfaces->global_ctrl_dst;
-       while (dst) {
-               if (fromlen == dst->addrlen &&
-                   os_memcmp(from->sun_path, dst->addr.sun_path,
-                             fromlen - offsetof(struct sockaddr_un, sun_path))
-                   == 0) {
-                       wpa_hexdump(MSG_DEBUG,
-                                   "CTRL_IFACE monitor detached (global)",
-                                   from->sun_path,
-                                   fromlen -
-                                   offsetof(struct sockaddr_un, sun_path));
-                       if (prev == NULL)
-                               interfaces->global_ctrl_dst = dst->next;
-                       else
-                               prev->next = dst->next;
-                       os_free(dst);
-                       return 0;
-               }
-               prev = dst;
-               dst = dst->next;
-       }
-       return -1;
+       return ctrl_iface_detach(&interfaces->global_ctrl_dst, from, fromlen);
 }
 
 
@@ -2791,6 +3163,51 @@ error_return:
 
 
 static int
+hostapd_global_ctrl_iface_interfaces(struct hapd_interfaces *interfaces,
+                                    const char *input,
+                                    char *reply, int reply_size)
+{
+       size_t i, j;
+       int res;
+       char *pos, *end;
+       struct hostapd_iface *iface;
+       int show_ctrl = 0;
+
+       if (input)
+               show_ctrl = !!os_strstr(input, "ctrl");
+
+       pos = reply;
+       end = reply + reply_size;
+
+       for (i = 0; i < interfaces->count; i++) {
+               iface = interfaces->iface[i];
+
+               for (j = 0; j < iface->num_bss; j++) {
+                       struct hostapd_bss_config *conf;
+
+                       conf = iface->conf->bss[j];
+                       if (show_ctrl)
+                               res = os_snprintf(pos, end - pos,
+                                                 "%s ctrl_iface=%s\n",
+                                                 conf->iface,
+                                                 conf->ctrl_interface ?
+                                                 conf->ctrl_interface : "N/A");
+                       else
+                               res = os_snprintf(pos, end - pos, "%s\n",
+                                                 conf->iface);
+                       if (os_snprintf_error(end - pos, res)) {
+                               *pos = '\0';
+                               return pos - reply;
+                       }
+                       pos += res;
+               }
+       }
+
+       return pos - reply;
+}
+
+
+static int
 hostapd_global_ctrl_iface_dup_network(struct hapd_interfaces *interfaces,
                                      char *cmd)
 {
@@ -2839,7 +3256,7 @@ static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces,
                                            const char *ifname,
                                            char *buf, char *reply,
                                            int reply_size,
-                                           struct sockaddr_un *from,
+                                           struct sockaddr_storage *from,
                                            socklen_t fromlen)
 {
        struct hostapd_data *hapd;
@@ -2863,15 +3280,18 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
                                              void *sock_ctx)
 {
        void *interfaces = eloop_ctx;
-       char buf[256];
+       char buffer[256], *buf = buffer;
        int res;
-       struct sockaddr_un from;
+       struct sockaddr_storage from;
        socklen_t fromlen = sizeof(from);
        char *reply;
        int reply_len;
        const int reply_size = 4096;
+#ifdef CONFIG_CTRL_IFACE_UDP
+       unsigned char lcookie[COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
 
-       res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+       res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0,
                       (struct sockaddr *) &from, &fromlen);
        if (res < 0) {
                wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
@@ -2894,6 +3314,35 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
        os_memcpy(reply, "OK\n", 3);
        reply_len = 3;
 
+#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;
+               goto send_reply;
+       }
+
+       if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
+           hexstr2bin(buf + 7, lcookie, 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) {
+               wpa_printf(MSG_DEBUG,
+                          "CTRL: Invalid cookie in the request - drop request");
+               os_free(reply);
+               return;
+       }
+
+       buf += 7 + 2 * COOKIE_LEN;
+       while (*buf == ' ')
+               buf++;
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
        if (os_strncmp(buf, "IFNAME=", 7) == 0) {
                char *pos = os_strchr(buf + 7, ' ');
 
@@ -2930,7 +3379,6 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
                        reply_len = -1;
 #ifdef CONFIG_MODULE_TESTS
        } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
-               int hapd_module_tests(void);
                if (hapd_module_tests() < 0)
                        reply_len = -1;
 #endif /* CONFIG_MODULE_TESTS */
@@ -2954,6 +3402,11 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
                        reply_len = os_snprintf(reply, reply_size, "OK\n");
                else
                        reply_len = -1;
+       } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
+               reply_len = hostapd_global_ctrl_iface_interfaces(
+                       interfaces, buf + 10, reply, sizeof(buffer));
+       } else if (os_strcmp(buf, "TERMINATE") == 0) {
+               eloop_terminate();
        } else {
                wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
                           "ignored");
@@ -2975,6 +3428,7 @@ send_reply:
 }
 
 
+#ifndef CONFIG_CTRL_IFACE_UDP
 static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
 {
        char *buf;
@@ -2994,10 +3448,95 @@ static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
        buf[len - 1] = '\0';
        return buf;
 }
+#endif /* CONFIG_CTRL_IFACE_UDP */
 
 
 int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
 {
+#ifdef CONFIG_CTRL_IFACE_UDP
+       int port = HOSTAPD_GLOBAL_CTRL_IFACE_PORT;
+       char p[32] = { 0 };
+       char *pos;
+       struct addrinfo hints = { 0 }, *res, *saveres;
+       int n;
+
+       if (interface->global_ctrl_sock > -1) {
+               wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
+               return 0;
+       }
+
+       if (interface->global_iface_path == NULL)
+               return 0;
+
+       pos = os_strstr(interface->global_iface_path, "udp:");
+       if (pos) {
+               pos += 4;
+               port = atoi(pos);
+               if (port <= 0) {
+                       wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port");
+                       goto fail;
+               }
+       }
+
+       dl_list_init(&interface->global_ctrl_dst);
+       interface->global_ctrl_sock = -1;
+       os_get_random(gcookie, COOKIE_LEN);
+
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+       hints.ai_flags = AI_PASSIVE;
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       hints.ai_family = AF_INET6;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+       hints.ai_family = AF_INET;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+       hints.ai_socktype = SOCK_DGRAM;
+
+try_again:
+       os_snprintf(p, sizeof(p), "%d", port);
+       n = getaddrinfo(NULL, p, &hints, &res);
+       if (n) {
+               wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
+               goto fail;
+       }
+
+       saveres = res;
+       interface->global_ctrl_sock = socket(res->ai_family, res->ai_socktype,
+                                            res->ai_protocol);
+       if (interface->global_ctrl_sock < 0) {
+               wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
+               goto fail;
+       }
+
+       if (bind(interface->global_ctrl_sock, res->ai_addr, res->ai_addrlen) <
+           0) {
+               port++;
+               if ((port - HOSTAPD_GLOBAL_CTRL_IFACE_PORT) <
+                   HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos)
+                       goto try_again;
+               wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
+               goto fail;
+       }
+
+       freeaddrinfo(saveres);
+
+       wpa_printf(MSG_DEBUG, "global ctrl_iface_init UDP port: %d", port);
+
+       if (eloop_register_read_sock(interface->global_ctrl_sock,
+                                    hostapd_global_ctrl_iface_receive,
+                                    interface, NULL) < 0) {
+               hostapd_global_ctrl_iface_deinit(interface);
+               return -1;
+       }
+
+       return 0;
+
+fail:
+       if (interface->global_ctrl_sock >= 0)
+               close(interface->global_ctrl_sock);
+       return -1;
+#else /* CONFIG_CTRL_IFACE_UDP */
        struct sockaddr_un addr;
        int s = -1;
        char *fname = NULL;
@@ -3103,18 +3642,22 @@ fail:
                os_free(fname);
        }
        return -1;
+#endif /* CONFIG_CTRL_IFACE_UDP */
 }
 
 
 void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
 {
+#ifndef CONFIG_CTRL_IFACE_UDP
        char *fname = NULL;
+#endif /* CONFIG_CTRL_IFACE_UDP */
        struct wpa_ctrl_dst *dst, *prev;
 
        if (interfaces->global_ctrl_sock > -1) {
                eloop_unregister_read_sock(interfaces->global_ctrl_sock);
                close(interfaces->global_ctrl_sock);
                interfaces->global_ctrl_sock = -1;
+#ifndef CONFIG_CTRL_IFACE_UDP
                fname = hostapd_global_ctrl_iface_path(interfaces);
                if (fname) {
                        unlink(fname);
@@ -3134,18 +3677,15 @@ void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
                                           strerror(errno));
                        }
                }
+#endif /* CONFIG_CTRL_IFACE_UDP */
        }
 
        os_free(interfaces->global_iface_path);
        interfaces->global_iface_path = NULL;
 
-       dst = interfaces->global_ctrl_dst;
-       interfaces->global_ctrl_dst = NULL;
-       while (dst) {
-               prev = dst;
-               dst = dst->next;
-               os_free(prev);
-       }
+       dl_list_for_each_safe(dst, prev, &interfaces->global_ctrl_dst,
+                             struct wpa_ctrl_dst, list)
+               os_free(dst);
 }
 
 
@@ -3154,6 +3694,7 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, 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];
@@ -3162,13 +3703,13 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
 
        if (type != WPA_MSG_ONLY_GLOBAL) {
                s = hapd->ctrl_sock;
-               dst = hapd->ctrl_dst;
+               ctrl_dst = &hapd->ctrl_dst;
        } else {
                s = hapd->iface->interfaces->global_ctrl_sock;
-               dst = hapd->iface->interfaces->global_ctrl_dst;
+               ctrl_dst = &hapd->iface->interfaces->global_ctrl_dst;
        }
 
-       if (s < 0 || dst == NULL)
+       if (s < 0 || dl_list_empty(ctrl_dst))
                return;
 
        os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
@@ -3181,12 +3722,10 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
        msg.msg_iovlen = 2;
 
        idx = 0;
-       while (dst) {
-               next = dst->next;
+       dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
                if (level >= dst->debug_level) {
-                       wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
-                                   (u8 *) dst->addr.sun_path, dst->addrlen -
-                                   offsetof(struct sockaddr_un, sun_path));
+                       sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor send",
+                                      &dst->addr, dst->addrlen);
                        msg.msg_name = &dst->addr;
                        msg.msg_namelen = dst->addrlen;
                        if (sendmsg(s, &msg, 0) < 0) {
@@ -3210,7 +3749,6 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
                                dst->errors = 0;
                }
                idx++;
-               dst = next;
        }
 }
 
index 430f758..4659dd1 100644 (file)
@@ -18,6 +18,9 @@ CONFIG_DRIVER_HOSTAP=y
 # Driver interface for drivers using the nl80211 kernel interface
 CONFIG_DRIVER_NL80211=y
 
+# QCA vendor extensions to nl80211
+#CONFIG_DRIVER_NL80211_QCA=y
+
 # driver_nl80211.c requires libnl. If you are compiling it yourself
 # you may need to point hostapd to your version of libnl.
 #
@@ -246,6 +249,9 @@ CONFIG_IPV6=y
 # Should we use epoll instead of select? Select is used by default.
 #CONFIG_ELOOP_EPOLL=y
 
+# Should we use kqueue instead of select? Select is used by default.
+#CONFIG_ELOOP_KQUEUE=y
+
 # Select TLS implementation
 # openssl = OpenSSL (default)
 # gnutls = GnuTLS
@@ -326,3 +332,14 @@ CONFIG_IPV6=y
 # http://wireless.kernel.org/en/users/Documentation/acs
 #
 #CONFIG_ACS=y
+
+# Multiband Operation support
+# These extentions facilitate efficient use of multiple frequency bands
+# available to the AP and the devices that may associate with it.
+#CONFIG_MBO=y
+
+# Client Taxonomy
+# Has the AP retain the Probe Request and (Re)Association Request frames from
+# a client, from which a signature can be produced which can identify the model
+# of client device like "Nexus 6P" or "iPhone 5s".
+#CONFIG_TAXONOMY=y
index f7887eb..a5016f2 100644 (file)
@@ -9,6 +9,7 @@
 #include "utils/includes.h"
 
 #include "utils/common.h"
+#include "utils/module_tests.h"
 
 int hapd_module_tests(void)
 {
index 84d0308..2117d34 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
- * Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2007, 2012-2016, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -284,7 +284,7 @@ static int read_gsm_triplets(const char *fname)
 
        f = fopen(fname, "r");
        if (f == NULL) {
-               printf("Could not open GSM tripler data file '%s'\n", fname);
+               printf("Could not open GSM triplet data file '%s'\n", fname);
                return -1;
        }
 
@@ -312,66 +312,40 @@ static int read_gsm_triplets(const char *fname)
                }
 
                /* IMSI */
-               pos2 = strchr(pos, ':');
-               if (pos2 == NULL) {
-                       printf("%s:%d - Invalid IMSI (%s)\n",
-                              fname, line, pos);
-                       ret = -1;
-                       break;
-               }
-               *pos2 = '\0';
-               if (strlen(pos) >= sizeof(g->imsi)) {
-                       printf("%s:%d - Too long IMSI (%s)\n",
-                              fname, line, pos);
+               pos2 = NULL;
+               pos = str_token(buf, ":", &pos2);
+               if (!pos || os_strlen(pos) >= sizeof(g->imsi)) {
+                       printf("%s:%d - Invalid IMSI\n", fname, line);
                        ret = -1;
                        break;
                }
                os_strlcpy(g->imsi, pos, sizeof(g->imsi));
-               pos = pos2 + 1;
 
                /* Kc */
-               pos2 = strchr(pos, ':');
-               if (pos2 == NULL) {
-                       printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
-                       ret = -1;
-                       break;
-               }
-               *pos2 = '\0';
-               if (strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) {
-                       printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
+               pos = str_token(buf, ":", &pos2);
+               if (!pos || os_strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) {
+                       printf("%s:%d - Invalid Kc\n", fname, line);
                        ret = -1;
                        break;
                }
-               pos = pos2 + 1;
 
                /* SRES */
-               pos2 = strchr(pos, ':');
-               if (pos2 == NULL) {
-                       printf("%s:%d - Invalid SRES (%s)\n", fname, line,
-                              pos);
+               pos = str_token(buf, ":", &pos2);
+               if (!pos || os_strlen(pos) != 8 ||
+                   hexstr2bin(pos, g->sres, 4)) {
+                       printf("%s:%d - Invalid SRES\n", fname, line);
                        ret = -1;
                        break;
                }
-               *pos2 = '\0';
-               if (strlen(pos) != 8 || hexstr2bin(pos, g->sres, 4)) {
-                       printf("%s:%d - Invalid SRES (%s)\n", fname, line,
-                              pos);
-                       ret = -1;
-                       break;
-               }
-               pos = pos2 + 1;
 
                /* RAND */
-               pos2 = strchr(pos, ':');
-               if (pos2)
-                       *pos2 = '\0';
-               if (strlen(pos) != 32 || hexstr2bin(pos, g->_rand, 16)) {
-                       printf("%s:%d - Invalid RAND (%s)\n", fname, line,
-                              pos);
+               pos = str_token(buf, ":", &pos2);
+               if (!pos || os_strlen(pos) != 32 ||
+                   hexstr2bin(pos, g->_rand, 16)) {
+                       printf("%s:%d - Invalid RAND\n", fname, line);
                        ret = -1;
                        break;
                }
-               pos = pos2 + 1;
 
                g->next = gsm_db;
                gsm_db = g;
@@ -450,86 +424,58 @@ static int read_milenage(const char *fname)
                }
 
                /* IMSI */
-               pos2 = strchr(pos, ' ');
-               if (pos2 == NULL) {
-                       printf("%s:%d - Invalid IMSI (%s)\n",
-                              fname, line, pos);
-                       ret = -1;
-                       break;
-               }
-               *pos2 = '\0';
-               if (strlen(pos) >= sizeof(m->imsi)) {
-                       printf("%s:%d - Too long IMSI (%s)\n",
-                              fname, line, pos);
+               pos2 = NULL;
+               pos = str_token(buf, " ", &pos2);
+               if (!pos || os_strlen(pos) >= sizeof(m->imsi)) {
+                       printf("%s:%d - Invalid IMSI\n", fname, line);
                        ret = -1;
                        break;
                }
                os_strlcpy(m->imsi, pos, sizeof(m->imsi));
-               pos = pos2 + 1;
 
                /* Ki */
-               pos2 = strchr(pos, ' ');
-               if (pos2 == NULL) {
-                       printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
+               pos = str_token(buf, " ", &pos2);
+               if (!pos || os_strlen(pos) != 32 ||
+                   hexstr2bin(pos, m->ki, 16)) {
+                       printf("%s:%d - Invalid Ki\n", fname, line);
                        ret = -1;
                        break;
                }
-               *pos2 = '\0';
-               if (strlen(pos) != 32 || hexstr2bin(pos, m->ki, 16)) {
-                       printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
-                       ret = -1;
-                       break;
-               }
-               pos = pos2 + 1;
 
                /* OPc */
-               pos2 = strchr(pos, ' ');
-               if (pos2 == NULL) {
-                       printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
-                       ret = -1;
-                       break;
-               }
-               *pos2 = '\0';
-               if (strlen(pos) != 32 || hexstr2bin(pos, m->opc, 16)) {
-                       printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
+               pos = str_token(buf, " ", &pos2);
+               if (!pos || os_strlen(pos) != 32 ||
+                   hexstr2bin(pos, m->opc, 16)) {
+                       printf("%s:%d - Invalid OPc\n", fname, line);
                        ret = -1;
                        break;
                }
-               pos = pos2 + 1;
 
                /* AMF */
-               pos2 = strchr(pos, ' ');
-               if (pos2 == NULL) {
-                       printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
-                       ret = -1;
-                       break;
-               }
-               *pos2 = '\0';
-               if (strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) {
-                       printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
+               pos = str_token(buf, " ", &pos2);
+               if (!pos || os_strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) {
+                       printf("%s:%d - Invalid AMF\n", fname, line);
                        ret = -1;
                        break;
                }
-               pos = pos2 + 1;
 
                /* SQN */
-               pos2 = strchr(pos, ' ');
-               if (pos2)
-                       *pos2 = '\0';
-               if (strlen(pos) != 12 || hexstr2bin(pos, m->sqn, 6)) {
-                       printf("%s:%d - Invalid SEQ (%s)\n", fname, line, pos);
+               pos = str_token(buf, " ", &pos2);
+               if (!pos || os_strlen(pos) != 12 ||
+                   hexstr2bin(pos, m->sqn, 6)) {
+                       printf("%s:%d - Invalid SEQ\n", fname, line);
                        ret = -1;
                        break;
                }
 
-               if (pos2) {
-                       pos = pos2 + 1;
+               pos = str_token(buf, " ", &pos2);
+               if (pos) {
                        m->res_len = atoi(pos);
                        if (m->res_len &&
                            (m->res_len < EAP_AKA_RES_MIN_LEN ||
                             m->res_len > EAP_AKA_RES_MAX_LEN)) {
-                               printf("%s:%d - Invalid RES_len (%s)\n",
-                                      fname, line, pos);
+                               printf("%s:%d - Invalid RES_len\n",
+                                      fname, line);
                                ret = -1;
                                break;
                        }
@@ -1027,7 +973,7 @@ static void usage(void)
 {
        printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
               "database/authenticator\n"
-              "Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>\n"
+              "Copyright (c) 2005-2016, Jouni Malinen <j@w1.fi>\n"
               "\n"
               "usage:\n"
               "hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
index a0071f7..fa9a855 100644 (file)
@@ -3,6 +3,8 @@
 
 # AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
 # management frames with the Host AP driver); wlan0 with many nl80211 drivers
+# Note: This attribute can be overridden by the values supplied with the '-i'
+# command line parameter.
 interface=wlan0
 
 # In case of atheros and nl80211 driver interfaces, an additional
@@ -125,11 +127,13 @@ ssid=test
 # ieee80211d=1 and local_pwr_constraint configured.
 #spectrum_mgmt_required=1
 
-# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
-# ad = IEEE 802.11ad (60 GHz); a/g options are used with IEEE 802.11n, too, to
-# specify band). 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.
+# 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
+# special value "any" can be used to indicate that any support band can be used.
+# This special case is currently supported only with drivers with which
+# offloaded ACS is used.
 # Default: IEEE 802.11b
 hw_mode=g
 
@@ -173,7 +177,7 @@ channel=1
 # Channel list restriction. This option allows hostapd to select one of the
 # provided channels when a channel should be automatically selected.
 # Channel list can be provided as range using hyphen ('-') or individual
-# channels can be specified by space (' ') seperated values
+# channels can be specified by space (' ') separated values
 # Default: all channels allowed in selected hw_mode
 #chanlist=100 104 108 112 116
 #chanlist=1 6 11-13
@@ -192,16 +196,16 @@ dtim_period=2
 # (default: 2007)
 max_num_sta=255
 
-# RTS/CTS threshold; 2347 = disabled (default); range 0..2347
+# RTS/CTS threshold; -1 = disabled (default); range -1..65535
 # If this field is not included in hostapd.conf, hostapd will not control
 # RTS threshold and 'iwconfig wlan# rts <val>' can be used to set it.
-rts_threshold=2347
+rts_threshold=-1
 
-# Fragmentation threshold; 2346 = disabled (default); range 256..2346
+# Fragmentation threshold; -1 = disabled (default); range -1, 256..2346
 # If this field is not included in hostapd.conf, hostapd will not control
 # fragmentation threshold and 'iwconfig wlan# frag <val>' can be used to set
 # it.
-fragm_threshold=2346
+fragm_threshold=-1
 
 # Rate configuration
 # Default is to enable all rates supported by the hardware. This configuration
@@ -267,13 +271,27 @@ auth_algs=3
 #     requests for broadcast SSID
 ignore_broadcast_ssid=0
 
-# Additional vendor specfic elements for Beacon and Probe Response frames
+# Do not reply to broadcast Probe Request frames from unassociated STA if there
+# is no room for additional stations (max_num_sta). This can be used to
+# discourage a STA from trying to associate with this AP if the association
+# would be rejected due to maximum STA limit.
+# Default: 0 (disabled)
+#no_probe_resp_if_max_sta=0
+
+# Additional vendor specific elements for Beacon and Probe Response frames
 # This parameter can be used to add additional vendor specific element(s) into
 # the end of the Beacon and Probe Response frames. The format for these
 # element(s) is a hexdump of the raw information elements (id+len+payload for
 # one or more elements)
 #vendor_elements=dd0411223301
 
+# Additional vendor specific elements for (Re)Association Response frames
+# This parameter can be used to add additional vendor specific element(s) into
+# the end of the (Re)Association Response frames. The format for these
+# element(s) is a hexdump of the raw information elements (id+len+payload for
+# one or more elements)
+#assocresp_elements=dd0411223301
+
 # TX queue parameters (EDCF / bursting)
 # tx_queue_<queue name>_<param>
 # queues: data0, data1, data2, data3, after_beacon, beacon
@@ -470,6 +488,7 @@ wmm_ac_vo_acm=0
 # 0 = disabled (default)
 # 1 = enabled
 # Note: You will also need to enable WMM for full HT functionality.
+# Note: hw_mode=g (2.4 GHz) and hw_mode=a (5 GHz) is used to specify the band.
 #ieee80211n=1
 
 # ht_capab: HT capabilities (list of flags)
@@ -523,6 +542,7 @@ wmm_ac_vo_acm=0
 # 0 = disabled (default)
 # 1 = enabled
 # Note: You will also need to enable WMM for full VHT functionality.
+# Note: hw_mode=a is used to specify that 5 GHz band is used with VHT.
 #ieee80211ac=1
 
 # vht_capab: VHT capabilities (list of flags)
@@ -605,9 +625,9 @@ wmm_ac_vo_acm=0
 # VHT TXOP PS: [VHT-TXOP-PS]
 # Indicates whether or not the AP supports VHT TXOP Power Save Mode
 #  or whether or not the STA is in VHT TXOP Power Save mode
-# 0 = VHT AP doesnt support VHT TXOP PS mode (OR) VHT Sta not in VHT TXOP PS
+# 0 = VHT AP doesn't support VHT TXOP PS mode (OR) VHT STA not in VHT TXOP PS
 #  mode
-# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT Sta is in VHT TXOP power save
+# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT STA is in VHT TXOP power save
 #  mode
 #
 # +HTC-VHT Capable: [HTC-VHT]
@@ -665,6 +685,13 @@ wmm_ac_vo_acm=0
 #
 #vht_oper_centr_freq_seg1_idx=159
 
+# Workaround to use station's nsts capability in (Re)Association Response frame
+# This may be needed with some deployed devices as an interoperability
+# workaround for beamforming if the AP's capability is greater than the
+# station's capability. This is disabled by default and can be enabled by
+# setting use_sta_nsts=1.
+#use_sta_nsts=0
+
 ##### IEEE 802.1X-2004 related configuration ##################################
 
 # Require IEEE 802.1X authorization
@@ -788,6 +815,11 @@ eap_server=0
 #      -respout /tmp/ocsp-cache.der
 #ocsp_stapling_response=/tmp/ocsp-cache.der
 
+# Cached OCSP stapling response list (DER encoded OCSPResponseList)
+# This is similar to ocsp_stapling_response, but the extended version defined in
+# RFC 6961 to allow multiple OCSP responses to be provided.
+#ocsp_stapling_response_multi=/tmp/ocsp-multi-cache.der
+
 # dh_file: File path to DH/DSA parameters file (in PEM format)
 # This is an optional configuration file for setting parameters for an
 # ephemeral DH key exchange. In most cases, the default RSA authentication does
@@ -825,6 +857,11 @@ eap_server=0
 #eap_sim_db=unix:/tmp/hlr_auc_gw.sock
 #eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/hostapd.db
 
+# EAP-SIM DB request timeout
+# This parameter sets the maximum time to wait for a database request response.
+# The parameter value is in seconds.
+#eap_sim_db_timeout=1
+
 # Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret,
 # random value. It is configured as a 16-octet value in hex format. It can be
 # generated, e.g., with the following command:
@@ -888,11 +925,23 @@ eap_server=0
 # The own IP address of the access point (used as NAS-IP-Address)
 own_ip_addr=127.0.0.1
 
-# Optional NAS-Identifier string for RADIUS messages. When used, this should be
-# a unique to the NAS within the scope of the RADIUS server. For example, a
-# fully qualified domain name can be used here.
+# NAS-Identifier string for RADIUS messages. When used, this should be unique
+# to the NAS within the scope of the RADIUS server. Please note that hostapd
+# uses a separate RADIUS client for each BSS and as such, a unique
+# nas_identifier value should be configured separately for each BSS. This is
+# particularly important for cases where RADIUS accounting is used
+# (Accounting-On/Off messages are interpreted as clearing all ongoing sessions
+# and that may get interpreted as applying to all BSSes if the same
+# NAS-Identifier value is used.) For example, a fully qualified domain name
+# prefixed with a unique identifier of the BSS (e.g., BSSID) can be used here.
+#
 # When using IEEE 802.11r, nas_identifier must be set and must be between 1 and
 # 48 octets long.
+#
+# It is mandatory to configure either own_ip_addr or nas_identifier to be
+# compliant with the RADIUS protocol. When using RADIUS accounting, it is
+# strongly recommended that nas_identifier is set to a unique value for each
+# BSS.
 #nas_identifier=ap.example.com
 
 # RADIUS client forced local IP address for the access point
@@ -957,6 +1006,17 @@ own_ip_addr=127.0.0.1
 # 2 = required; reject authentication if RADIUS server does not include VLAN ID
 #dynamic_vlan=0
 
+# Per-Station AP_VLAN interface mode
+# If enabled, each station is assigned its own AP_VLAN interface.
+# This implies per-station group keying and ebtables filtering of inter-STA
+# traffic (when passed through the AP).
+# If the sta is not assigned to any VLAN, then its AP_VLAN interface will be
+# added to the bridge given by the "bridge" configuration option (see above).
+# Otherwise, it will be added to the per-VLAN bridge.
+# 0 = disabled (default)
+# 1 = enabled
+#per_sta_vif=0
+
 # VLAN interface list for dynamic VLAN mode is read from a separate text file.
 # This list is used to map VLAN ID from the RADIUS server to a network
 # interface. Each station is bound to one interface in the same way as with
@@ -1035,6 +1095,9 @@ own_ip_addr=127.0.0.1
 #
 # DAS require Event-Timestamp
 #radius_das_require_event_timestamp=1
+#
+# DAS require Message-Authenticator
+#radius_das_require_message_authenticator=1
 
 ##### RADIUS authentication server configuration ##############################
 
@@ -1228,6 +1291,7 @@ own_ip_addr=127.0.0.1
 
 # PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID)
 # 6-octet identifier as a hex string.
+# Defaults to BSSID.
 #r1_key_holder=000102030405
 
 # Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535)
@@ -1684,6 +1748,24 @@ own_ip_addr=127.0.0.1
 # username/password
 #nai_realm=0,example.org,13[5:6],21[2:4][5:7]
 
+# Arbitrary ANQP-element configuration
+# Additional ANQP-elements with arbitrary values can be defined by specifying
+# their contents in raw format as a hexdump of the payload. Note that these
+# values will override ANQP-element contents that may have been specified in the
+# more higher layer configuration parameters listed above.
+# format: anqp_elem=<InfoID>:<hexdump of payload>
+# For example, AP Geospatial Location ANQP-element with unknown location:
+#anqp_elem=265:0000
+# For example, AP Civic Location ANQP-element with unknown location:
+#anqp_elem=266:000000
+
+# GAS Address 3 behavior
+# 0 = P2P specification (Address3 = AP BSSID) workaround enabled by default
+#     based on GAS request Address3
+# 1 = IEEE 802.11 standard compliant regardless of GAS request Address3
+# 2 = Force non-compliant behavior (Address3 = AP BSSID for all cases)
+#gas_address3=0
+
 # QoS Map Set configuration
 #
 # Comma delimited QoS Map Set in decimal values
@@ -1823,6 +1905,27 @@ own_ip_addr=127.0.0.1
 # Transitioning between states).
 #fst_llt=100
 
+##### Radio measurements / location ###########################################
+
+# The content of a LCI measurement subelement
+#lci=<Hexdump of binary data of the LCI report>
+
+# The content of a location civic measurement subelement
+#civic=<Hexdump of binary data of the location civic report>
+
+# Enable neighbor report via radio measurements
+#rrm_neighbor_report=1
+
+# Publish fine timing measurement (FTM) responder functionality
+# This parameter only controls publishing via Extended Capabilities element.
+# Actual functionality is managed outside hostapd.
+#ftm_responder=0
+
+# Publish fine timing measurement (FTM) initiator functionality
+# This parameter only controls publishing via Extended Capabilities element.
+# Actual functionality is managed outside hostapd.
+#ftm_initiator=0
+
 ##### TESTING OPTIONS #########################################################
 #
 # The options in this section are only available when the build configuration
@@ -1844,6 +1947,10 @@ own_ip_addr=127.0.0.1
 #
 # Corrupt Key MIC in GTK rekey EAPOL-Key frames with the given probability
 #corrupt_gtk_rekey_mic_probability=0.0
+#
+# Include only ECSA IE without CSA IE where possible
+# (channel switch operating class is needed)
+#ecsa_ie_only=0
 
 ##### Multiple BSSID support ##################################################
 #
@@ -1866,6 +1973,10 @@ own_ip_addr=127.0.0.1
 # - is not the same as the MAC address of the radio
 # - is not the same as any other explicitly specified BSSID
 #
+# Alternatively, the 'use_driver_iface_addr' parameter can be used to request
+# hostapd to use the driver auto-generated interface address (e.g., to use the
+# exact MAC addresses allocated to the device).
+#
 # Not all drivers support multiple BSSes. The exact mechanism for determining
 # the driver capabilities is driver specific. With the current (i.e., a recent
 # kernel) drivers using nl80211, this information can be checked with "iw list"
index 46c2f37..5e62542 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd - command line interface for hostapd daemon
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
 #include "utils/eloop.h"
 #include "utils/edit.h"
 #include "common/version.h"
+#include "common/cli.h"
 
+#ifndef CONFIG_NO_CTRL_IFACE
 
 static const char *const hostapd_cli_version =
 "hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
-
-
-static const char *const hostapd_cli_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"See README for more details.\n";
-
-static const char *const hostapd_cli_full_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"\n"
-"Redistribution and use in source and binary forms, with or without\n"
-"modification, are permitted provided that the following conditions are\n"
-"met:\n"
-"\n"
-"1. Redistributions of source code must retain the above copyright\n"
-"   notice, this list of conditions and the following disclaimer.\n"
-"\n"
-"2. Redistributions in binary form must reproduce the above copyright\n"
-"   notice, this list of conditions and the following disclaimer in the\n"
-"   documentation and/or other materials provided with the distribution.\n"
-"\n"
-"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
-"   names of its contributors may be used to endorse or promote products\n"
-"   derived from this software without specific prior written permission.\n"
-"\n"
-"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
-"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
-"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
-"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
-"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
-"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
-"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
-"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
-"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
-"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
-"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
-"\n";
-
-static const char *const commands_help =
-"Commands:\n"
-"   mib                  get MIB variables (dot1x, dot11, radius)\n"
-"   sta <addr>           get MIB variables for one station\n"
-"   all_sta              get MIB variables for all stations\n"
-"   new_sta <addr>       add a new station\n"
-"   deauthenticate <addr>  deauthenticate a station\n"
-"   disassociate <addr>  disassociate a station\n"
-#ifdef CONFIG_IEEE80211W
-"   sa_query <addr>      send SA Query to a station\n"
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_WPS
-"   wps_pin <uuid> <pin> [timeout] [addr]  add WPS Enrollee PIN\n"
-"   wps_check_pin <PIN>  verify PIN checksum\n"
-"   wps_pbc              indicate button pushed to initiate PBC\n"
-"   wps_cancel           cancel the pending WPS operation\n"
-#ifdef CONFIG_WPS_NFC
-"   wps_nfc_tag_read <hexdump>  report read NFC tag with WPS data\n"
-"   wps_nfc_config_token <WPS/NDEF>  build NFC configuration token\n"
-"   wps_nfc_token <WPS/NDEF/enable/disable>  manager NFC password token\n"
-#endif /* CONFIG_WPS_NFC */
-"   wps_ap_pin <cmd> [params..]  enable/disable AP PIN\n"
-"   wps_config <SSID> <auth> <encr> <key>  configure AP\n"
-"   wps_get_status       show current WPS status\n"
-#endif /* CONFIG_WPS */
-"   get_config           show current configuration\n"
-"   help                 show this usage help\n"
-"   interface [ifname]   show interfaces/select interface\n"
-"   level <debug level>  change debug level\n"
-"   license              show full hostapd_cli license\n"
-"   quit                 exit hostapd_cli\n";
+"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
 
 static struct wpa_ctrl *ctrl_conn;
 static int hostapd_cli_quit = 0;
@@ -104,6 +38,13 @@ static const char *pid_file = NULL;
 static const char *action_file = NULL;
 static int ping_interval = 5;
 static int interactive = 0;
+static int event_handler_registered = 0;
+
+static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */
+
+static void print_help(FILE *stream, const char *cmd);
+static char ** list_cmd_list(void);
+static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx);
 
 
 static void usage(void)
@@ -128,20 +69,49 @@ static void usage(void)
                "   -B           run a daemon in the background\n"
                "   -i<ifname>   Interface to listen on (default: first "
                "interface found in the\n"
-               "                socket path)\n\n"
-               "%s",
-               commands_help);
+               "                socket path)\n\n");
+       print_help(stderr, NULL);
+}
+
+
+static void register_event_handler(struct wpa_ctrl *ctrl)
+{
+       if (!ctrl_conn)
+               return;
+       if (interactive) {
+               event_handler_registered =
+                       !eloop_register_read_sock(wpa_ctrl_get_fd(ctrl),
+                                                 hostapd_cli_receive,
+                                                 NULL, NULL);
+       }
+}
+
+
+static void unregister_event_handler(struct wpa_ctrl *ctrl)
+{
+       if (!ctrl_conn)
+               return;
+       if (interactive && event_handler_registered) {
+               eloop_unregister_read_sock(wpa_ctrl_get_fd(ctrl));
+               event_handler_registered = 0;
+       }
 }
 
 
 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
 {
+#ifndef CONFIG_CTRL_IFACE_UDP
        char *cfile;
        int flen;
+#endif /* !CONFIG_CTRL_IFACE_UDP */
 
        if (ifname == NULL)
                return NULL;
 
+#ifdef CONFIG_CTRL_IFACE_UDP
+       ctrl_conn = wpa_ctrl_open(ifname);
+       return ctrl_conn;
+#else /* CONFIG_CTRL_IFACE_UDP */
        flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
        cfile = malloc(flen);
        if (cfile == NULL)
@@ -158,6 +128,7 @@ static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
        ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
        free(cfile);
        return ctrl_conn;
+#endif /* CONFIG_CTRL_IFACE_UDP */
 }
 
 
@@ -166,6 +137,7 @@ static void hostapd_cli_close_connection(void)
        if (ctrl_conn == NULL)
                return;
 
+       unregister_event_handler(ctrl_conn);
        if (hostapd_cli_attached) {
                wpa_ctrl_detach(ctrl_conn);
                hostapd_cli_attached = 0;
@@ -215,6 +187,22 @@ static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
 }
 
 
+static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd,
+                          int min_args, int argc, char *argv[])
+{
+       char buf[4096];
+
+       if (argc < min_args) {
+               printf("Invalid %s command - at least %d argument%s required.\n",
+                      cmd, min_args, min_args > 1 ? "s are" : " is");
+               return -1;
+       }
+       if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
+               return -1;
+       return wpa_ctrl_command(ctrl, buf);
+}
+
+
 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        return wpa_ctrl_command(ctrl, "PING");
@@ -330,6 +318,21 @@ static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static char ** hostapd_complete_deauthenticate(const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+
+       switch (arg) {
+       case 1:
+               res = cli_txt_list_array(&stations);
+               break;
+       }
+
+       return res;
+}
+
+
 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
                                        char *argv[])
 {
@@ -348,6 +351,37 @@ static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static char ** hostapd_complete_disassociate(const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+
+       switch (arg) {
+       case 1:
+               res = cli_txt_list_array(&stations);
+               break;
+       }
+
+       return res;
+}
+
+
+#ifdef CONFIG_TAXONOMY
+static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc,
+                                    char *argv[])
+{
+       char buf[64];
+
+       if (argc != 1) {
+               printf("Invalid 'signature' command - exactly one argument, STA address, is required.\n");
+               return -1;
+       }
+       os_snprintf(buf, sizeof(buf), "SIGNATURE %s", argv[0]);
+       return wpa_ctrl_command(ctrl, buf);
+}
+#endif /* CONFIG_TAXONOMY */
+
+
 #ifdef CONFIG_IEEE80211W
 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
                                    char *argv[])
@@ -720,15 +754,30 @@ static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
 
 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-       printf("%s", commands_help);
+       print_help(stdout, argc > 0 ? argv[0] : NULL);
        return 0;
 }
 
 
+static char ** hostapd_cli_complete_help(const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+
+       switch (arg) {
+       case 1:
+               res = list_cmd_list();
+               break;
+       }
+
+       return res;
+}
+
+
 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
                                   char *argv[])
 {
-       printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
+       printf("%s\n\n%s\n", hostapd_cli_version, cli_full_license);
        return 0;
 }
 
@@ -839,6 +888,28 @@ static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+static void hostapd_cli_get_interfaces(struct wpa_ctrl *ctrl,
+                                      struct dl_list *interfaces)
+{
+       struct dirent *dent;
+       DIR *dir;
+
+       if (!ctrl || !interfaces)
+               return;
+       dir = opendir(ctrl_iface_dir);
+       if (dir == NULL)
+               return;
+
+       while ((dent = readdir(dir))) {
+               if (strcmp(dent->d_name, ".") == 0 ||
+                   strcmp(dent->d_name, "..") == 0)
+                       continue;
+               cli_txt_list_add(interfaces, dent->d_name);
+       }
+       closedir(dir);
+}
+
+
 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
 {
        struct dirent *dent;
@@ -880,6 +951,7 @@ static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
                printf("Connected to interface '%s.\n", ctrl_ifname);
                if (wpa_ctrl_attach(ctrl_conn) == 0) {
                        hostapd_cli_attached = 1;
+                       register_event_handler(ctrl_conn);
                } else {
                        printf("Warning: Failed to attach to "
                               "hostapd.\n");
@@ -892,6 +964,24 @@ static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static char ** hostapd_complete_interface(const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       char **res = NULL;
+       DEFINE_DL_LIST(interfaces);
+
+       switch (arg) {
+       case 1:
+               hostapd_cli_get_interfaces(ctrl_conn, &interfaces);
+               res = cli_txt_list_array(&interfaces);
+               cli_txt_list_flush(&interfaces);
+               break;
+       }
+
+       return res;
+}
+
+
 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        char cmd[256];
@@ -1068,68 +1158,245 @@ static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       if (argc == 0)
+               return -1;
+       return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
+}
+
+
+static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "PMKSA");
+}
+
+
+static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
+                                      char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "PMKSA_FLUSH");
+}
+
+
+static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
+                                       char *argv[])
+{
+       char cmd[2048];
+       int res;
+
+       if (argc < 3 || argc > 5) {
+               printf("Invalid set_neighbor command: needs 3-5 arguments\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s",
+                         argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "",
+                         argc == 5 ? argv[4] : "");
+       if (os_snprintf_error(sizeof(cmd), res)) {
+               printf("Too long SET_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[])
+{
+       char cmd[400];
+       int res;
+
+       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_req_lci(struct wpa_ctrl *ctrl, int argc,
+                                  char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc != 1) {
+               printf("Invalid req_lci command - requires destination address\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]);
+       if (os_snprintf_error(sizeof(cmd), res)) {
+               printf("Too long REQ_LCI command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc,
+                                    char *argv[])
+{
+       if (argc < 4) {
+               printf("Invalid req_range command: needs at least 4 arguments - dest address, randomization interval, min AP count, and 1 to 16 AP addresses\n");
+               return -1;
+       }
+
+       return hostapd_cli_cmd(ctrl, "REQ_RANGE", 4, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
+                                       char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
+}
+
+
 struct hostapd_cli_cmd {
        const char *cmd;
        int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
+       char ** (*completion)(const char *str, int pos);
+       const char *usage;
 };
 
 static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
-       { "ping", hostapd_cli_cmd_ping },
-       { "mib", hostapd_cli_cmd_mib },
-       { "relog", hostapd_cli_cmd_relog },
-       { "status", hostapd_cli_cmd_status },
-       { "sta", hostapd_cli_cmd_sta },
-       { "all_sta", hostapd_cli_cmd_all_sta },
-       { "new_sta", hostapd_cli_cmd_new_sta },
-       { "deauthenticate", hostapd_cli_cmd_deauthenticate },
-       { "disassociate", hostapd_cli_cmd_disassociate },
+       { "ping", hostapd_cli_cmd_ping, NULL,
+         "= pings hostapd" },
+       { "mib", hostapd_cli_cmd_mib, NULL,
+         "= get MIB variables (dot1x, dot11, radius)" },
+       { "relog", hostapd_cli_cmd_relog, NULL, NULL },
+       { "status", hostapd_cli_cmd_status, NULL, NULL },
+       { "sta", hostapd_cli_cmd_sta, NULL,
+         "<addr> = get MIB variables for one station" },
+       { "all_sta", hostapd_cli_cmd_all_sta, NULL,
+          "= get MIB variables for all stations" },
+       { "new_sta", hostapd_cli_cmd_new_sta, NULL,
+         "<addr> = add a new station" },
+       { "deauthenticate", hostapd_cli_cmd_deauthenticate,
+         hostapd_complete_deauthenticate,
+         "<addr> = deauthenticate a station" },
+       { "disassociate", hostapd_cli_cmd_disassociate,
+         hostapd_complete_disassociate,
+         "<addr> = disassociate a station" },
+#ifdef CONFIG_TAXONOMY
+       { "signature", hostapd_cli_cmd_signature, NULL,
+         "<addr> = get taxonomy signature for a station" },
+#endif /* CONFIG_TAXONOMY */
 #ifdef CONFIG_IEEE80211W
-       { "sa_query", hostapd_cli_cmd_sa_query },
+       { "sa_query", hostapd_cli_cmd_sa_query, NULL,
+         "<addr> = send SA Query to a station" },
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_WPS
-       { "wps_pin", hostapd_cli_cmd_wps_pin },
-       { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
-       { "wps_pbc", hostapd_cli_cmd_wps_pbc },
-       { "wps_cancel", hostapd_cli_cmd_wps_cancel },
+       { "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
+         "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
+       { "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL,
+         "<PIN> = verify PIN checksum" },
+       { "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL,
+         "= indicate button pushed to initiate PBC" },
+       { "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL,
+         "= cancel the pending WPS operation" },
 #ifdef CONFIG_WPS_NFC
-       { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
-       { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
-       { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
-       { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
+       { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL,
+         "<hexdump> = report read NFC tag with WPS data" },
+       { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL,
+         "<WPS/NDEF> = build NFC configuration token" },
+       { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL,
+         "<WPS/NDEF/enable/disable> = manager NFC password token" },
+       { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL,
+         NULL },
 #endif /* CONFIG_WPS_NFC */
-       { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
-       { "wps_config", hostapd_cli_cmd_wps_config },
-       { "wps_get_status", hostapd_cli_cmd_wps_get_status },
+       { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL,
+         "<cmd> [params..] = enable/disable AP PIN" },
+       { "wps_config", hostapd_cli_cmd_wps_config, NULL,
+         "<SSID> <auth> <encr> <key> = configure AP" },
+       { "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
+         "= show current WPS status" },
 #endif /* CONFIG_WPS */
-       { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
-       { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
-       { "bss_tm_req", hostapd_cli_cmd_bss_tm_req },
-       { "get_config", hostapd_cli_cmd_get_config },
-       { "help", hostapd_cli_cmd_help },
-       { "interface", hostapd_cli_cmd_interface },
+       { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL, NULL },
+       { "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL, NULL },
+       { "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL, NULL },
+       { "get_config", hostapd_cli_cmd_get_config, NULL,
+         "= show current configuration" },
+       { "help", hostapd_cli_cmd_help, hostapd_cli_complete_help,
+         "= show this usage help" },
+       { "interface", hostapd_cli_cmd_interface, hostapd_complete_interface,
+         "[ifname] = show interfaces/select interface" },
 #ifdef CONFIG_FST
-       { "fst", hostapd_cli_cmd_fst },
+       { "fst", hostapd_cli_cmd_fst, NULL, NULL },
 #endif /* CONFIG_FST */
-       { "level", hostapd_cli_cmd_level },
-       { "license", hostapd_cli_cmd_license },
-       { "quit", hostapd_cli_cmd_quit },
-       { "set", hostapd_cli_cmd_set },
-       { "get", hostapd_cli_cmd_get },
-       { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
-       { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
-       { "chan_switch", hostapd_cli_cmd_chan_switch },
-       { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
-       { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
-       { "vendor", hostapd_cli_cmd_vendor },
-       { "enable", hostapd_cli_cmd_enable },
-       { "reload", hostapd_cli_cmd_reload },
-       { "disable", hostapd_cli_cmd_disable },
-       { "erp_flush", hostapd_cli_cmd_erp_flush },
-       { "log_level", hostapd_cli_cmd_log_level },
-       { NULL, NULL }
+       { "raw", hostapd_cli_cmd_raw, NULL, NULL },
+       { "level", hostapd_cli_cmd_level, NULL,
+         "<debug level> = change debug level" },
+       { "license", hostapd_cli_cmd_license, NULL,
+         "= show full hostapd_cli license" },
+       { "quit", hostapd_cli_cmd_quit, NULL,
+         "= exit hostapd_cli" },
+       { "set", hostapd_cli_cmd_set, NULL, NULL },
+       { "get", hostapd_cli_cmd_get, NULL, NULL },
+       { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL, NULL },
+       { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf, NULL, NULL },
+       { "chan_switch", hostapd_cli_cmd_chan_switch, NULL, NULL },
+       { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, NULL },
+       { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL, NULL },
+       { "vendor", hostapd_cli_cmd_vendor, NULL, NULL },
+       { "enable", hostapd_cli_cmd_enable, NULL, NULL },
+       { "reload", hostapd_cli_cmd_reload, NULL, NULL },
+       { "disable", hostapd_cli_cmd_disable, NULL, NULL },
+       { "erp_flush", hostapd_cli_cmd_erp_flush, NULL, NULL },
+       { "log_level", hostapd_cli_cmd_log_level, NULL, NULL },
+       { "pmksa", hostapd_cli_cmd_pmksa, NULL, NULL },
+       { "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL, NULL },
+       { "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL, NULL },
+       { "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL, NULL },
+       { "req_lci", hostapd_cli_cmd_req_lci, NULL, NULL },
+       { "req_range", hostapd_cli_cmd_req_range, NULL, NULL },
+       { "driver_flags", hostapd_cli_cmd_driver_flags, NULL, NULL },
+       { NULL, NULL, NULL, NULL }
 };
 
 
+/*
+ * Prints command usage, lines are padded with the specified string.
+ */
+static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd,
+                          const char *pad)
+{
+       char c;
+       size_t n;
+
+       if (cmd->usage == NULL)
+               return;
+       fprintf(stream, "%s%s ", pad, cmd->cmd);
+       for (n = 0; (c = cmd->usage[n]); n++) {
+               fprintf(stream, "%c", c);
+               if (c == '\n')
+                       fprintf(stream, "%s", pad);
+       }
+       fprintf(stream, "\n");
+}
+
+
+static void print_help(FILE *stream, const char *cmd)
+{
+       int n;
+
+       fprintf(stream, "commands:\n");
+       for (n = 0; hostapd_cli_commands[n].cmd; n++) {
+               if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd))
+                       print_cmd_help(stream, &hostapd_cli_commands[n], "  ");
+       }
+}
+
+
 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        const struct hostapd_cli_cmd *cmd, *match = NULL;
@@ -1169,6 +1436,34 @@ static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+static void cli_event(const char *str)
+{
+       const char *start, *s;
+
+       start = os_strchr(str, '>');
+       if (start == NULL)
+               return;
+
+       start++;
+
+       if (str_starts(start, AP_STA_CONNECTED)) {
+               s = os_strchr(start, ' ');
+               if (s == NULL)
+                       return;
+               cli_txt_list_add(&stations, s + 1);
+               return;
+       }
+
+       if (str_starts(start, AP_STA_DISCONNECTED)) {
+               s = os_strchr(start, ' ');
+               if (s == NULL)
+                       return;
+               cli_txt_list_del_addr(&stations, s + 1);
+               return;
+       }
+}
+
+
 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
                                     int action_monitor)
 {
@@ -1183,6 +1478,7 @@ static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
                        if (action_monitor)
                                hostapd_cli_action_process(buf, len);
                        else {
+                               cli_event(buf);
                                if (in_read && first)
                                        printf("\n");
                                first = 0;
@@ -1196,35 +1492,9 @@ static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
 }
 
 
-#define max_args 10
-
-static int tokenize_cmd(char *cmd, char *argv[])
+static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx)
 {
-       char *pos;
-       int argc = 0;
-
-       pos = cmd;
-       for (;;) {
-               while (*pos == ' ')
-                       pos++;
-               if (*pos == '\0')
-                       break;
-               argv[argc] = pos;
-               argc++;
-               if (argc == max_args)
-                       break;
-               if (*pos == '"') {
-                       char *pos2 = os_strrchr(pos, '"');
-                       if (pos2)
-                               pos = pos2 + 1;
-               }
-               while (*pos != '\0' && *pos != ' ')
-                       pos++;
-               if (*pos == ' ')
-                       *pos++ = '\0';
-       }
-
-       return argc;
+       hostapd_cli_recv_pending(ctrl_conn, 0, 0);
 }
 
 
@@ -1240,6 +1510,7 @@ static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
                        printf("Connection to hostapd re-established\n");
                        if (wpa_ctrl_attach(ctrl_conn) == 0) {
                                hostapd_cli_attached = 1;
+                               register_event_handler(ctrl_conn);
                        } else {
                                printf("Warning: Failed to attach to "
                                       "hostapd.\n");
@@ -1274,17 +1545,82 @@ static void hostapd_cli_edit_eof_cb(void *ctx)
 }
 
 
+static char ** list_cmd_list(void)
+{
+       char **res;
+       int i, count;
+
+       count = ARRAY_SIZE(hostapd_cli_commands);
+       res = os_calloc(count + 1, sizeof(char *));
+       if (res == NULL)
+               return NULL;
+
+       for (i = 0; hostapd_cli_commands[i].cmd; i++) {
+               res[i] = os_strdup(hostapd_cli_commands[i].cmd);
+               if (res[i] == NULL)
+                       break;
+       }
+
+       return res;
+}
+
+
+static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str,
+                                     int pos)
+{
+       int i;
+
+       for (i = 0; hostapd_cli_commands[i].cmd; i++) {
+               if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0)
+                       continue;
+               if (hostapd_cli_commands[i].completion)
+                       return hostapd_cli_commands[i].completion(str, pos);
+               if (!hostapd_cli_commands[i].usage)
+                       return NULL;
+               edit_clear_line();
+               printf("\r%s\n", hostapd_cli_commands[i].usage);
+               edit_redraw();
+               break;
+       }
+
+       return NULL;
+}
+
+
+static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str,
+                                             int pos)
+{
+       char **res;
+       const char *end;
+       char *cmd;
+
+       end = os_strchr(str, ' ');
+       if (end == NULL || str + pos < end)
+               return list_cmd_list();
+
+       cmd = os_malloc(pos + 1);
+       if (cmd == NULL)
+               return NULL;
+       os_memcpy(cmd, str, pos);
+       cmd[end - str] = '\0';
+       res = hostapd_cli_cmd_completion(cmd, str, pos);
+       os_free(cmd);
+       return res;
+}
+
+
 static void hostapd_cli_interactive(void)
 {
        printf("\nInteractive mode\n\n");
 
        eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
        edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
-                 NULL, NULL, NULL, NULL);
+                 hostapd_cli_edit_completion_cb, NULL, NULL, NULL);
        eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
 
        eloop_run();
 
+       cli_txt_list_flush(&stations);
        edit_deinit(NULL, NULL);
        eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
 }
@@ -1388,8 +1724,7 @@ int main(int argc, char *argv[])
        interactive = (argc == optind) && (action_file == NULL);
 
        if (interactive) {
-               printf("%s\n\n%s\n\n", hostapd_cli_version,
-                      hostapd_cli_license);
+               printf("%s\n\n%s\n\n", hostapd_cli_version, cli_license);
        }
 
        if (eloop_init())
@@ -1437,6 +1772,7 @@ int main(int argc, char *argv[])
        if (interactive || action_file) {
                if (wpa_ctrl_attach(ctrl_conn) == 0) {
                        hostapd_cli_attached = 1;
+                       register_event_handler(ctrl_conn);
                } else {
                        printf("Warning: Failed to attach to hostapd.\n");
                        if (action_file)
@@ -1444,7 +1780,7 @@ int main(int argc, char *argv[])
                }
        }
 
-       if (daemonize && os_daemonize(pid_file))
+       if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
                return -1;
 
        if (interactive)
@@ -1454,8 +1790,18 @@ int main(int argc, char *argv[])
        else
                wpa_request(ctrl_conn, argc - optind, &argv[optind]);
 
+       unregister_event_handler(ctrl_conn);
        os_free(ctrl_ifname);
        eloop_destroy();
        hostapd_cli_cleanup();
        return 0;
 }
+
+#else /* CONFIG_NO_CTRL_IFACE */
+
+int main(int argc, char *argv[])
+{
+       return -1;
+}
+
+#endif /* CONFIG_NO_CTRL_IFACE */
index 6c7406a..2c8dbd3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / main()
- * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
+ * 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.
@@ -171,7 +171,8 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
 
                if (global.drv_priv[i] == NULL &&
                    wpa_drivers[i]->global_init) {
-                       global.drv_priv[i] = wpa_drivers[i]->global_init();
+                       global.drv_priv[i] =
+                               wpa_drivers[i]->global_init(iface->interfaces);
                        if (global.drv_priv[i] == NULL) {
                                wpa_printf(MSG_ERROR, "Failed to initialize "
                                           "driver '%s'",
@@ -216,11 +217,20 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
                iface->drv_flags = capa.flags;
                iface->smps_modes = capa.smps_modes;
                iface->probe_resp_offloads = capa.probe_resp_offloads;
+               /*
+                * Use default extended capa values from per-radio information
+                */
                iface->extended_capa = capa.extended_capa;
                iface->extended_capa_mask = capa.extended_capa_mask;
                iface->extended_capa_len = capa.extended_capa_len;
                iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
 
+               /*
+                * Override extended capa with per-interface type (AP), if
+                * available from the driver.
+                */
+               hostapd_get_ext_capa(iface);
+
                triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa);
                if (triggs && hapd->driver->set_wowlan) {
                        if (hapd->driver->set_wowlan(hapd->drv_priv, triggs))
@@ -241,7 +251,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
  * interfaces. No actiual driver operations are started.
  */
 static struct hostapd_iface *
-hostapd_interface_init(struct hapd_interfaces *interfaces,
+hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name,
                       const char *config_fname, int debug)
 {
        struct hostapd_iface *iface;
@@ -251,6 +261,12 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
        iface = hostapd_init(interfaces, config_fname);
        if (!iface)
                return NULL;
+
+       if (if_name) {
+               os_strlcpy(iface->conf->bss[0]->iface, if_name,
+                          sizeof(iface->conf->bss[0]->iface));
+       }
+
        iface->interfaces = interfaces;
 
        for (k = 0; k < debug; k++) {
@@ -260,7 +276,8 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
 
        if (iface->conf->bss[0]->iface[0] == '\0' &&
            !hostapd_drv_none(iface->bss[0])) {
-               wpa_printf(MSG_ERROR, "Interface name not specified in %s",
+               wpa_printf(MSG_ERROR,
+                          "Interface name not specified in %s, nor by '-i' parameter",
                           config_fname);
                hostapd_interface_deinit_free(iface);
                return NULL;
@@ -329,6 +346,7 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces,
                wpa_printf(MSG_ERROR, "Failed to initialize event loop");
                return -1;
        }
+       interfaces->eloop_initialized = 1;
 
        random_init(entropy_file);
 
@@ -356,7 +374,7 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces,
 }
 
 
-static void hostapd_global_deinit(const char *pid_file)
+static void hostapd_global_deinit(const char *pid_file, int eloop_initialized)
 {
        int i;
 
@@ -374,7 +392,8 @@ static void hostapd_global_deinit(const char *pid_file)
 
        random_deinit();
 
-       eloop_destroy();
+       if (eloop_initialized)
+               eloop_destroy();
 
 #ifndef CONFIG_NATIVE_WINDOWS
        closelog();
@@ -408,9 +427,16 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
        }
 #endif /* EAP_SERVER_TNC */
 
-       if (daemonize && os_daemonize(pid_file)) {
-               wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
-               return -1;
+       if (daemonize) {
+               if (os_daemonize(pid_file)) {
+                       wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
+                       return -1;
+               }
+               if (eloop_sock_requeue()) {
+                       wpa_printf(MSG_ERROR, "eloop_sock_requeue: %s",
+                                  strerror(errno));
+                       return -1;
+               }
        }
 
        eloop_run();
@@ -425,7 +451,7 @@ static void show_version(void)
                "hostapd v" VERSION_STR "\n"
                "User space daemon for IEEE 802.11 AP management,\n"
                "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
-               "Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> "
+               "Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> "
                "and contributors\n");
 }
 
@@ -437,7 +463,8 @@ static void usage(void)
                "\n"
                "usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
                "\\\n"
-               "         [-g <global ctrl_iface>] [-G <group>] \\\n"
+               "         [-g <global ctrl_iface>] [-G <group>]\\\n"
+               "         [-i <comma-separated list of interface names>]\\\n"
                "         <configuration file(s)>\n"
                "\n"
                "options:\n"
@@ -456,6 +483,8 @@ static void usage(void)
                "   -T = record to Linux tracing in addition to logging\n"
                "        (records all messages regardless of debug verbosity)\n"
 #endif /* CONFIG_DEBUG_LINUX_TRACING */
+               "   -i   list of interface names to use\n"
+               "   -S   start all the interfaces synchronously\n"
                "   -t   include timestamps in some debug messages\n"
                "   -v   show hostapd version\n");
 
@@ -466,9 +495,8 @@ static void usage(void)
 static const char * hostapd_msg_ifname_cb(void *ctx)
 {
        struct hostapd_data *hapd = ctx;
-       if (hapd && hapd->iconf && hapd->iconf->bss &&
-           hapd->iconf->num_bss > 0 && hapd->iconf->bss[0])
-               return hapd->iconf->bss[0]->iface;
+       if (hapd && hapd->conf)
+               return hapd->conf->iface;
        return NULL;
 }
 
@@ -476,11 +504,16 @@ static const char * hostapd_msg_ifname_cb(void *ctx)
 static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
                                         const char *path)
 {
+#ifndef CONFIG_CTRL_IFACE_UDP
        char *pos;
+#endif /* !CONFIG_CTRL_IFACE_UDP */
+
        os_free(interfaces->global_iface_path);
        interfaces->global_iface_path = os_strdup(path);
        if (interfaces->global_iface_path == NULL)
                return -1;
+
+#ifndef CONFIG_CTRL_IFACE_UDP
        pos = os_strrchr(interfaces->global_iface_path, '/');
        if (pos == NULL) {
                wpa_printf(MSG_ERROR, "No '/' in the global control interface "
@@ -492,6 +525,7 @@ static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
 
        *pos = '\0';
        interfaces->global_iface_name = pos + 1;
+#endif /* !CONFIG_CTRL_IFACE_UDP */
 
        return 0;
 }
@@ -513,6 +547,43 @@ static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
 }
 
 
+static int hostapd_get_interface_names(char ***if_names,
+                                      size_t *if_names_size,
+                                      char *optarg)
+{
+       char *if_name, *tmp, **nnames;
+       size_t i;
+
+       if (!optarg)
+               return -1;
+       if_name = strtok_r(optarg, ",", &tmp);
+
+       while (if_name) {
+               nnames = os_realloc_array(*if_names, 1 + *if_names_size,
+                                         sizeof(char *));
+               if (!nnames)
+                       goto fail;
+               *if_names = nnames;
+
+               (*if_names)[*if_names_size] = os_strdup(if_name);
+               if (!(*if_names)[*if_names_size])
+                       goto fail;
+               (*if_names_size)++;
+               if_name = strtok_r(NULL, ",", &tmp);
+       }
+
+       return 0;
+
+fail:
+       for (i = 0; i < *if_names_size; i++)
+               os_free((*if_names)[i]);
+       os_free(*if_names);
+       *if_names = NULL;
+       *if_names_size = 0;
+       return -1;
+}
+
+
 #ifdef CONFIG_WPS
 static int gen_uuid(const char *txt_addr)
 {
@@ -570,6 +641,9 @@ int main(int argc, char *argv[])
 #ifdef CONFIG_DEBUG_LINUX_TRACING
        int enable_trace_dbg = 0;
 #endif /* CONFIG_DEBUG_LINUX_TRACING */
+       int start_ifaces_in_sync = 0;
+       char **if_names = NULL;
+       size_t if_names_size = 0;
 
        if (os_program_init())
                return -1;
@@ -584,10 +658,10 @@ int main(int argc, char *argv[])
        interfaces.global_iface_path = NULL;
        interfaces.global_iface_name = NULL;
        interfaces.global_ctrl_sock = -1;
-       interfaces.global_ctrl_dst = NULL;
+       dl_list_init(&interfaces.global_ctrl_dst);
 
        for (;;) {
-               c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:");
+               c = getopt(argc, argv, "b:Bde:f:hi:KP:STtu:vg:G:");
                if (c < 0)
                        break;
                switch (c) {
@@ -644,10 +718,18 @@ int main(int argc, char *argv[])
                        bss_config = tmp_bss;
                        bss_config[num_bss_configs++] = optarg;
                        break;
+               case 'S':
+                       start_ifaces_in_sync = 1;
+                       break;
 #ifdef CONFIG_WPS
                case 'u':
                        return gen_uuid(optarg);
 #endif /* CONFIG_WPS */
+               case 'i':
+                       if (hostapd_get_interface_names(&if_names,
+                                                       &if_names_size, optarg))
+                               goto out;
+                       break;
                default:
                        usage();
                        break;
@@ -705,13 +787,21 @@ int main(int argc, char *argv[])
 
        /* Allocate and parse configuration for full interface files */
        for (i = 0; i < interfaces.count; i++) {
+               char *if_name = NULL;
+
+               if (i < if_names_size)
+                       if_name = if_names[i];
+
                interfaces.iface[i] = hostapd_interface_init(&interfaces,
+                                                            if_name,
                                                             argv[optind + i],
                                                             debug);
                if (!interfaces.iface[i]) {
                        wpa_printf(MSG_ERROR, "Failed to initialize interface");
                        goto out;
                }
+               if (start_ifaces_in_sync)
+                       interfaces.iface[i]->need_to_start_in_sync = 1;
        }
 
        /* Allocate and parse configuration for per-BSS files */
@@ -787,8 +877,9 @@ int main(int argc, char *argv[])
        }
        os_free(interfaces.iface);
 
-       eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
-       hostapd_global_deinit(pid_file);
+       if (interfaces.eloop_initialized)
+               eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
+       hostapd_global_deinit(pid_file, interfaces.eloop_initialized);
        os_free(pid_file);
 
        if (log_file)
@@ -797,6 +888,10 @@ int main(int argc, char *argv[])
 
        os_free(bss_config);
 
+       for (i = 0; i < if_names_size; i++)
+               os_free(if_names[i]);
+       os_free(if_names);
+
        fst_global_deinit();
 
        os_program_deinit();
index b23ac17..e4db322 100644 (file)
@@ -4,7 +4,6 @@ INCLUDES = $(LOCAL_PATH)
 INCLUDES += $(LOCAL_PATH)/../../src/utils
 INCLUDES += $(LOCAL_PATH)/../../src/common
 INCLUDES += $(LOCAL_PATH)/../../src
-INCLUDES += external/openssl/include
 INCLUDES += external/libxml2/include
 INCLUDES += external/curl/include
 INCLUDES += external/webkit/Source/WebKit/gtk
@@ -55,6 +54,7 @@ OBJS += ../../src/crypto/crypto_internal.c
 OBJS += ../../src/crypto/md5-internal.c
 OBJS += ../../src/crypto/sha1-internal.c
 OBJS += ../../src/crypto/sha256-internal.c
+OBJS += ../../src/crypto/tls_openssl_ocsp.c
 
 L_CFLAGS += -DEAP_TLS_OPENSSL
 
index 94cd5f1..fc9b619 100644 (file)
@@ -76,6 +76,7 @@ LIBS += -lcurl
 endif
 
 CFLAGS += -DEAP_TLS_OPENSSL
+OBJS += ../../src/crypto/tls_openssl_ocsp.o
 LIBS += -lssl -lcrypto
 
 hs20-osu-client: $(OBJS)
index ec05bc4..9f1519b 100644 (file)
@@ -16,6 +16,9 @@
 #include <openssl/asn1t.h>
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
+#ifdef OPENSSL_IS_BORINGSSL
+#include <openssl/buf.h>
+#endif /* OPENSSL_IS_BORINGSSL */
 
 #include "common.h"
 #include "utils/base64.h"
 static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7,
                         size_t len, char *pem_file, char *der_file)
 {
+#ifdef OPENSSL_IS_BORINGSSL
+       CBS pkcs7_cbs;
+#else /* OPENSSL_IS_BORINGSSL */
        PKCS7 *p7 = NULL;
        const unsigned char *p = pkcs7;
+#endif /* OPENSSL_IS_BORINGSSL */
        STACK_OF(X509) *certs;
        int i, num, ret = -1;
        BIO *out = NULL;
 
+#ifdef OPENSSL_IS_BORINGSSL
+       certs = sk_X509_new_null();
+       if (!certs)
+               goto fail;
+       CBS_init(&pkcs7_cbs, pkcs7, len);
+       if (!PKCS7_get_certificates(certs, &pkcs7_cbs)) {
+               wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s",
+                          ERR_error_string(ERR_get_error(), NULL));
+               write_result(ctx, "Could not parse PKCS#7 object from EST");
+               goto fail;
+       }
+#else /* OPENSSL_IS_BORINGSSL */
        p7 = d2i_PKCS7(NULL, &p, len);
        if (p7 == NULL) {
                wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s",
@@ -52,6 +71,7 @@ static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7,
                certs = NULL;
                break;
        }
+#endif /* OPENSSL_IS_BORINGSSL */
 
        if (!certs || ((num = sk_X509_num(certs)) == 0)) {
                wpa_printf(MSG_INFO, "No certificates found in PKCS#7 object");
@@ -84,7 +104,12 @@ static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7,
        ret = 0;
 
 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);
 
@@ -310,6 +335,23 @@ static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
        if (!csrattrs || ! csrattrs->attrs)
                return;
 
+#ifdef OPENSSL_IS_BORINGSSL
+       num = sk_num(CHECKED_CAST(_STACK *, STACK_OF(AttrOrOID) *,
+                                 csrattrs->attrs));
+       for (i = 0; i < num; i++) {
+               AttrOrOID *ao = sk_value(
+                       CHECKED_CAST(_STACK *, const STACK_OF(AttrOrOID) *,
+                                    csrattrs->attrs), i);
+               switch (ao->type) {
+               case 0:
+                       add_csrattrs_oid(ctx, ao->d.oid, exts);
+                       break;
+               case 1:
+                       add_csrattrs_attr(ctx, ao->d.attribute, exts);
+                       break;
+               }
+       }
+#else /* OPENSSL_IS_BORINGSSL */
        num = SKM_sk_num(AttrOrOID, csrattrs->attrs);
        for (i = 0; i < num; i++) {
                AttrOrOID *ao = SKM_sk_value(AttrOrOID, csrattrs->attrs, i);
@@ -322,6 +364,7 @@ static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
                        break;
                }
        }
+#endif /* OPENSSL_IS_BORINGSSL */
 }
 
 
@@ -340,6 +383,7 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
        STACK_OF(X509_EXTENSION) *exts = NULL;
        X509_EXTENSION *ex;
        BIO *out;
+       CONF *ctmp = NULL;
 
        wpa_printf(MSG_INFO, "Generate RSA private key");
        write_summary(ctx, "Generate RSA private key");
@@ -421,20 +465,20 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
        if (!exts)
                goto fail;
 
-       ex = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints,
-                                "CA:FALSE");
+       ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_basic_constraints,
+                                 "CA:FALSE");
        if (ex == NULL ||
            !sk_X509_EXTENSION_push(exts, ex))
                goto fail;
 
-       ex = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage,
-                                "nonRepudiation,digitalSignature,keyEncipherment");
+       ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_key_usage,
+                                 "nonRepudiation,digitalSignature,keyEncipherment");
        if (ex == NULL ||
            !sk_X509_EXTENSION_push(exts, ex))
                goto fail;
 
-       ex = X509V3_EXT_conf_nid(NULL, NULL, NID_ext_key_usage,
-                                "1.3.6.1.4.1.40808.1.1.2");
+       ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_ext_key_usage,
+                                 "1.3.6.1.4.1.40808.1.1.2");
        if (ex == NULL ||
            !sk_X509_EXTENSION_push(exts, ex))
                goto fail;
@@ -454,7 +498,9 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
                char *txt;
                size_t rlen;
 
+#if !defined(ANDROID) || !defined(OPENSSL_IS_BORINGSSL)
                X509_REQ_print(out, req);
+#endif
                rlen = BIO_ctrl_pending(out);
                txt = os_malloc(rlen + 1);
                if (txt) {
@@ -473,7 +519,9 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
                FILE *f = fopen(csr_pem, "w");
                if (f == NULL)
                        goto fail;
+#if !defined(ANDROID) || !defined(OPENSSL_IS_BORINGSSL)
                X509_REQ_print_fp(f, req);
+#endif
                if (!PEM_write_X509_REQ(f, req)) {
                        fclose(f);
                        goto fail;
index 0315f7b..c05c57d 100644 (file)
@@ -2229,7 +2229,7 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
                fprintf(f, "</table></a><br><small>BSSID: %s<br>\n"
                        "SSID: %s<br>\n",
                        last->bssid, last->osu_ssid);
-               if (last->osu_nai)
+               if (last->osu_nai[0])
                        fprintf(f, "NAI: %s<br>\n", last->osu_nai);
                fprintf(f, "URL: %s<br>\n"
                        "methods:%s%s<br>\n"
@@ -2339,12 +2339,23 @@ static int cmd_signup(struct hs20_osu_client *ctx, int no_prod_assoc,
                return -1;
 
        snprintf(fname, sizeof(fname), "%s/osu-info", dir);
-       if (mkdir(fname, S_IRWXU | S_IRWXG) < 0 && errno != EEXIST) {
+       if (mkdir(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0 &&
+           errno != EEXIST) {
                wpa_printf(MSG_INFO, "mkdir(%s) failed: %s",
                           fname, strerror(errno));
                return -1;
        }
 
+#ifdef ANDROID
+       /* Allow processes running with Group ID as AID_WIFI
+        * to read/write files from osu-info directory
+        */
+       if (chown(fname, -1, AID_WIFI)) {
+               wpa_printf(MSG_INFO, "Could not chown osu-info directory: %s",
+                          strerror(errno));
+       }
+#endif /* ANDROID */
+
        snprintf(buf, sizeof(buf), "SET osu_dir %s", fname);
        if (wpa_command(ifname, buf) < 0) {
                wpa_printf(MSG_INFO, "Failed to configure osu_dir to wpa_supplicant");
@@ -2559,7 +2570,7 @@ static int cmd_pol_upd(struct hs20_osu_client *ctx, const char *address,
        if (!pps_fname) {
                char buf[256];
                wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information");
-               if (os_strncmp(address, "fqdn=", 5) == 0) {
+               if (address && os_strncmp(address, "fqdn=", 5) == 0) {
                        wpa_printf(MSG_INFO, "Use requested FQDN from command line");
                        os_snprintf(buf, sizeof(buf), "%s", address + 5);
                        address = NULL;
@@ -3122,20 +3133,12 @@ int main(int argc, char *argv[])
                        usage();
                        exit(0);
                }
-               if (argc - optind < 2)
-                       wpa_printf(MSG_ERROR, "Server URL missing from command line");
-               else
-                       ret = cmd_sub_rem(&ctx, argv[optind + 1],
-                                         argc > optind + 2 ?
-                                         argv[optind + 2] : NULL,
-                                         argc > optind + 3 ?
-                                         argv[optind + 3] : NULL);
+               ret = cmd_sub_rem(&ctx, argv[optind + 1],
+                                 argc > optind + 2 ? argv[optind + 2] : NULL,
+                                 argc > optind + 3 ? argv[optind + 3] : NULL);
        } else if (strcmp(argv[optind], "pol_upd") == 0) {
-               if (argc - optind < 2) {
-                       usage();
-                       exit(0);
-               }
-               ret = cmd_pol_upd(&ctx, argc > 2 ? argv[optind + 1] : NULL,
+               ret = cmd_pol_upd(&ctx,
+                                 argc > optind + 1 ? argv[optind + 1] : NULL,
                                  argc > optind + 2 ? argv[optind + 2] : NULL,
                                  argc > optind + 3 ? argv[optind + 3] : NULL);
        } else if (strcmp(argv[optind], "prov") == 0) {
index dde4434..002d028 100644 (file)
@@ -96,7 +96,8 @@ else
   putenv("HS20USER");
 
 putenv("HS20REALM=$realm");
-putenv("HS20POST=$HTTP_RAW_POST_DATA");
+$postdata = file_get_contents("php://input");
+putenv("HS20POST=$postdata");
 $addr = $_SERVER["REMOTE_ADDR"];
 putenv("HS20ADDR=$addr");
 
diff --git a/libeap/mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf b/libeap/mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf
deleted file mode 100644 (file)
index 08cde7e..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-interface=wlan0
-driver=nl80211
-
-hw_mode=g
-channel=1
-ssid=mac80211 test
-
-wpa=2
-wpa_key_mgmt=WPA-PSK
-wpa_pairwise=CCMP
-wpa_passphrase=12345678
diff --git a/libeap/mac80211_hwsim/tests/0001-wpa2-psk/test.txt b/libeap/mac80211_hwsim/tests/0001-wpa2-psk/test.txt
deleted file mode 100644 (file)
index 05d85a0..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# WPA2-Personal (PSK) with CCMP, AP and single client
-
-modprobe mac80211_hwsim
-
-hostapd hostapd.conf
-
-wpa_supplicant -Dwext -iwlan1 -c wpa_supplicant.conf
diff --git a/libeap/mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf b/libeap/mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf
deleted file mode 100644 (file)
index 299128c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-ctrl_interface=/var/run/wpa_supplicant
-
-network={
-       ssid="mac80211 test"
-       psk="12345678"
-       key_mgmt=WPA-PSK
-       proto=WPA2
-       pairwise=CCMP
-       group=CCMP
-}
diff --git a/libeap/mac80211_hwsim/tests/0002-vlan/hostapd.accept b/libeap/mac80211_hwsim/tests/0002-vlan/hostapd.accept
deleted file mode 100644 (file)
index e97a175..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-02:00:00:00:01:00      1
-02:00:00:00:02:00      2
diff --git a/libeap/mac80211_hwsim/tests/0002-vlan/hostapd.conf b/libeap/mac80211_hwsim/tests/0002-vlan/hostapd.conf
deleted file mode 100644 (file)
index 8698f0e..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-interface=wlan0
-driver=nl80211
-
-hw_mode=g
-channel=1
-ssid=mac80211 test
-
-dynamic_vlan=2
-vlan_file=hostapd.vlan
-
-macaddr_acl=0
-accept_mac_file=hostapd.accept
diff --git a/libeap/mac80211_hwsim/tests/0002-vlan/hostapd.vlan b/libeap/mac80211_hwsim/tests/0002-vlan/hostapd.vlan
deleted file mode 100644 (file)
index b3750b2..0000000
+++ /dev/null
@@ -1 +0,0 @@
-*      vlan#
diff --git a/libeap/mac80211_hwsim/tests/0002-vlan/test.txt b/libeap/mac80211_hwsim/tests/0002-vlan/test.txt
deleted file mode 100644 (file)
index 8c92f1c..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-# Plaintext connection, two clients, different VLANs
-
-modprobe mac80211_hwsim radios=3
-
-hostapd hostapd.conf
-
-ifconfig wlan1 up
-iwconfig wlan1 essid "mac80211 test"
-
-ifconfig wlan2 up
-iwconfig wlan2 essid "mac80211 test"
-
-# Expected results:
-# STA1(wlan1) is bound to vlan1
-# STA2(wlan2) is bound to vlan2
diff --git a/libeap/patches/openssl-0.9.8za-tls-extensions.patch b/libeap/patches/openssl-0.9.8za-tls-extensions.patch
deleted file mode 100644 (file)
index 82bfe23..0000000
+++ /dev/null
@@ -1,397 +0,0 @@
-This patch adds support for TLS SessionTicket extension (RFC 5077) for
-the parts used by EAP-FAST (RFC 4851).
-
-This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
-(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
-
-OpenSSL 0.9.8za does not enable TLS extension support by default, so it
-will need to be enabled by adding enable-tlsext to config script
-command line.
-
-
-diff -upr openssl-0.9.8za.orig/ssl/s3_clnt.c openssl-0.9.8za/ssl/s3_clnt.c
---- openssl-0.9.8za.orig/ssl/s3_clnt.c 2014-06-05 11:09:26.000000000 +0300
-+++ openssl-0.9.8za/ssl/s3_clnt.c      2014-06-05 20:37:09.221387312 +0300
-@@ -767,6 +767,22 @@ int ssl3_get_server_hello(SSL *s)
-               goto f_err;
-               }
-+#ifndef OPENSSL_NO_TLSEXT
-+      /* check if we want to resume the session based on external pre-shared secret */
-+      if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+              {
-+              SSL_CIPHER *pref_cipher=NULL;
-+              s->session->master_key_length=sizeof(s->session->master_key);
-+              if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
-+                      NULL, &pref_cipher, s->tls_session_secret_cb_arg))
-+                      {
-+                      s->session->cipher=pref_cipher ?
-+                              pref_cipher : ssl_get_cipher_by_char(s,p+j);
-+                      s->s3->flags |= SSL3_FLAGS_CCS_OK;
-+                      }
-+              }
-+#endif /* OPENSSL_NO_TLSEXT */
-+
-       if (j != 0 && j == s->session->session_id_length
-           && memcmp(p,s->session->session_id,j) == 0)
-           {
-@@ -2745,11 +2760,8 @@ int ssl3_check_finished(SSL *s)
-       {
-       int ok;
-       long n;
--      /* If we have no ticket or session ID is non-zero length (a match of
--       * a non-zero session length would never reach here) it cannot be a
--       * resumed session.
--       */
--      if (!s->session->tlsext_tick || s->session->session_id_length)
-+      /* If we have no ticket it cannot be a resumed session. */
-+      if (!s->session->tlsext_tick)
-               return 1;
-       /* this function is called when we really expect a Certificate
-        * message, so permit appropriate message length */
-diff -upr openssl-0.9.8za.orig/ssl/s3_srvr.c openssl-0.9.8za/ssl/s3_srvr.c
---- openssl-0.9.8za.orig/ssl/s3_srvr.c 2014-06-05 11:09:26.000000000 +0300
-+++ openssl-0.9.8za/ssl/s3_srvr.c      2014-06-05 20:37:09.225387312 +0300
-@@ -1011,6 +1011,59 @@ int ssl3_get_client_hello(SSL *s)
-                       SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
-                       goto err;
-               }
-+
-+      /* Check if we want to use external pre-shared secret for this
-+       * handshake for not reused session only. We need to generate
-+       * server_random before calling tls_session_secret_cb in order to allow
-+       * SessionTicket processing to use it in key derivation. */
-+      {
-+              unsigned long Time;
-+              unsigned char *pos;
-+              Time=(unsigned long)time(NULL);                 /* Time */
-+              pos=s->s3->server_random;
-+              l2n(Time,pos);
-+              if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
-+                      {
-+                      al=SSL_AD_INTERNAL_ERROR;
-+                      goto f_err;
-+                      }
-+      }
-+
-+      if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+              {
-+              SSL_CIPHER *pref_cipher=NULL;
-+
-+              s->session->master_key_length=sizeof(s->session->master_key);
-+              if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, 
-+                      ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
-+                      {
-+                      s->hit=1;
-+                      s->session->ciphers=ciphers;
-+                      s->session->verify_result=X509_V_OK;
-+                      
-+                      ciphers=NULL;
-+                      
-+                      /* check if some cipher was preferred by call back */
-+                      pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
-+                      if (pref_cipher == NULL)
-+                              {
-+                              al=SSL_AD_HANDSHAKE_FAILURE;
-+                              SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
-+                              goto f_err;
-+                              }
-+
-+                      s->session->cipher=pref_cipher;
-+
-+                      if (s->cipher_list)
-+                              sk_SSL_CIPHER_free(s->cipher_list);
-+
-+                      if (s->cipher_list_by_id)
-+                              sk_SSL_CIPHER_free(s->cipher_list_by_id);
-+
-+                      s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
-+                      s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
-+                      }
-+              }
- #endif
-       /* Worst case, we will use the NULL compression, but if we have other
-        * options, we will now look for them.  We have i-1 compression
-@@ -1161,16 +1214,22 @@ int ssl3_send_server_hello(SSL *s)
-       unsigned char *buf;
-       unsigned char *p,*d;
-       int i,sl;
--      unsigned long l,Time;
-+      unsigned long l;
-+#ifdef OPENSSL_NO_TLSEXT
-+      unsigned long Time;
-+#endif
-       if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
-               {
-               buf=(unsigned char *)s->init_buf->data;
-+#ifdef OPENSSL_NO_TLSEXT
-               p=s->s3->server_random;
-+              /* Generate server_random if it was not needed previously */
-               Time=(unsigned long)time(NULL);                 /* Time */
-               l2n(Time,p);
-               if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
-                       return -1;
-+#endif
-               /* Do the message type and length last */
-               d=p= &(buf[4]);
-diff -upr openssl-0.9.8za.orig/ssl/ssl_err.c openssl-0.9.8za/ssl/ssl_err.c
---- openssl-0.9.8za.orig/ssl/ssl_err.c 2014-06-05 11:09:08.000000000 +0300
-+++ openssl-0.9.8za/ssl/ssl_err.c      2014-06-05 20:37:09.225387312 +0300
-@@ -265,6 +265,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
- {ERR_FUNC(SSL_F_TLS1_ENC),    "TLS1_ENC"},
- {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),        "TLS1_SETUP_KEY_BLOCK"},
- {ERR_FUNC(SSL_F_WRITE_PENDING),       "WRITE_PENDING"},
-+{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
- {0,NULL}
-       };
-diff -upr openssl-0.9.8za.orig/ssl/ssl.h openssl-0.9.8za/ssl/ssl.h
---- openssl-0.9.8za.orig/ssl/ssl.h     2014-06-05 11:09:08.000000000 +0300
-+++ openssl-0.9.8za/ssl/ssl.h  2014-06-05 20:37:09.229387312 +0300
-@@ -344,6 +344,7 @@ extern "C" {
-  * 'struct ssl_st *' function parameters used to prototype callbacks
-  * in SSL_CTX. */
- typedef struct ssl_st *ssl_crock_st;
-+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
- /* used to hold info on the particular ciphers used */
- typedef struct ssl_cipher_st
-@@ -362,6 +363,9 @@ typedef struct ssl_cipher_st
- DECLARE_STACK_OF(SSL_CIPHER)
-+typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg);
-+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
-+
- /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
- typedef struct ssl_method_st
-       {
-@@ -1053,6 +1057,18 @@ struct ssl_st
-       /* RFC4507 session ticket expected to be received or sent */
-       int tlsext_ticket_expected;
-+
-+      /* TLS Session Ticket extension override */
-+      TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
-+
-+      /* TLS Session Ticket extension callback */
-+      tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
-+      void *tls_session_ticket_ext_cb_arg;
-+
-+      /* TLS pre-shared secret session resumption */
-+      tls_session_secret_cb_fn tls_session_secret_cb;
-+      void *tls_session_secret_cb_arg;
-+
-       SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
- #define session_ctx initial_ctx
- #else
-@@ -1668,6 +1684,15 @@ void *SSL_COMP_get_compression_methods(v
- int SSL_COMP_add_compression_method(int id,void *cm);
- #endif
-+/* TLS extensions functions */
-+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
-+
-+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
-+                                void *arg);
-+
-+/* Pre-shared secret session resumption functions */
-+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
-+
- /* BEGIN ERROR CODES */
- /* The following lines are auto generated by the script mkerr.pl. Any changes
-  * made after this point may be overwritten when the script is next run.
-@@ -1872,6 +1897,7 @@ void ERR_load_SSL_strings(void);
- #define SSL_F_TLS1_ENC                                         210
- #define SSL_F_TLS1_SETUP_KEY_BLOCK                     211
- #define SSL_F_WRITE_PENDING                            212
-+#define SSL_F_SSL_SET_SESSION_TICKET_EXT               213
- /* Reason codes. */
- #define SSL_R_APP_DATA_IN_HANDSHAKE                    100
-diff -upr openssl-0.9.8za.orig/ssl/ssl_sess.c openssl-0.9.8za/ssl/ssl_sess.c
---- openssl-0.9.8za.orig/ssl/ssl_sess.c        2014-06-05 11:09:08.000000000 +0300
-+++ openssl-0.9.8za/ssl/ssl_sess.c     2014-06-05 20:37:09.229387312 +0300
-@@ -712,6 +712,61 @@ long SSL_CTX_get_timeout(const SSL_CTX *
-       return(s->session_timeout);
-       }
-+#ifndef OPENSSL_NO_TLSEXT
-+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
-+      STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
-+      {
-+      if (s == NULL) return(0);
-+      s->tls_session_secret_cb = tls_session_secret_cb;
-+      s->tls_session_secret_cb_arg = arg;
-+      return(1);
-+      }
-+
-+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
-+                                void *arg)
-+      {
-+      if (s == NULL) return(0);
-+      s->tls_session_ticket_ext_cb = cb;
-+      s->tls_session_ticket_ext_cb_arg = arg;
-+      return(1);
-+      }
-+
-+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
-+      {
-+      if (s->version >= TLS1_VERSION)
-+              {
-+              if (s->tlsext_session_ticket)
-+                      {
-+                      OPENSSL_free(s->tlsext_session_ticket);
-+                      s->tlsext_session_ticket = NULL;
-+                      }
-+
-+              s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
-+              if (!s->tlsext_session_ticket)
-+                      {
-+                      SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
-+                      return 0;
-+                      }
-+
-+              if (ext_data)
-+                      {
-+                      s->tlsext_session_ticket->length = ext_len;
-+                      s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
-+                      memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
-+                      }
-+              else
-+                      {
-+                      s->tlsext_session_ticket->length = 0;
-+                      s->tlsext_session_ticket->data = NULL;
-+                      }
-+
-+              return 1;
-+              }
-+
-+      return 0;
-+      }
-+#endif /* OPENSSL_NO_TLSEXT */
-+
- typedef struct timeout_param_st
-       {
-       SSL_CTX *ctx;
-diff -upr openssl-0.9.8za.orig/ssl/t1_lib.c openssl-0.9.8za/ssl/t1_lib.c
---- openssl-0.9.8za.orig/ssl/t1_lib.c  2014-06-05 11:09:08.000000000 +0300
-+++ openssl-0.9.8za/ssl/t1_lib.c       2014-06-05 20:37:09.229387312 +0300
-@@ -106,6 +106,12 @@ int tls1_new(SSL *s)
- void tls1_free(SSL *s)
-       {
-+#ifndef OPENSSL_NO_TLSEXT
-+      if (s->tlsext_session_ticket)
-+              {
-+              OPENSSL_free(s->tlsext_session_ticket);
-+              }
-+#endif
-       ssl3_free(s);
-       }
-@@ -206,8 +212,23 @@ unsigned char *ssl_add_clienthello_tlsex
-               int ticklen;
-               if (!s->new_session && s->session && s->session->tlsext_tick)
-                       ticklen = s->session->tlsext_ticklen;
-+              else if (s->session && s->tlsext_session_ticket &&
-+                       s->tlsext_session_ticket->data)
-+                      {
-+                      ticklen = s->tlsext_session_ticket->length;
-+                      s->session->tlsext_tick = OPENSSL_malloc(ticklen);
-+                      if (!s->session->tlsext_tick)
-+                              return NULL;
-+                      memcpy(s->session->tlsext_tick,
-+                             s->tlsext_session_ticket->data,
-+                             ticklen);
-+                      s->session->tlsext_ticklen = ticklen;
-+                      }
-               else
-                       ticklen = 0;
-+              if (ticklen == 0 && s->tlsext_session_ticket &&
-+                  s->tlsext_session_ticket->data == NULL)
-+                      goto skip_ext;
-               /* Check for enough room 2 for extension type, 2 for len
-                * rest for ticket
-                */
-@@ -221,6 +242,7 @@ unsigned char *ssl_add_clienthello_tlsex
-                       ret += ticklen;
-                       }
-               }
-+              skip_ext:
-       if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
-           s->version != DTLS1_VERSION)
-@@ -574,6 +596,15 @@ int ssl_parse_clienthello_tlsext(SSL *s,
-                               return 0;
-                       renegotiate_seen = 1;
-                       }
-+              else if (type == TLSEXT_TYPE_session_ticket)
-+                      {
-+                      if (s->tls_session_ticket_ext_cb &&
-+                          !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
-+                              {
-+                              *al = TLS1_AD_INTERNAL_ERROR;
-+                              return 0;
-+                              }
-+                      }
-               else if (type == TLSEXT_TYPE_status_request &&
-                        s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb)
-                       {
-@@ -751,6 +782,12 @@ int ssl_parse_serverhello_tlsext(SSL *s,
-                       }
-               else if (type == TLSEXT_TYPE_session_ticket)
-                       {
-+                      if (s->tls_session_ticket_ext_cb &&
-+                          !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
-+                              {
-+                              *al = TLS1_AD_INTERNAL_ERROR;
-+                              return 0;
-+                              }
-                       if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
-                               || (size > 0))
-                               {
-@@ -1043,6 +1080,15 @@ int tls1_process_ticket(SSL *s, unsigned
-                               s->tlsext_ticket_expected = 1;
-                               return 0;       /* Cache miss */
-                               }
-+                      if (s->tls_session_secret_cb)
-+                              {
-+                              /* Indicate cache miss here and instead of
-+                               * generating the session from ticket now,
-+                               * trigger abbreviated handshake based on
-+                               * external mechanism to calculate the master
-+                               * secret later. */
-+                              return 0;
-+                              }
-                       return tls_decrypt_ticket(s, p, size, session_id, len,
-                                                                       ret);
-                       }
-diff -upr openssl-0.9.8za.orig/ssl/tls1.h openssl-0.9.8za/ssl/tls1.h
---- openssl-0.9.8za.orig/ssl/tls1.h    2014-06-05 11:09:08.000000000 +0300
-+++ openssl-0.9.8za/ssl/tls1.h 2014-06-05 20:37:09.229387312 +0300
-@@ -415,6 +415,13 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
- #define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
- #endif
-+/* TLS extension struct */
-+struct tls_session_ticket_ext_st
-+      {
-+      unsigned short length;
-+      void *data;
-+      };
-+
- #ifdef  __cplusplus
- }
- #endif
-diff -upr openssl-0.9.8za.orig/util/ssleay.num openssl-0.9.8za/util/ssleay.num
---- openssl-0.9.8za.orig/util/ssleay.num       2014-06-05 12:38:45.000000000 +0300
-+++ openssl-0.9.8za/util/ssleay.num    2014-06-05 20:37:09.229387312 +0300
-@@ -242,3 +242,5 @@ SSL_set_SSL_CTX
- SSL_get_servername                      291   EXIST::FUNCTION:TLSEXT
- SSL_get_servername_type                 292   EXIST::FUNCTION:TLSEXT
- SSL_CTX_set_client_cert_engine          293   EXIST::FUNCTION:ENGINE
-+SSL_set_session_ticket_ext            306     EXIST::FUNCTION:TLSEXT
-+SSL_set_session_secret_cb             307     EXIST::FUNCTION:TLSEXT
diff --git a/libeap/patches/openssl-0.9.8zf-tls-extensions.patch b/libeap/patches/openssl-0.9.8zf-tls-extensions.patch
deleted file mode 100644 (file)
index 3a8f90e..0000000
+++ /dev/null
@@ -1,398 +0,0 @@
-This patch adds support for TLS SessionTicket extension (RFC 5077) for
-the parts used by EAP-FAST (RFC 4851).
-
-This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
-(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
-
-OpenSSL 0.9.8zf does not enable TLS extension support by default, so it
-will need to be enabled by adding enable-tlsext to config script
-command line.
-
-
-diff -upr openssl-0.9.8zf.orig/ssl/s3_clnt.c openssl-0.9.8zf/ssl/s3_clnt.c
---- openssl-0.9.8zf.orig/ssl/s3_clnt.c 2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/s3_clnt.c      2015-03-24 16:19:14.043911769 +0200
-@@ -760,6 +760,23 @@ int ssl3_get_server_hello(SSL *s)
-         goto f_err;
-     }
-+#ifndef OPENSSL_NO_TLSEXT
-+    /* check if we want to resume the session based on external pre-shared secret */
-+    if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
-+        SSL_CIPHER *pref_cipher = NULL;
-+
-+        s->session->master_key_length = sizeof(s->session->master_key);
-+        if (s->tls_session_secret_cb(s, s->session->master_key,
-+                                   &s->session->master_key_length,
-+                                   NULL, &pref_cipher,
-+                                   s->tls_session_secret_cb_arg)) {
-+            s->session->cipher = pref_cipher ?
-+                  pref_cipher : ssl_get_cipher_by_char(s, p + j);
-+          s->s3->flags |= SSL3_FLAGS_CCS_OK;
-+      }
-+    }
-+#endif /* OPENSSL_NO_TLSEXT */
-+
-     if (j != 0 && j == s->session->session_id_length
-         && memcmp(p, s->session->session_id, j) == 0) {
-         if (s->sid_ctx_length != s->session->sid_ctx_length
-@@ -2684,12 +2701,8 @@ int ssl3_check_finished(SSL *s)
- {
-     int ok;
-     long n;
--    /*
--     * If we have no ticket or session ID is non-zero length (a match of a
--     * non-zero session length would never reach here) it cannot be a resumed
--     * session.
--     */
--    if (!s->session->tlsext_tick || s->session->session_id_length)
-+    /* If we have no ticket it cannot be a resumed session. */
-+    if (!s->session->tlsext_tick)
-         return 1;
-     /*
-      * this function is called when we really expect a Certificate message,
-diff -upr openssl-0.9.8zf.orig/ssl/s3_srvr.c openssl-0.9.8zf/ssl/s3_srvr.c
---- openssl-0.9.8zf.orig/ssl/s3_srvr.c 2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/s3_srvr.c      2015-03-24 16:23:34.567909681 +0200
-@@ -999,6 +999,59 @@ int ssl3_get_client_hello(SSL *s)
-         SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
-         goto err;
-     }
-+
-+    /* Check if we want to use external pre-shared secret for this
-+     * handshake for not reused session only. We need to generate
-+     * server_random before calling tls_session_secret_cb in order to allow
-+     * SessionTicket processing to use it in key derivation. */
-+    {
-+        unsigned long Time;
-+      unsigned char *pos;
-+      Time = (unsigned long)time(NULL);                       /* Time */
-+      pos = s->s3->server_random;
-+      l2n(Time, pos);
-+      if (RAND_pseudo_bytes(pos, SSL3_RANDOM_SIZE - 4) <= 0) {
-+              al = SSL_AD_INTERNAL_ERROR;
-+              goto f_err;
-+      }
-+    }
-+
-+    if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
-+      SSL_CIPHER *pref_cipher = NULL;
-+
-+      s->session->master_key_length = sizeof(s->session->master_key);
-+      if (s->tls_session_secret_cb(s, s->session->master_key,
-+                                   &s->session->master_key_length, 
-+                                   ciphers, &pref_cipher,
-+                                   s->tls_session_secret_cb_arg)) {
-+          s->hit = 1;
-+          s->session->ciphers = ciphers;
-+          s->session->verify_result = X509_V_OK;
-+
-+          ciphers = NULL;
-+
-+          /* check if some cipher was preferred by call back */
-+          pref_cipher = pref_cipher ? pref_cipher :
-+                  ssl3_choose_cipher(s, s->session->ciphers,
-+                                     SSL_get_ciphers(s));
-+          if (pref_cipher == NULL) {
-+              al = SSL_AD_HANDSHAKE_FAILURE;
-+              SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER);
-+              goto f_err;
-+          }
-+
-+          s->session->cipher = pref_cipher;
-+
-+          if (s->cipher_list)
-+              sk_SSL_CIPHER_free(s->cipher_list);
-+
-+          if (s->cipher_list_by_id)
-+              sk_SSL_CIPHER_free(s->cipher_list_by_id);
-+
-+          s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
-+          s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
-+      }
-+    }
- #endif
-     /*
-      * Worst case, we will use the NULL compression, but if we have other
-@@ -1143,15 +1196,21 @@ int ssl3_send_server_hello(SSL *s)
-     unsigned char *buf;
-     unsigned char *p, *d;
-     int i, sl;
--    unsigned long l, Time;
-+    unsigned long l;
-+#ifdef OPENSSL_NO_TLSEXT
-+    unsigned long Time;
-+#endif
-     if (s->state == SSL3_ST_SW_SRVR_HELLO_A) {
-         buf = (unsigned char *)s->init_buf->data;
-+#ifdef OPENSSL_NO_TLSEXT
-         p = s->s3->server_random;
-+        /* Generate server_random if it was not needed previously */
-         Time = (unsigned long)time(NULL); /* Time */
-         l2n(Time, p);
-         if (RAND_pseudo_bytes(p, SSL3_RANDOM_SIZE - 4) <= 0)
-             return -1;
-+#endif
-         /* Do the message type and length last */
-         d = p = &(buf[4]);
-diff -upr openssl-0.9.8zf.orig/ssl/ssl_err.c openssl-0.9.8zf/ssl/ssl_err.c
---- openssl-0.9.8zf.orig/ssl/ssl_err.c 2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/ssl_err.c      2015-03-24 16:35:58.627903717 +0200
-@@ -316,6 +316,7 @@ static ERR_STRING_DATA SSL_str_functs[]
-     {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
-     {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
-     {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
-+    {ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
-     {0, NULL}
- };
-diff -upr openssl-0.9.8zf.orig/ssl/ssl.h openssl-0.9.8zf/ssl/ssl.h
---- openssl-0.9.8zf.orig/ssl/ssl.h     2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/ssl.h  2015-03-24 16:25:44.339908641 +0200
-@@ -349,6 +349,7 @@ extern "C" {
-  * function parameters used to prototype callbacks in SSL_CTX.
-  */
- typedef struct ssl_st *ssl_crock_st;
-+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
- /* used to hold info on the particular ciphers used */
- typedef struct ssl_cipher_st {
-@@ -366,6 +367,12 @@ typedef struct ssl_cipher_st {
- DECLARE_STACK_OF(SSL_CIPHER)
-+typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data,
-+                                          int len, void *arg);
-+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len,
-+                                      STACK_OF(SSL_CIPHER) *peer_ciphers,
-+                                      SSL_CIPHER **cipher, void *arg);
-+
- /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
- typedef struct ssl_method_st {
-     int version;
-@@ -1116,6 +1123,18 @@ struct ssl_st {
-     int tlsext_ocsp_resplen;
-     /* RFC4507 session ticket expected to be received or sent */
-     int tlsext_ticket_expected;
-+
-+    /* TLS Session Ticket extension override */
-+    TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
-+
-+    /* TLS Session Ticket extension callback */
-+    tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
-+    void *tls_session_ticket_ext_cb_arg;
-+
-+    /* TLS pre-shared secret session resumption */
-+    tls_session_secret_cb_fn tls_session_secret_cb;
-+    void *tls_session_secret_cb_arg;
-+
-     SSL_CTX *initial_ctx;       /* initial ctx, used to store sessions */
- #  define session_ctx initial_ctx
- # else
-@@ -1772,6 +1791,17 @@ void *SSL_COMP_get_compression_methods(v
- int SSL_COMP_add_compression_method(int id, void *cm);
- # endif
-+/* TLS extensions functions */
-+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
-+
-+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
-+                                void *arg);
-+
-+/* Pre-shared secret session resumption functions */
-+int SSL_set_session_secret_cb(SSL *s,
-+                            tls_session_secret_cb_fn tls_session_secret_cb,
-+                            void *arg);
-+
- /* BEGIN ERROR CODES */
- /*
-  * The following lines are auto generated by the script mkerr.pl. Any changes
-@@ -1977,6 +2007,7 @@ void ERR_load_SSL_strings(void);
- # define SSL_F_TLS1_ENC                                   210
- # define SSL_F_TLS1_SETUP_KEY_BLOCK                       211
- # define SSL_F_WRITE_PENDING                              212
-+#define SSL_F_SSL_SET_SESSION_TICKET_EXT                  213
- /* Reason codes. */
- # define SSL_R_APP_DATA_IN_HANDSHAKE                      100
-diff -upr openssl-0.9.8zf.orig/ssl/ssl_sess.c openssl-0.9.8zf/ssl/ssl_sess.c
---- openssl-0.9.8zf.orig/ssl/ssl_sess.c        2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/ssl_sess.c     2015-03-24 16:28:04.819907515 +0200
-@@ -716,6 +716,61 @@ long SSL_CTX_get_timeout(const SSL_CTX *
-     return (s->session_timeout);
- }
-+#ifndef OPENSSL_NO_TLSEXT
-+int SSL_set_session_secret_cb(
-+      SSL *s,
-+      int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
-+                                   STACK_OF(SSL_CIPHER) *peer_ciphers,
-+                                   SSL_CIPHER **cipher, void *arg), void *arg)
-+{
-+    if (s == NULL)
-+          return 0;
-+    s->tls_session_secret_cb = tls_session_secret_cb;
-+    s->tls_session_secret_cb_arg = arg;
-+    return 1;
-+}
-+
-+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
-+                                void *arg)
-+{
-+    if (s == NULL)
-+          return 0;
-+    s->tls_session_ticket_ext_cb = cb;
-+    s->tls_session_ticket_ext_cb_arg = arg;
-+    return 1;
-+}
-+
-+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
-+{
-+    if (s->version >= TLS1_VERSION) {
-+      if (s->tlsext_session_ticket) {
-+          OPENSSL_free(s->tlsext_session_ticket);
-+          s->tlsext_session_ticket = NULL;
-+      }
-+
-+      s->tlsext_session_ticket = OPENSSL_malloc(
-+              sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
-+      if (!s->tlsext_session_ticket) {
-+          SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
-+          return 0;
-+      }
-+
-+      if (ext_data) {
-+          s->tlsext_session_ticket->length = ext_len;
-+          s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
-+          memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
-+      } else {
-+              s->tlsext_session_ticket->length = 0;
-+              s->tlsext_session_ticket->data = NULL;
-+      }
-+
-+      return 1;
-+    }
-+
-+    return 0;
-+}
-+#endif /* OPENSSL_NO_TLSEXT */
-+
- typedef struct timeout_param_st {
-     SSL_CTX *ctx;
-     long time;
-diff -upr openssl-0.9.8zf.orig/ssl/t1_lib.c openssl-0.9.8zf/ssl/t1_lib.c
---- openssl-0.9.8zf.orig/ssl/t1_lib.c  2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/t1_lib.c       2015-03-24 16:32:46.923905254 +0200
-@@ -108,6 +108,11 @@ int tls1_new(SSL *s)
- void tls1_free(SSL *s)
- {
-+#ifndef OPENSSL_NO_TLSEXT
-+    if (s->tlsext_session_ticket) {
-+      OPENSSL_free(s->tlsext_session_ticket);
-+    }
-+#endif
-     ssl3_free(s);
- }
-@@ -206,8 +211,20 @@ unsigned char *ssl_add_clienthello_tlsex
-         int ticklen;
-         if (!s->new_session && s->session && s->session->tlsext_tick)
-             ticklen = s->session->tlsext_ticklen;
--        else
-+      else if (s->session && s->tlsext_session_ticket &&
-+               s->tlsext_session_ticket->data) {
-+          ticklen = s->tlsext_session_ticket->length;
-+          s->session->tlsext_tick = OPENSSL_malloc(ticklen);
-+          if (!s->session->tlsext_tick)
-+              return NULL;
-+          memcpy(s->session->tlsext_tick, s->tlsext_session_ticket->data,
-+                 ticklen);
-+          s->session->tlsext_ticklen = ticklen;
-+      } else
-             ticklen = 0;
-+      if (ticklen == 0 && s->tlsext_session_ticket &&
-+          s->tlsext_session_ticket->data == NULL)
-+          goto skip_ext;
-         /*
-          * Check for enough room 2 for extension type, 2 for len rest for
-          * ticket
-@@ -221,6 +238,7 @@ unsigned char *ssl_add_clienthello_tlsex
-             ret += ticklen;
-         }
-     }
-+skip_ext:
-     if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
-         s->version != DTLS1_VERSION) {
-@@ -560,6 +578,14 @@ int ssl_parse_clienthello_tlsext(SSL *s,
-             if (!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
-                 return 0;
-             renegotiate_seen = 1;
-+      } else if (type == TLSEXT_TYPE_session_ticket) {
-+          if (s->tls_session_ticket_ext_cb &&
-+              !s->tls_session_ticket_ext_cb(s, data, size,
-+                                            s->tls_session_ticket_ext_cb_arg))
-+          {
-+              *al = TLS1_AD_INTERNAL_ERROR;
-+              return 0;
-+          }
-         } else if (type == TLSEXT_TYPE_status_request &&
-                    s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb) {
-@@ -710,6 +736,13 @@ int ssl_parse_serverhello_tlsext(SSL *s,
-             }
-             tlsext_servername = 1;
-         } else if (type == TLSEXT_TYPE_session_ticket) {
-+          if (s->tls_session_ticket_ext_cb &&
-+              !s->tls_session_ticket_ext_cb(
-+                      s, data, size,
-+                      s->tls_session_ticket_ext_cb_arg)) {
-+              *al = TLS1_AD_INTERNAL_ERROR;
-+              return 0;
-+          }
-             if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
-                 || (size > 0)) {
-                 *al = TLS1_AD_UNSUPPORTED_EXTENSION;
-@@ -993,6 +1026,14 @@ int tls1_process_ticket(SSL *s, unsigned
-                 s->tlsext_ticket_expected = 1;
-                 return 0;       /* Cache miss */
-             }
-+          if (s->tls_session_secret_cb) {
-+              /* Indicate cache miss here and instead of
-+               * generating the session from ticket now,
-+               * trigger abbreviated handshake based on
-+               * external mechanism to calculate the master
-+               * secret later. */
-+              return 0;
-+          }
-             return tls_decrypt_ticket(s, p, size, session_id, len, ret);
-         }
-         p += size;
-diff -upr openssl-0.9.8zf.orig/ssl/tls1.h openssl-0.9.8zf/ssl/tls1.h
---- openssl-0.9.8zf.orig/ssl/tls1.h    2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/tls1.h 2015-03-24 16:33:31.855904894 +0200
-@@ -460,6 +460,12 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
- #  define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"
- # endif
-+/* TLS extension struct */
-+struct tls_session_ticket_ext_st {
-+    unsigned short length;
-+    void *data;
-+};
-+
- #ifdef  __cplusplus
- }
- #endif
-diff -upr openssl-0.9.8zf.orig/util/ssleay.num openssl-0.9.8zf/util/ssleay.num
---- openssl-0.9.8zf.orig/util/ssleay.num       2015-03-19 15:47:15.000000000 +0200
-+++ openssl-0.9.8zf/util/ssleay.num    2015-03-24 16:33:51.127904739 +0200
-@@ -242,3 +242,5 @@ SSL_set_SSL_CTX
- SSL_get_servername                      291   EXIST::FUNCTION:TLSEXT
- SSL_get_servername_type                 292   EXIST::FUNCTION:TLSEXT
- SSL_CTX_set_client_cert_engine          293   EXIST::FUNCTION:ENGINE
-+SSL_set_session_ticket_ext            306     EXIST::FUNCTION:TLSEXT
-+SSL_set_session_secret_cb             307     EXIST::FUNCTION:TLSEXT
index e4b3678..8b0f475 100644 (file)
@@ -61,7 +61,7 @@ static void start_example(void *eloop_ctx, void *timeout_ctx)
                return;
        }
 
-       radius_msg_make_authenticator(msg, (u8 *) ctx, sizeof(*ctx));
+       radius_msg_make_authenticator(msg);
 
        if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
                                 (u8 *) "user", 4)) {
index a096de4..0aacc3c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / RADIUS Accounting
- * Copyright (c) 2002-2009, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -41,6 +41,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
        size_t len;
        int i;
        struct wpabuf *b;
+       struct os_time now;
 
        msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
                             radius_client_get_id(hapd->radius));
@@ -49,44 +50,24 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                return NULL;
        }
 
-       if (sta) {
-               radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
-
-               if ((hapd->conf->wpa & 2) &&
-                   !hapd->conf->disable_pmksa_caching &&
-                   sta->eapol_sm && sta->eapol_sm->acct_multi_session_id_hi) {
-                       os_snprintf(buf, sizeof(buf), "%08X+%08X",
-                                   sta->eapol_sm->acct_multi_session_id_hi,
-                                   sta->eapol_sm->acct_multi_session_id_lo);
-                       if (!radius_msg_add_attr(
-                                   msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
-                                   (u8 *) buf, os_strlen(buf))) {
-                               wpa_printf(MSG_INFO,
-                                          "Could not add Acct-Multi-Session-Id");
-                               goto fail;
-                       }
-               }
-       } else {
-               radius_msg_make_authenticator(msg, (u8 *) hapd, sizeof(*hapd));
-       }
-
        if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
                                       status_type)) {
                wpa_printf(MSG_INFO, "Could not add Acct-Status-Type");
                goto fail;
        }
 
-       if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
-                                           RADIUS_ATTR_ACCT_AUTHENTIC) &&
-           !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
-                                      hapd->conf->ieee802_1x ?
-                                      RADIUS_ACCT_AUTHENTIC_RADIUS :
-                                      RADIUS_ACCT_AUTHENTIC_LOCAL)) {
-               wpa_printf(MSG_INFO, "Could not add Acct-Authentic");
-               goto fail;
-       }
-
        if (sta) {
+               if (!hostapd_config_get_radius_attr(
+                           hapd->conf->radius_acct_req_attr,
+                           RADIUS_ATTR_ACCT_AUTHENTIC) &&
+                   !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
+                                              hapd->conf->ieee802_1x ?
+                                              RADIUS_ACCT_AUTHENTIC_RADIUS :
+                                              RADIUS_ACCT_AUTHENTIC_LOCAL)) {
+                       wpa_printf(MSG_INFO, "Could not add Acct-Authentic");
+                       goto fail;
+               }
+
                /* Use 802.1X identity if available */
                val = ieee802_1x_get_identity(sta->eapol_sm, &len);
 
@@ -147,6 +128,32 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                        wpa_printf(MSG_ERROR, "Could not add CUI from ACL");
                        goto fail;
                }
+
+               if (sta->ipaddr &&
+                   !radius_msg_add_attr_int32(msg,
+                                              RADIUS_ATTR_FRAMED_IP_ADDRESS,
+                                              be_to_host32(sta->ipaddr))) {
+                       wpa_printf(MSG_ERROR,
+                                  "Could not add Framed-IP-Address");
+                       goto fail;
+               }
+       }
+
+       os_get_time(&now);
+       if (now.sec > 1000000000 &&
+           !radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
+                                      now.sec)) {
+               wpa_printf(MSG_INFO, "Could not add Event-Timestamp");
+               goto fail;
+       }
+
+       /*
+        * Add Acct-Delay-Time with zero value for the first transmission. This
+        * will be updated within radius_client.c when retransmitting the frame.
+        */
+       if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_DELAY_TIME, 0)) {
+               wpa_printf(MSG_INFO, "Could not add Acct-Delay-Time");
+               goto fail;
        }
 
        return msg;
@@ -164,19 +171,25 @@ static int accounting_sta_update_stats(struct hostapd_data *hapd,
        if (hostapd_drv_read_sta_data(hapd, data, sta->addr))
                return -1;
 
-       if (sta->last_rx_bytes > data->rx_bytes)
-               sta->acct_input_gigawords++;
-       if (sta->last_tx_bytes > data->tx_bytes)
-               sta->acct_output_gigawords++;
-       sta->last_rx_bytes = data->rx_bytes;
-       sta->last_tx_bytes = data->tx_bytes;
+       if (!data->bytes_64bit) {
+               /* Extend 32-bit counters from the driver to 64-bit counters */
+               if (sta->last_rx_bytes_lo > data->rx_bytes)
+                       sta->last_rx_bytes_hi++;
+               sta->last_rx_bytes_lo = data->rx_bytes;
+
+               if (sta->last_tx_bytes_lo > data->tx_bytes)
+                       sta->last_tx_bytes_hi++;
+               sta->last_tx_bytes_lo = data->tx_bytes;
+       }
 
        hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
-                      HOSTAPD_LEVEL_DEBUG, "updated TX/RX stats: "
-                      "Acct-Input-Octets=%lu Acct-Input-Gigawords=%u "
-                      "Acct-Output-Octets=%lu Acct-Output-Gigawords=%u",
-                      sta->last_rx_bytes, sta->acct_input_gigawords,
-                      sta->last_tx_bytes, sta->acct_output_gigawords);
+                      HOSTAPD_LEVEL_DEBUG,
+                      "updated TX/RX stats: rx_bytes=%llu [%u:%u] tx_bytes=%llu [%u:%u] bytes_64bit=%d",
+                      data->rx_bytes, sta->last_rx_bytes_hi,
+                      sta->last_rx_bytes_lo,
+                      data->tx_bytes, sta->last_tx_bytes_hi,
+                      sta->last_tx_bytes_lo,
+                      data->bytes_64bit);
 
        return 0;
 }
@@ -217,12 +230,14 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
 
        hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
                       HOSTAPD_LEVEL_INFO,
-                      "starting accounting session %08X-%08X",
-                      sta->acct_session_id_hi, sta->acct_session_id_lo);
+                      "starting accounting session %016llX",
+                      (unsigned long long) sta->acct_session_id);
 
        os_get_reltime(&sta->acct_session_start);
-       sta->last_rx_bytes = sta->last_tx_bytes = 0;
-       sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
+       sta->last_rx_bytes_hi = 0;
+       sta->last_rx_bytes_lo = 0;
+       sta->last_tx_bytes_hi = 0;
+       sta->last_tx_bytes_lo = 0;
        hostapd_drv_sta_clear_stats(hapd, sta->addr);
 
        if (!hapd->conf->radius->acct_server)
@@ -251,8 +266,7 @@ static void accounting_sta_report(struct hostapd_data *hapd,
        int cause = sta->acct_terminate_cause;
        struct hostap_sta_driver_data data;
        struct os_reltime now_r, diff;
-       struct os_time now;
-       u32 gigawords;
+       u64 bytes;
 
        if (!hapd->conf->radius->acct_server)
                return;
@@ -266,7 +280,6 @@ static void accounting_sta_report(struct hostapd_data *hapd,
        }
 
        os_get_reltime(&now_r);
-       os_get_time(&now);
        os_reltime_sub(&now_r, &sta->acct_session_start, &diff);
        if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
                                       diff.sec)) {
@@ -287,48 +300,42 @@ static void accounting_sta_report(struct hostapd_data *hapd,
                        wpa_printf(MSG_INFO, "Could not add Acct-Output-Packets");
                        goto fail;
                }
+               if (data.bytes_64bit)
+                       bytes = data.rx_bytes;
+               else
+                       bytes = ((u64) sta->last_rx_bytes_hi << 32) |
+                               sta->last_rx_bytes_lo;
                if (!radius_msg_add_attr_int32(msg,
                                               RADIUS_ATTR_ACCT_INPUT_OCTETS,
-                                              data.rx_bytes)) {
+                                              (u32) bytes)) {
                        wpa_printf(MSG_INFO, "Could not add Acct-Input-Octets");
                        goto fail;
                }
-               gigawords = sta->acct_input_gigawords;
-#if __WORDSIZE == 64
-               gigawords += data.rx_bytes >> 32;
-#endif
-               if (gigawords &&
-                   !radius_msg_add_attr_int32(
-                           msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
-                           gigawords)) {
+               if (!radius_msg_add_attr_int32(msg,
+                                              RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
+                                              (u32) (bytes >> 32))) {
                        wpa_printf(MSG_INFO, "Could not add Acct-Input-Gigawords");
                        goto fail;
                }
+               if (data.bytes_64bit)
+                       bytes = data.tx_bytes;
+               else
+                       bytes = ((u64) sta->last_tx_bytes_hi << 32) |
+                               sta->last_tx_bytes_lo;
                if (!radius_msg_add_attr_int32(msg,
                                               RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
-                                              data.tx_bytes)) {
+                                              (u32) bytes)) {
                        wpa_printf(MSG_INFO, "Could not add Acct-Output-Octets");
                        goto fail;
                }
-               gigawords = sta->acct_output_gigawords;
-#if __WORDSIZE == 64
-               gigawords += data.tx_bytes >> 32;
-#endif
-               if (gigawords &&
-                   !radius_msg_add_attr_int32(
-                           msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
-                           gigawords)) {
+               if (!radius_msg_add_attr_int32(msg,
+                                              RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
+                                              (u32) (bytes >> 32))) {
                        wpa_printf(MSG_INFO, "Could not add Acct-Output-Gigawords");
                        goto fail;
                }
        }
 
-       if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
-                                      now.sec)) {
-               wpa_printf(MSG_INFO, "Could not add Event-Timestamp");
-               goto fail;
-       }
-
        if (eloop_terminated())
                cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT;
 
@@ -375,22 +382,17 @@ void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
                eloop_cancel_timeout(accounting_interim_update, hapd, sta);
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
                               HOSTAPD_LEVEL_INFO,
-                              "stopped accounting session %08X-%08X",
-                              sta->acct_session_id_hi,
-                              sta->acct_session_id_lo);
+                              "stopped accounting session %016llX",
+                              (unsigned long long) sta->acct_session_id);
                sta->acct_session_started = 0;
        }
 }
 
 
-void accounting_sta_get_id(struct hostapd_data *hapd,
-                                 struct sta_info *sta)
+int accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta)
 {
-       sta->acct_session_id_lo = hapd->acct_session_id_lo++;
-       if (hapd->acct_session_id_lo == 0) {
-               hapd->acct_session_id_hi++;
-       }
-       sta->acct_session_id_hi = hapd->acct_session_id_hi;
+       return radius_gen_session_id((u8 *) &sta->acct_session_id,
+                                    sizeof(sta->acct_session_id));
 }
 
 
@@ -437,12 +439,14 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
        if (!msg)
                return;
 
-       if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
-                                      RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
-       {
-               wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
-               radius_msg_free(msg);
-               return;
+       if (hapd->acct_session_id) {
+               char buf[20];
+
+               os_snprintf(buf, sizeof(buf), "%016llX",
+                           (unsigned long long) hapd->acct_session_id);
+               if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
+                                        (u8 *) buf, os_strlen(buf)))
+                       wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id");
        }
 
        if (radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL) < 0)
@@ -450,6 +454,63 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
 }
 
 
+static void accounting_interim_error_cb(const u8 *addr, void *ctx)
+{
+       struct hostapd_data *hapd = ctx;
+       struct sta_info *sta;
+       unsigned int i, wait_time;
+       int res;
+
+       sta = ap_get_sta(hapd, addr);
+       if (!sta)
+               return;
+       sta->acct_interim_errors++;
+       if (sta->acct_interim_errors > 10 /* RADIUS_CLIENT_MAX_RETRIES */) {
+               wpa_printf(MSG_DEBUG,
+                          "Interim RADIUS accounting update failed for " MACSTR
+                          " - too many errors, abandon this interim accounting update",
+                          MAC2STR(addr));
+               sta->acct_interim_errors = 0;
+               /* Next update will be tried after normal update interval */
+               return;
+       }
+
+       /*
+        * Use a shorter update interval as an improved retransmission mechanism
+        * for failed interim accounting updates. This allows the statistics to
+        * be updated for each retransmission.
+        *
+        * RADIUS client code has already waited RADIUS_CLIENT_FIRST_WAIT.
+        * Schedule the first retry attempt immediately and every following one
+        * with exponential backoff.
+        */
+       if (sta->acct_interim_errors == 1) {
+               wait_time = 0;
+       } else {
+               wait_time = 3; /* RADIUS_CLIENT_FIRST_WAIT */
+               for (i = 1; i < sta->acct_interim_errors; i++)
+                       wait_time *= 2;
+       }
+       res = eloop_deplete_timeout(wait_time, 0, accounting_interim_update,
+                                   hapd, sta);
+       if (res == 1)
+               wpa_printf(MSG_DEBUG,
+                          "Interim RADIUS accounting update failed for " MACSTR
+                          " (error count: %u) - schedule next update in %u seconds",
+                          MAC2STR(addr), sta->acct_interim_errors, wait_time);
+       else if (res == 0)
+               wpa_printf(MSG_DEBUG,
+                          "Interim RADIUS accounting update failed for " MACSTR
+                          " (error count: %u)", MAC2STR(addr),
+                          sta->acct_interim_errors);
+       else
+               wpa_printf(MSG_DEBUG,
+                          "Interim RADIUS accounting update failed for " MACSTR
+                          " (error count: %u) - no timer found", MAC2STR(addr),
+                          sta->acct_interim_errors);
+}
+
+
 /**
  * accounting_init: Initialize accounting
  * @hapd: hostapd BSS data
@@ -457,20 +518,15 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
  */
 int accounting_init(struct hostapd_data *hapd)
 {
-       struct os_time now;
-
-       /* Acct-Session-Id should be unique over reboots. Using a random number
-        * is preferred. If that is not available, take the current time. Mix
-        * in microseconds to make this more likely to be unique. */
-       os_get_time(&now);
-       if (os_get_random((u8 *) &hapd->acct_session_id_hi,
-                         sizeof(hapd->acct_session_id_hi)) < 0)
-               hapd->acct_session_id_hi = now.sec;
-       hapd->acct_session_id_hi ^= now.usec;
+       if (radius_gen_session_id((u8 *) &hapd->acct_session_id,
+                                 sizeof(hapd->acct_session_id)) < 0)
+               return -1;
 
        if (radius_client_register(hapd->radius, RADIUS_ACCT,
                                   accounting_receive, hapd))
                return -1;
+       radius_client_set_interim_error_cb(hapd->radius,
+                                          accounting_interim_error_cb, hapd);
 
        accounting_report_state(hapd, 1);
 
index dcc54ee..de5a33f 100644 (file)
 #define ACCOUNTING_H
 
 #ifdef CONFIG_NO_ACCOUNTING
-static inline void accounting_sta_get_id(struct hostapd_data *hapd,
-                                        struct sta_info *sta)
+static inline int accounting_sta_get_id(struct hostapd_data *hapd,
+                                       struct sta_info *sta)
 {
+       return 0;
 }
 
 static inline void accounting_sta_start(struct hostapd_data *hapd,
@@ -34,7 +35,7 @@ static inline void accounting_deinit(struct hostapd_data *hapd)
 {
 }
 #else /* CONFIG_NO_ACCOUNTING */
-void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
+int accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
 void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta);
 void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta);
 int accounting_init(struct hostapd_data *hapd);
index 03d797f..5e83805 100644 (file)
@@ -599,8 +599,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
        wpa_printf(MSG_DEBUG, "ACS: Survey analysis for selected bandwidth %d MHz",
                   n_chans == 1 ? 20 :
                   n_chans == 2 ? 40 :
-                  n_chans == 4 ? 80 :
-                  -1);
+                  80);
 
        for (i = 0; i < iface->current_mode->num_channels; i++) {
                double total_weight;
@@ -933,6 +932,9 @@ enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
                return HOSTAPD_CHAN_ACS;
        }
 
+       if (!iface->current_mode)
+               return HOSTAPD_CHAN_INVALID;
+
        acs_cleanup(iface);
 
        err = acs_request_scan(iface);
index 9a96e50..228de2b 100644 (file)
@@ -38,6 +38,8 @@ static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
 
 void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
 {
+       dl_list_init(&bss->anqp_elem);
+
        bss->logger_syslog_level = HOSTAPD_LEVEL_INFO;
        bss->logger_stdout_level = HOSTAPD_LEVEL_INFO;
        bss->logger_syslog = (unsigned int) -1;
@@ -63,6 +65,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
        bss->dtim_period = 2;
 
        bss->radius_server_auth_port = 1812;
+       bss->eap_sim_db_timeout = 1;
        bss->ap_max_inactivity = AP_MAX_INACTIVITY;
        bss->eapol_version = EAPOL_VERSION;
 
@@ -180,6 +183,7 @@ struct hostapd_config * hostapd_config_defaults(void)
        conf->ignore_assoc_probability = 0.0;
        conf->ignore_reassoc_probability = 0.0;
        conf->corrupt_gtk_rekey_mic_probability = 0.0;
+       conf->ecsa_ie_only = 0;
 #endif /* CONFIG_TESTING_OPTIONS */
 
        conf->acs = 0;
@@ -198,13 +202,6 @@ int hostapd_mac_comp(const void *a, const void *b)
 }
 
 
-int hostapd_mac_comp_empty(const void *a)
-{
-       macaddr empty = { 0 };
-       return os_memcmp(a, empty, sizeof(macaddr));
-}
-
-
 static int hostapd_config_read_wpa_psk(const char *fname,
                                       struct hostapd_ssid *ssid)
 {
@@ -410,6 +407,19 @@ void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l)
 }
 
 
+static void hostapd_config_free_anqp_elem(struct hostapd_bss_config *conf)
+{
+       struct anqp_element *elem;
+
+       while ((elem = dl_list_first(&conf->anqp_elem, struct anqp_element,
+                                    list))) {
+               dl_list_del(&elem->list);
+               wpabuf_free(elem->payload);
+               os_free(elem);
+       }
+}
+
+
 void hostapd_config_free_bss(struct hostapd_bss_config *conf)
 {
        struct hostapd_eap_user *user, *prev_user;
@@ -454,6 +464,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
        os_free(conf->private_key);
        os_free(conf->private_key_passwd);
        os_free(conf->ocsp_stapling_response);
+       os_free(conf->ocsp_stapling_response_multi);
        os_free(conf->dh_file);
        os_free(conf->openssl_ciphers);
        os_free(conf->pac_opaque_encr_key);
@@ -523,6 +534,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
        os_free(conf->network_auth_type);
        os_free(conf->anqp_3gpp_cell_net);
        os_free(conf->domain_name);
+       hostapd_config_free_anqp_elem(conf);
 
 #ifdef CONFIG_RADIUS_TEST
        os_free(conf->dump_msk_file);
@@ -555,6 +567,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
 #endif /* CONFIG_HS20 */
 
        wpabuf_free(conf->vendor_elements);
+       wpabuf_free(conf->assocresp_elements);
 
        os_free(conf->sae_groups);
 
@@ -594,6 +607,8 @@ void hostapd_config_free(struct hostapd_config *conf)
 #ifdef CONFIG_ACS
        os_free(conf->acs_chan_bias);
 #endif /* CONFIG_ACS */
+       wpabuf_free(conf->lci);
+       wpabuf_free(conf->civic);
 
        os_free(conf);
 }
@@ -610,7 +625,7 @@ void hostapd_config_free(struct hostapd_config *conf)
  * Perform a binary search for given MAC address from a pre-sorted list.
  */
 int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
-                         const u8 *addr, int *vlan_id)
+                         const u8 *addr, struct vlan_description *vlan_id)
 {
        int start, end, middle, res;
 
@@ -650,11 +665,26 @@ int hostapd_rate_found(int *list, int rate)
 }
 
 
-int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id)
+int hostapd_vlan_valid(struct hostapd_vlan *vlan,
+                      struct vlan_description *vlan_desc)
 {
        struct hostapd_vlan *v = vlan;
+       int i;
+
+       if (!vlan_desc->notempty || vlan_desc->untagged < 0 ||
+           vlan_desc->untagged > MAX_VLAN_ID)
+               return 0;
+       for (i = 0; i < MAX_NUM_TAGGED_VLAN; i++) {
+               if (vlan_desc->tagged[i] < 0 ||
+                   vlan_desc->tagged[i] > MAX_VLAN_ID)
+                       return 0;
+       }
+       if (!vlan_desc->untagged && !vlan_desc->tagged[0])
+               return 0;
+
        while (v) {
-               if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
+               if (!vlan_compare(&v->vlan_desc, vlan_desc) ||
+                   v->vlan_id == VLAN_ID_WILDCARD)
                        return 1;
                v = v->next;
        }
@@ -756,7 +786,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
                return -1;
        }
 
-       if (full_config && hostapd_mac_comp_empty(bss->bssid) != 0) {
+       if (full_config && !is_zero_ether_addr(bss->bssid)) {
                size_t i;
 
                for (i = 0; i < conf->num_bss; i++) {
@@ -811,6 +841,15 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
        }
 #endif /* CONFIG_IEEE80211N */
 
+#ifdef CONFIG_IEEE80211AC
+       if (full_config && conf->ieee80211ac &&
+           bss->ssid.security_policy == SECURITY_STATIC_WEP) {
+               bss->disable_11ac = 1;
+               wpa_printf(MSG_ERROR,
+                          "VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
+       }
+#endif /* CONFIG_IEEE80211AC */
+
 #ifdef CONFIG_WPS
        if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) {
                wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
@@ -847,6 +886,15 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
        }
 #endif /* CONFIG_HS20 */
 
+#ifdef CONFIG_MBO
+       if (full_config && bss->mbo_enabled && (bss->wpa & 2) &&
+           bss->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
+               wpa_printf(MSG_ERROR,
+                          "MBO: PMF needs to be enabled whenever using WPA2 with MBO");
+               return -1;
+       }
+#endif /* CONFIG_MBO */
+
        return 0;
 }
 
index de470a9..8c8f7e2 100644 (file)
 #define HOSTAPD_CONFIG_H
 
 #include "common/defs.h"
+#include "utils/list.h"
 #include "ip_addr.h"
 #include "common/wpa_common.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "wps/wps.h"
 #include "fst/fst.h"
+#include "vlan.h"
 
 /**
  * mesh_conf - local MBSS state and settings
@@ -39,6 +41,10 @@ struct mesh_conf {
 #define MESH_CONF_SEC_AUTH BIT(1)
 #define MESH_CONF_SEC_AMPE BIT(2)
        unsigned int security;
+       enum mfp_options ieee80211w;
+       unsigned int pairwise_cipher;
+       unsigned int group_cipher;
+       unsigned int mgmt_group_cipher;
        int dot11MeshMaxRetries;
        int dot11MeshRetryTimeout; /* msec */
        int dot11MeshConfirmTimeout; /* msec */
@@ -52,7 +58,7 @@ typedef u8 macaddr[ETH_ALEN];
 
 struct mac_acl_entry {
        macaddr addr;
-       int vlan_id;
+       struct vlan_description vlan_id;
 };
 
 struct hostapd_radius_servers;
@@ -102,6 +108,7 @@ struct hostapd_ssid {
 #define DYNAMIC_VLAN_NAMING_WITH_DEVICE 1
 #define DYNAMIC_VLAN_NAMING_END 2
        int vlan_naming;
+       int per_sta_vif;
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
        char *vlan_tagged_interface;
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
@@ -113,6 +120,7 @@ struct hostapd_ssid {
 struct hostapd_vlan {
        struct hostapd_vlan *next;
        int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
+       struct vlan_description vlan_desc;
        char ifname[IFNAMSIZ + 1];
        int configured;
        int dynamic_vlan;
@@ -124,9 +132,14 @@ struct hostapd_vlan {
 };
 
 #define PMK_LEN 32
+#define MIN_PASSPHRASE_LEN 8
+#define MAX_PASSPHRASE_LEN 63
 struct hostapd_sta_wpa_psk_short {
        struct hostapd_sta_wpa_psk_short *next;
+       unsigned int is_passphrase:1;
        u8 psk[PMK_LEN];
+       char passphrase[MAX_PASSPHRASE_LEN + 1];
+       int ref; /* (number of references held) - 1 */
 };
 
 struct hostapd_wpa_psk {
@@ -205,6 +218,13 @@ struct hostapd_nai_realm_data {
        } eap_method[MAX_NAI_EAP_METHODS];
 };
 
+struct anqp_element {
+       struct dl_list list;
+       u16 infoid;
+       struct wpabuf *payload;
+};
+
+
 /**
  * struct hostapd_bss_config - Per-BSS configuration
  */
@@ -231,6 +251,7 @@ struct hostapd_bss_config {
        struct hostapd_eap_user *eap_user;
        char *eap_user_sqlite;
        char *eap_sim_db;
+       unsigned int eap_sim_db_timeout;
        int eap_server_erp; /* Whether ERP is enabled on internal EAP server */
        struct hostapd_ip_addr own_ip_addr;
        char *nas_identifier;
@@ -242,6 +263,7 @@ struct hostapd_bss_config {
        int radius_das_port;
        unsigned int radius_das_time_window;
        int radius_das_require_event_timestamp;
+       int radius_das_require_message_authenticator;
        struct hostapd_ip_addr radius_das_client_addr;
        u8 *radius_das_shared_secret;
        size_t radius_das_shared_secret_len;
@@ -332,6 +354,7 @@ struct hostapd_bss_config {
        int check_crl;
        unsigned int tls_session_lifetime;
        char *ocsp_stapling_response;
+       char *ocsp_stapling_response_multi;
        char *dh_file;
        char *openssl_ciphers;
        u8 *pac_opaque_encr_key;
@@ -358,6 +381,7 @@ struct hostapd_bss_config {
 
        int ap_max_inactivity;
        int ignore_broadcast_ssid;
+       int no_probe_resp_if_max_sta;
 
        int wmm_enabled;
        int wmm_uapsd;
@@ -481,8 +505,11 @@ struct hostapd_bss_config {
        unsigned int nai_realm_count;
        struct hostapd_nai_realm_data *nai_realm_data;
 
+       struct dl_list anqp_elem; /* list of struct anqp_element */
+
        u16 gas_comeback_delay;
        int gas_frag_limit;
+       int gas_address3;
 
        u8 qos_map_set[16 + 2 * 21];
        unsigned int qos_map_set_len;
@@ -536,6 +563,7 @@ struct hostapd_bss_config {
 #endif /* CONFIG_RADIUS_TEST */
 
        struct wpabuf *vendor_elements;
+       struct wpabuf *assocresp_elements;
 
        unsigned int sae_anti_clogging_threshold;
        int *sae_groups;
@@ -551,12 +579,22 @@ struct hostapd_bss_config {
 #define MESH_ENABLED BIT(0)
        int mesh;
 
-       int radio_measurements;
+       u8 radio_measurements[RRM_CAPABILITIES_IE_LEN];
 
        int vendor_vht;
+       int use_sta_nsts;
 
        char *no_probe_resp_if_seen_on;
        char *no_auth_if_seen_on;
+
+       int pbss;
+
+#ifdef CONFIG_MBO
+       int mbo_enabled;
+#endif /* CONFIG_MBO */
+
+       int ftm_responder;
+       int ftm_initiator;
 };
 
 
@@ -638,6 +676,9 @@ struct hostapd_config {
        u8 vht_oper_centr_freq_seg0_idx;
        u8 vht_oper_centr_freq_seg1_idx;
 
+       /* Use driver-generated interface addresses when adding multiple BSSs */
+       u8 use_driver_iface_addr;
+
 #ifdef CONFIG_FST
        struct fst_iface_cfg fst_cfg;
 #endif /* CONFIG_FST */
@@ -652,6 +693,7 @@ struct hostapd_config {
        double ignore_assoc_probability;
        double ignore_reassoc_probability;
        double corrupt_gtk_rekey_mic_probability;
+       int ecsa_ie_only;
 #endif /* CONFIG_TESTING_OPTIONS */
 
 #ifdef CONFIG_ACS
@@ -662,11 +704,13 @@ struct hostapd_config {
        } *acs_chan_bias;
        unsigned int num_acs_chan_bias;
 #endif /* CONFIG_ACS */
+
+       struct wpabuf *lci;
+       struct wpabuf *civic;
 };
 
 
 int hostapd_mac_comp(const void *a, const void *b);
-int hostapd_mac_comp_empty(const void *a);
 struct hostapd_config * hostapd_config_defaults(void);
 void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
 void hostapd_config_free_eap_user(struct hostapd_eap_user *user);
@@ -674,13 +718,14 @@ void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
 void hostapd_config_free_bss(struct hostapd_bss_config *conf);
 void hostapd_config_free(struct hostapd_config *conf);
 int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
-                         const u8 *addr, int *vlan_id);
+                         const u8 *addr, struct vlan_description *vlan_id);
 int hostapd_rate_found(int *list, int rate);
 const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
                           const u8 *addr, const u8 *p2p_dev_addr,
                           const u8 *prev_psk);
 int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
-int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id);
+int hostapd_vlan_valid(struct hostapd_vlan *vlan,
+                      struct vlan_description *vlan_desc);
 const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
                                        int vlan_id);
 struct hostapd_radius_attr *
index 6cafcb7..f139465 100644 (file)
@@ -33,10 +33,36 @@ u32 hostapd_sta_flags_to_drv(u32 flags)
                res |= WPA_STA_SHORT_PREAMBLE;
        if (flags & WLAN_STA_MFP)
                res |= WPA_STA_MFP;
+       if (flags & WLAN_STA_AUTH)
+               res |= WPA_STA_AUTHENTICATED;
+       if (flags & WLAN_STA_ASSOC)
+               res |= WPA_STA_ASSOCIATED;
        return res;
 }
 
 
+static int add_buf(struct wpabuf **dst, const struct wpabuf *src)
+{
+       if (!src)
+               return 0;
+       if (wpabuf_resize(dst, wpabuf_len(src)) != 0)
+               return -1;
+       wpabuf_put_buf(*dst, src);
+       return 0;
+}
+
+
+static int add_buf_data(struct wpabuf **dst, const u8 *data, size_t len)
+{
+       if (!data || !len)
+               return 0;
+       if (wpabuf_resize(dst, len) != 0)
+               return -1;
+       wpabuf_put_data(*dst, data, len);
+       return 0;
+}
+
+
 int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
                               struct wpabuf **beacon_ret,
                               struct wpabuf **proberesp_ret,
@@ -49,82 +75,38 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
 
        pos = buf;
        pos = hostapd_eid_time_adv(hapd, pos);
-       if (pos != buf) {
-               if (wpabuf_resize(&beacon, pos - buf) != 0)
-                       goto fail;
-               wpabuf_put_data(beacon, buf, pos - buf);
-       }
+       if (add_buf_data(&beacon, buf, pos - buf) < 0)
+               goto fail;
        pos = hostapd_eid_time_zone(hapd, pos);
-       if (pos != buf) {
-               if (wpabuf_resize(&proberesp, pos - buf) != 0)
-                       goto fail;
-               wpabuf_put_data(proberesp, buf, pos - buf);
-       }
+       if (add_buf_data(&proberesp, buf, pos - buf) < 0)
+               goto fail;
 
        pos = buf;
        pos = hostapd_eid_ext_capab(hapd, pos);
-       if (pos != buf) {
-               if (wpabuf_resize(&assocresp, pos - buf) != 0)
-                       goto fail;
-               wpabuf_put_data(assocresp, buf, pos - buf);
-       }
+       if (add_buf_data(&assocresp, buf, pos - buf) < 0)
+               goto fail;
        pos = hostapd_eid_interworking(hapd, pos);
        pos = hostapd_eid_adv_proto(hapd, pos);
        pos = hostapd_eid_roaming_consortium(hapd, pos);
-       if (pos != buf) {
-               if (wpabuf_resize(&beacon, pos - buf) != 0)
-                       goto fail;
-               wpabuf_put_data(beacon, buf, pos - buf);
-
-               if (wpabuf_resize(&proberesp, pos - buf) != 0)
-                       goto fail;
-               wpabuf_put_data(proberesp, buf, pos - buf);
-       }
+       if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
+           add_buf_data(&proberesp, buf, pos - buf) < 0)
+               goto fail;
 
 #ifdef CONFIG_FST
-       if (hapd->iface->fst_ies) {
-               size_t add = wpabuf_len(hapd->iface->fst_ies);
-
-               if (wpabuf_resize(&beacon, add) < 0)
-                       goto fail;
-               wpabuf_put_buf(beacon, hapd->iface->fst_ies);
-               if (wpabuf_resize(&proberesp, add) < 0)
-                       goto fail;
-               wpabuf_put_buf(proberesp, hapd->iface->fst_ies);
-               if (wpabuf_resize(&assocresp, add) < 0)
-                       goto fail;
-               wpabuf_put_buf(assocresp, hapd->iface->fst_ies);
-       }
+       if (add_buf(&beacon, hapd->iface->fst_ies) < 0 ||
+           add_buf(&proberesp, hapd->iface->fst_ies) < 0 ||
+           add_buf(&assocresp, hapd->iface->fst_ies) < 0)
+               goto fail;
 #endif /* CONFIG_FST */
 
-       if (hapd->wps_beacon_ie) {
-               if (wpabuf_resize(&beacon, wpabuf_len(hapd->wps_beacon_ie)) <
-                   0)
-                       goto fail;
-               wpabuf_put_buf(beacon, hapd->wps_beacon_ie);
-       }
-
-       if (hapd->wps_probe_resp_ie) {
-               if (wpabuf_resize(&proberesp,
-                                 wpabuf_len(hapd->wps_probe_resp_ie)) < 0)
-                       goto fail;
-               wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie);
-       }
+       if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 ||
+           add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0)
+               goto fail;
 
 #ifdef CONFIG_P2P
-       if (hapd->p2p_beacon_ie) {
-               if (wpabuf_resize(&beacon, wpabuf_len(hapd->p2p_beacon_ie)) <
-                   0)
-                       goto fail;
-               wpabuf_put_buf(beacon, hapd->p2p_beacon_ie);
-       }
-
-       if (hapd->p2p_probe_resp_ie) {
-               if (wpabuf_resize(&proberesp,
-                                 wpabuf_len(hapd->p2p_probe_resp_ie)) < 0)
-                       goto fail;
-               wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie);
-       }
+       if (add_buf(&beacon, hapd->p2p_beacon_ie) < 0 ||
+           add_buf(&proberesp, hapd->p2p_probe_resp_ie) < 0)
+               goto fail;
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_P2P_MANAGER
@@ -148,8 +130,7 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
 #ifdef CONFIG_WPS
        if (hapd->conf->wps_state) {
                struct wpabuf *a = wps_build_assoc_resp_ie();
-               if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
-                       wpabuf_put_buf(assocresp, a);
+               add_buf(&assocresp, a);
                wpabuf_free(a);
        }
 #endif /* CONFIG_WPS */
@@ -169,44 +150,36 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
        if (hapd->p2p_group) {
                struct wpabuf *a;
                a = p2p_group_assoc_resp_ie(hapd->p2p_group, P2P_SC_SUCCESS);
-               if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
-                       wpabuf_put_buf(assocresp, a);
+               add_buf(&assocresp, a);
                wpabuf_free(a);
        }
 #endif /* CONFIG_WIFI_DISPLAY */
 
 #ifdef CONFIG_HS20
-       pos = buf;
-       pos = hostapd_eid_hs20_indication(hapd, pos);
-       if (pos != buf) {
-               if (wpabuf_resize(&beacon, pos - buf) != 0)
-                       goto fail;
-               wpabuf_put_data(beacon, buf, pos - buf);
-
-               if (wpabuf_resize(&proberesp, pos - buf) != 0)
-                       goto fail;
-               wpabuf_put_data(proberesp, buf, pos - buf);
-       }
+       pos = hostapd_eid_hs20_indication(hapd, buf);
+       if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
+           add_buf_data(&proberesp, buf, pos - buf) < 0)
+               goto fail;
 
        pos = hostapd_eid_osen(hapd, buf);
-       if (pos != buf) {
-               if (wpabuf_resize(&beacon, pos - buf) != 0)
-                       goto fail;
-               wpabuf_put_data(beacon, buf, pos - buf);
+       if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
+           add_buf_data(&proberesp, buf, pos - buf) < 0)
+               goto fail;
+#endif /* CONFIG_HS20 */
 
-               if (wpabuf_resize(&proberesp, pos - buf) != 0)
+#ifdef CONFIG_MBO
+       if (hapd->conf->mbo_enabled) {
+               pos = hostapd_eid_mbo(hapd, buf, sizeof(buf));
+               if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
+                   add_buf_data(&proberesp, buf, pos - buf) < 0 ||
+                   add_buf_data(&assocresp, buf, pos - buf) < 0)
                        goto fail;
-               wpabuf_put_data(proberesp, buf, pos - buf);
        }
-#endif /* CONFIG_HS20 */
+#endif /* CONFIG_MBO */
 
-       if (hapd->conf->vendor_elements) {
-               size_t add = wpabuf_len(hapd->conf->vendor_elements);
-               if (wpabuf_resize(&beacon, add) == 0)
-                       wpabuf_put_buf(beacon, hapd->conf->vendor_elements);
-               if (wpabuf_resize(&proberesp, add) == 0)
-                       wpabuf_put_buf(proberesp, hapd->conf->vendor_elements);
-       }
+       add_buf(&beacon, hapd->conf->vendor_elements);
+       add_buf(&proberesp, hapd->conf->vendor_elements);
+       add_buf(&assocresp, hapd->conf->assocresp_elements);
 
        *beacon_ret = beacon;
        *proberesp_ret = proberesp;
@@ -390,7 +363,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
                    u16 listen_interval,
                    const struct ieee80211_ht_capabilities *ht_capab,
                    const struct ieee80211_vht_capabilities *vht_capab,
-                   u32 flags, u8 qosinfo, u8 vht_opmode)
+                   u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
+                   int set)
 {
        struct hostapd_sta_add_params params;
 
@@ -412,6 +386,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
        params.vht_opmode = vht_opmode;
        params.flags = hostapd_sta_flags_to_drv(flags);
        params.qosinfo = qosinfo;
+       params.support_p2p_ps = supp_p2p_ps;
+       params.set = set;
        return hapd->driver->sta_add(hapd->drv_priv, &params);
 }
 
@@ -468,7 +444,7 @@ int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
                return -1;
        return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
                                    bss_ctx, drv_priv, force_ifname, if_addr,
-                                   bridge, use_existing);
+                                   bridge, use_existing, 1);
 }
 
 
@@ -647,16 +623,28 @@ int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
 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);
+}
+
+
+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)
+{
        if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
                return 0;
-       return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0);
+       return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
+                                      csa_offs, csa_offs_len);
 }
 
 
 int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
                           const u8 *addr, int reason)
 {
-       if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
+       if (!hapd->driver || !hapd->driver->sta_deauth || !hapd->drv_priv)
                return 0;
        return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr,
                                        reason);
@@ -666,7 +654,7 @@ int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
 int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
                             const u8 *addr, int reason)
 {
-       if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
+       if (!hapd->driver || !hapd->driver->sta_disassoc || !hapd->drv_priv)
                return 0;
        return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
                                          reason);
@@ -687,6 +675,36 @@ int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
                            unsigned int wait, const u8 *dst, const u8 *data,
                            size_t len)
 {
+       const u8 *bssid;
+       const u8 wildcard_bssid[ETH_ALEN] = {
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+       };
+
+       if (!hapd->driver || !hapd->driver->send_action || !hapd->drv_priv)
+               return 0;
+       bssid = hapd->own_addr;
+       if (!is_multicast_ether_addr(dst) &&
+           len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
+               struct sta_info *sta;
+
+               /*
+                * Public Action frames to a STA that is not a member of the BSS
+                * shall use wildcard BSSID value.
+                */
+               sta = ap_get_sta(hapd, dst);
+               if (!sta || !(sta->flags & WLAN_STA_ASSOC))
+                       bssid = wildcard_bssid;
+       }
+       return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
+                                        hapd->own_addr, bssid, data, len, 0);
+}
+
+
+int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd,
+                                    unsigned int freq,
+                                    unsigned int wait, const u8 *dst,
+                                    const u8 *data, size_t len)
+{
        if (hapd->driver == NULL || hapd->driver->send_action == NULL)
                return 0;
        return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
@@ -736,7 +754,7 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
 int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
                            const u8 *qos_map_set, u8 qos_map_set_len)
 {
-       if (hapd->driver == NULL || hapd->driver->set_qos_map == NULL)
+       if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv)
                return 0;
        return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
                                         qos_map_set_len);
@@ -762,6 +780,20 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
 }
 
 
+void hostapd_get_ext_capa(struct hostapd_iface *iface)
+{
+       struct hostapd_data *hapd = iface->bss[0];
+
+       if (!hapd->driver || !hapd->driver->get_ext_capab)
+               return;
+
+       hapd->driver->get_ext_capab(hapd->drv_priv, WPA_IF_AP_BSS,
+                                   &iface->extended_capa,
+                                   &iface->extended_capa_mask,
+                                   &iface->extended_capa_len);
+}
+
+
 int hostapd_drv_do_acs(struct hostapd_data *hapd)
 {
        struct drv_acs_params params;
index 82eaf3f..0bb7954 100644 (file)
@@ -41,7 +41,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
                    u16 listen_interval,
                    const struct ieee80211_ht_capabilities *ht_capab,
                    const struct ieee80211_vht_capabilities *vht_capab,
-                   u32 flags, u8 qosinfo, u8 vht_opmode);
+                   u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
+                   int set);
 int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
 int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
                             size_t elem_len);
@@ -88,6 +89,9 @@ int hostapd_drv_set_key(const char *ifname,
                        const u8 *key, size_t key_len);
 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);
 int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
                           const u8 *addr, int reason);
 int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
@@ -95,6 +99,10 @@ int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
 int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
                            unsigned int wait, const u8 *dst, const u8 *data,
                            size_t len);
+int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd,
+                                    unsigned int freq,
+                                    unsigned int wait, const u8 *dst,
+                                    const u8 *data, size_t len);
 int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
                         u16 auth_alg);
 int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
@@ -120,6 +128,8 @@ int hostapd_drv_wnm_oper(struct hostapd_data *hapd,
 int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set,
                            u8 qos_map_set_len);
 
+void hostapd_get_ext_capa(struct hostapd_iface *iface);
+
 static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
                                                  int enabled)
 {
@@ -150,7 +160,7 @@ static inline int hostapd_drv_get_inact_sec(struct hostapd_data *hapd,
 static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd,
                                         const u8 *addr)
 {
-       if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
+       if (!hapd->driver || !hapd->driver->sta_remove || !hapd->drv_priv)
                return 0;
        return hapd->driver->sta_remove(hapd->drv_priv, addr);
 }
@@ -273,7 +283,7 @@ static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd,
 static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf,
                                     size_t buflen)
 {
-       if (hapd->driver == NULL || hapd->driver->status == NULL)
+       if (!hapd->driver || !hapd->driver->status || !hapd->drv_priv)
                return -1;
        return hapd->driver->status(hapd->drv_priv, buf, buflen);
 }
@@ -332,7 +342,7 @@ static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
 
 static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
 {
-       if (hapd->driver == NULL || hapd->driver->stop_ap == NULL)
+       if (!hapd->driver || !hapd->driver->stop_ap || !hapd->drv_priv)
                return 0;
        return hapd->driver->stop_ap(hapd->drv_priv);
 }
index 13604ed..e7308a0 100644 (file)
@@ -59,6 +59,7 @@ void mlme_authenticate_indication(struct hostapd_data *hapd,
                       MAC2STR(sta->addr), mlme_auth_alg_str(sta->auth_alg));
        if (sta->auth_alg != WLAN_AUTH_FT && !(sta->flags & WLAN_STA_MFP))
                mlme_deletekeys_request(hapd, sta);
+       ap_sta_clear_disconnect_timeouts(hapd, sta);
 }
 
 
@@ -106,6 +107,7 @@ void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta)
                       MAC2STR(sta->addr));
        if (sta->auth_alg != WLAN_AUTH_FT)
                mlme_deletekeys_request(hapd, sta);
+       ap_sta_clear_disconnect_timeouts(hapd, sta);
 }
 
 
@@ -130,6 +132,7 @@ void mlme_reassociate_indication(struct hostapd_data *hapd,
                       MAC2STR(sta->addr));
        if (sta->auth_alg != WLAN_AUTH_FT)
                mlme_deletekeys_request(hapd, sta);
+       ap_sta_clear_disconnect_timeouts(hapd, sta);
 }
 
 
index 934dcfc..cdb49cd 100644 (file)
@@ -173,6 +173,8 @@ int authsrv_init(struct hostapd_data *hapd)
                params.openssl_ciphers = hapd->conf->openssl_ciphers;
                params.ocsp_stapling_response =
                        hapd->conf->ocsp_stapling_response;
+               params.ocsp_stapling_response_multi =
+                       hapd->conf->ocsp_stapling_response_multi;
 
                if (tls_global_set_params(hapd->ssl_ctx, &params)) {
                        wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
@@ -193,6 +195,7 @@ int authsrv_init(struct hostapd_data *hapd)
        if (hapd->conf->eap_sim_db) {
                hapd->eap_sim_db_priv =
                        eap_sim_db_init(hapd->conf->eap_sim_db,
+                                       hapd->conf->eap_sim_db_timeout,
                                        hostapd_sim_db_cb, hapd);
                if (hapd->eap_sim_db_priv == NULL) {
                        wpa_printf(MSG_ERROR, "Failed to initialize EAP-SIM "
index 5fe8fd5..233320d 100644 (file)
@@ -29,6 +29,7 @@
 #include "beacon.h"
 #include "hs20.h"
 #include "dfs.h"
+#include "taxonomy.h"
 
 
 #ifdef NEED_AP_MLME
 static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
                                         size_t len)
 {
-       if (!hapd->conf->radio_measurements || len < 2 + 4)
+       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++ = 5;
-       *eid++ = (hapd->conf->radio_measurements & BIT(0)) ?
-               WLAN_RRM_CAPS_NEIGHBOR_REPORT : 0x00;
-       *eid++ = 0x00;
-       *eid++ = 0x00;
-       *eid++ = 0x00;
-       *eid++ = 0x00;
-       return eid;
+       *eid++ = RRM_CAPABILITIES_IE_LEN;
+       os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
+
+       return eid + RRM_CAPABILITIES_IE_LEN;
 }
 
 
@@ -297,65 +301,65 @@ static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
 
 static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid)
 {
-       u8 chan;
-
-       if (!hapd->cs_freq_params.freq)
+#ifdef CONFIG_TESTING_OPTIONS
+       if (hapd->iface->cs_oper_class && hapd->iconf->ecsa_ie_only)
                return eid;
+#endif /* CONFIG_TESTING_OPTIONS */
 
-       if (ieee80211_freq_to_chan(hapd->cs_freq_params.freq, &chan) ==
-           NUM_HOSTAPD_MODES)
+       if (!hapd->cs_freq_params.channel)
                return eid;
 
        *eid++ = WLAN_EID_CHANNEL_SWITCH;
        *eid++ = 3;
        *eid++ = hapd->cs_block_tx;
-       *eid++ = chan;
+       *eid++ = hapd->cs_freq_params.channel;
        *eid++ = hapd->cs_count;
 
        return eid;
 }
 
 
-static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
+static u8 * hostapd_eid_ecsa(struct hostapd_data *hapd, u8 *eid)
 {
-       u8 sec_ch;
-
-       if (!hapd->cs_freq_params.sec_channel_offset)
+       if (!hapd->cs_freq_params.channel || !hapd->iface->cs_oper_class)
                return eid;
 
-       if (hapd->cs_freq_params.sec_channel_offset == -1)
-               sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
-       else if (hapd->cs_freq_params.sec_channel_offset == 1)
-               sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE;
-       else
-               return eid;
-
-       *eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;
-       *eid++ = 1;
-       *eid++ = sec_ch;
+       *eid++ = WLAN_EID_EXT_CHANSWITCH_ANN;
+       *eid++ = 4;
+       *eid++ = hapd->cs_block_tx;
+       *eid++ = hapd->iface->cs_oper_class;
+       *eid++ = hapd->cs_freq_params.channel;
+       *eid++ = hapd->cs_count;
 
        return eid;
 }
 
 
-static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos,
-                                 u8 *start, unsigned int *csa_counter_off)
+static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid)
 {
-       u8 *old_pos = pos;
+       u8 op_class, channel;
 
-       if (!csa_counter_off)
-               return pos;
+       if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) ||
+           !hapd->iface->freq)
+               return eid;
 
-       *csa_counter_off = 0;
-       pos = hostapd_eid_csa(hapd, pos);
+       if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
+                                         hapd->iconf->secondary_channel,
+                                         hapd->iconf->vht_oper_chwidth,
+                                         &op_class, &channel) ==
+           NUM_HOSTAPD_MODES)
+               return eid;
 
-       if (pos != old_pos) {
-               /* save an offset to the counter - should be last byte */
-               *csa_counter_off = pos - start - 1;
-               pos = hostapd_eid_secondary_channel(hapd, pos);
-       }
+       *eid++ = WLAN_EID_SUPPORTED_OPERATING_CLASSES;
+       *eid++ = 2;
 
-       return pos;
+       /* Current Operating Class */
+       *eid++ = op_class;
+
+       /* TODO: Advertise all the supported operating classes */
+       *eid++ = 0;
+
+       return eid;
 }
 
 
@@ -364,7 +368,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
                                   int is_p2p, size_t *resp_len)
 {
        struct ieee80211_mgmt *resp;
-       u8 *pos, *epos;
+       u8 *pos, *epos, *csa_pos;
        size_t buflen;
 
 #define MAX_PROBERESP_LEN 768
@@ -387,6 +391,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
                buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
                        2 + sizeof(struct ieee80211_vht_operation);
        }
+
+       buflen += hostapd_mbo_ie_len(hapd);
+
        resp = os_zalloc(buflen);
        if (resp == NULL)
                return NULL;
@@ -424,6 +431,12 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
        /* Power Constraint element */
        pos = hostapd_eid_pwr_constraint(hapd, pos);
 
+       /* CSA IE */
+       csa_pos = hostapd_eid_csa(hapd, pos);
+       if (csa_pos != pos)
+               hapd->cs_c_off_proberesp = csa_pos - (u8 *) resp - 1;
+       pos = csa_pos;
+
        /* ERP Information element */
        pos = hostapd_eid_erp_info(hapd, pos);
 
@@ -437,7 +450,19 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 
        pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
 
+       /* eCSA IE */
+       csa_pos = hostapd_eid_ecsa(hapd, pos);
+       if (csa_pos != pos)
+               hapd->cs_c_off_ecsa_proberesp = csa_pos - (u8 *) resp - 1;
+       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 */
@@ -451,9 +476,6 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
        pos = hostapd_eid_adv_proto(hapd, pos);
        pos = hostapd_eid_roaming_consortium(hapd, pos);
 
-       pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp,
-                                   &hapd->cs_c_off_proberesp);
-
 #ifdef CONFIG_FST
        if (hapd->iface->fst_ies) {
                os_memcpy(pos, wpabuf_head(hapd->iface->fst_ies),
@@ -464,8 +486,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 
 #ifdef CONFIG_IEEE80211AC
        if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
-               pos = hostapd_eid_vht_capabilities(hapd, pos);
+               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);
        }
        if (hapd->conf->vendor_vht)
                pos = hostapd_eid_vendor_vht(hapd, pos);
@@ -501,6 +525,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
        pos = hostapd_eid_osen(hapd, pos);
 #endif /* CONFIG_HS20 */
 
+       pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos);
+
        if (hapd->conf->vendor_elements) {
                os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
                          wpabuf_len(hapd->conf->vendor_elements));
@@ -537,8 +563,8 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
 
        pos = ssid_list;
        end = ssid_list + ssid_list_len;
-       while (pos + 1 <= end) {
-               if (pos + 2 + pos[1] > end)
+       while (end - pos >= 1) {
+               if (2 + pos[1] > end - pos)
                        break;
                if (pos[1] == 0)
                        wildcard = 1;
@@ -574,7 +600,7 @@ void sta_track_expire(struct hostapd_iface *iface, int force)
                           MAC2STR(info->addr));
                dl_list_del(&info->list);
                iface->num_sta_seen--;
-               os_free(info);
+               sta_track_del(info);
        }
 }
 
@@ -607,6 +633,8 @@ void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
 
        /* Add a new entry */
        info = os_zalloc(sizeof(*info));
+       if (info == NULL)
+               return;
        os_memcpy(info->addr, addr, ETH_ALEN);
        os_get_reltime(&info->last_seen);
 
@@ -648,6 +676,23 @@ sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
 }
 
 
+#ifdef CONFIG_TAXONOMY
+void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
+                                  struct wpabuf **probe_ie_taxonomy)
+{
+       struct hostapd_sta_info *info;
+
+       info = sta_track_get(iface, addr);
+       if (!info)
+               return;
+
+       wpabuf_free(*probe_ie_taxonomy);
+       *probe_ie_taxonomy = info->probe_ie_taxonomy;
+       info->probe_ie_taxonomy = NULL;
+}
+#endif /* CONFIG_TAXONOMY */
+
+
 void handle_probe_req(struct hostapd_data *hapd,
                      const struct ieee80211_mgmt *mgmt, size_t len,
                      int ssi_signal)
@@ -659,13 +704,16 @@ void handle_probe_req(struct hostapd_data *hapd,
        size_t i, resp_len;
        int noack;
        enum ssid_match_result res;
+       int ret;
+       u16 csa_offs[2];
+       size_t csa_offs_len;
 
-       ie = mgmt->u.probe_req.variable;
-       if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+       if (len < IEEE80211_HDRLEN)
                return;
+       ie = ((const u8 *) mgmt) + IEEE80211_HDRLEN;
        if (hapd->iconf->track_sta_max_num)
                sta_track_add(hapd->iface, mgmt->sa);
-       ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+       ie_len = len - IEEE80211_HDRLEN;
 
        for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
                if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
@@ -711,7 +759,7 @@ void handle_probe_req(struct hostapd_data *hapd,
        }
 
 #ifdef CONFIG_P2P
-       if (hapd->p2p && elems.wps_ie) {
+       if (hapd->p2p && hapd->p2p_group && elems.wps_ie) {
                struct wpabuf *wps;
                wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
                if (wps && !p2p_group_match_dev_type(hapd->p2p_group, wps)) {
@@ -724,7 +772,7 @@ void handle_probe_req(struct hostapd_data *hapd,
                wpabuf_free(wps);
        }
 
-       if (hapd->p2p && elems.p2p) {
+       if (hapd->p2p && hapd->p2p_group && elems.p2p) {
                struct wpabuf *p2p;
                p2p = ieee802_11_vendor_ie_concat(ie, ie_len, P2P_IE_VENDOR_TYPE);
                if (p2p && !p2p_group_match_dev_id(hapd->p2p_group, p2p)) {
@@ -754,6 +802,21 @@ void handle_probe_req(struct hostapd_data *hapd,
        }
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_TAXONOMY
+       {
+               struct sta_info *sta;
+               struct hostapd_sta_info *info;
+
+               if ((sta = ap_get_sta(hapd, mgmt->sa)) != NULL) {
+                       taxonomy_sta_info_probe_req(hapd, sta, ie, ie_len);
+               } else if ((info = sta_track_get(hapd->iface,
+                                                mgmt->sa)) != NULL) {
+                       taxonomy_hostapd_sta_info_probe_req(hapd, info,
+                                                           ie, ie_len);
+               }
+       }
+#endif /* CONFIG_TAXONOMY */
+
        res = ssid_match(hapd, elems.ssid, elems.ssid_len,
                         elems.ssid_list, elems.ssid_list_len);
        if (res == NO_SSID_MATCH) {
@@ -825,6 +888,17 @@ void handle_probe_req(struct hostapd_data *hapd,
                return;
        }
 
+       if (hapd->conf->no_probe_resp_if_max_sta &&
+           is_multicast_ether_addr(mgmt->da) &&
+           is_multicast_ether_addr(mgmt->bssid) &&
+           hapd->num_sta >= hapd->conf->max_num_sta &&
+           !ap_get_sta(hapd, mgmt->sa)) {
+               wpa_printf(MSG_MSGDUMP, "%s: Ignore Probe Request from " MACSTR
+                          " since no room for additional STA",
+                          hapd->conf->iface, MAC2STR(mgmt->sa));
+               return;
+       }
+
 #ifdef CONFIG_TESTING_OPTIONS
        if (hapd->iconf->ignore_probe_probability > 0.0 &&
            drand48() < hapd->iconf->ignore_probe_probability) {
@@ -847,7 +921,22 @@ void handle_probe_req(struct hostapd_data *hapd,
        noack = !!(res == WILDCARD_SSID_MATCH &&
                   is_broadcast_ether_addr(mgmt->da));
 
-       if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
+       csa_offs_len = 0;
+       if (hapd->csa_in_progress) {
+               if (hapd->cs_c_off_proberesp)
+                       csa_offs[csa_offs_len++] =
+                               hapd->cs_c_off_proberesp;
+
+               if (hapd->cs_c_off_ecsa_proberesp)
+                       csa_offs[csa_offs_len++] =
+                               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);
+
+       if (ret < 0)
                wpa_printf(MSG_INFO, "handle_probe_req: send failed");
 
        os_free(resp);
@@ -896,6 +985,16 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
 #endif /* NEED_AP_MLME */
 
 
+void sta_track_del(struct hostapd_sta_info *info)
+{
+#ifdef CONFIG_TAXONOMY
+       wpabuf_free(info->probe_ie_taxonomy);
+       info->probe_ie_taxonomy = NULL;
+#endif /* CONFIG_TAXONOMY */
+       os_free(info);
+}
+
+
 int ieee802_11_build_ap_params(struct hostapd_data *hapd,
                               struct wpa_driver_ap_params *params)
 {
@@ -906,7 +1005,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;
+       u8 *pos, *tailpos, *csa_pos;
 
 #define BEACON_HEAD_BUF_SIZE 256
 #define BEACON_TAIL_BUF_SIZE 512
@@ -934,6 +1033,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
        }
 #endif /* CONFIG_IEEE80211AC */
 
+       tail_len += hostapd_mbo_ie_len(hapd);
+
        tailpos = tail = os_malloc(tail_len);
        if (head == NULL || tail == NULL) {
                wpa_printf(MSG_ERROR, "Failed to set beacon data");
@@ -987,6 +1088,12 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
        /* Power Constraint element */
        tailpos = hostapd_eid_pwr_constraint(hapd, tailpos);
 
+       /* CSA IE */
+       csa_pos = hostapd_eid_csa(hapd, tailpos);
+       if (csa_pos != tailpos)
+               hapd->cs_c_off_beacon = csa_pos - tail - 1;
+       tailpos = csa_pos;
+
        /* ERP Information element */
        tailpos = hostapd_eid_erp_info(hapd, tailpos);
 
@@ -1004,7 +1111,19 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
        tailpos = hostapd_eid_bss_load(hapd, tailpos,
                                       tail + BEACON_TAIL_BUF_SIZE - tailpos);
 
+       /* eCSA IE */
+       csa_pos = hostapd_eid_ecsa(hapd, tailpos);
+       if (csa_pos != tailpos)
+               hapd->cs_c_off_ecsa_beacon = csa_pos - tail - 1;
+       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 */
@@ -1020,8 +1139,6 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
        tailpos = hostapd_eid_interworking(hapd, tailpos);
        tailpos = hostapd_eid_adv_proto(hapd, tailpos);
        tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
-       tailpos = hostapd_add_csa_elems(hapd, tailpos, tail,
-                                       &hapd->cs_c_off_beacon);
 
 #ifdef CONFIG_FST
        if (hapd->iface->fst_ies) {
@@ -1033,8 +1150,10 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 
 #ifdef CONFIG_IEEE80211AC
        if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
-               tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+               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);
        }
        if (hapd->conf->vendor_vht)
                tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
@@ -1069,6 +1188,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
        tailpos = hostapd_eid_osen(hapd, tailpos);
 #endif /* CONFIG_HS20 */
 
+       tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
+
        if (hapd->conf->vendor_elements) {
                os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
                          wpabuf_len(hapd->conf->vendor_elements));
@@ -1153,6 +1274,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
                params->osen = 1;
        }
 #endif /* CONFIG_HS20 */
+       params->pbss = hapd->conf->pbss;
        return 0;
 }
 
index d98f42e..fc71181 100644 (file)
@@ -22,9 +22,12 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
                               struct wpa_driver_ap_params *params);
 void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params);
 void sta_track_add(struct hostapd_iface *iface, const u8 *addr);
+void sta_track_del(struct hostapd_sta_info *info);
 void sta_track_expire(struct hostapd_iface *iface, int force);
 struct hostapd_data *
 sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
                  const char *ifname);
+void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
+                                  struct wpabuf **probe_ie_taxonomy);
 
 #endif /* BEACON_H */
index c98978f..3680fda 100644 (file)
@@ -22,6 +22,8 @@
 #include "p2p_hostapd.h"
 #include "ctrl_iface_ap.h"
 #include "ap_drv_ops.h"
+#include "mbo_ap.h"
+#include "taxonomy.h"
 
 
 static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
@@ -35,9 +37,9 @@ static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
                return 0;
 
        ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
-                         "rx_bytes=%lu\ntx_bytes=%lu\n",
+                         "rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n",
                          data.rx_packets, data.tx_packets,
-                         data.rx_bytes, data.tx_bytes);
+                         data.rx_bytes, data.tx_bytes, data.inactive_msec);
        if (os_snprintf_error(buflen, ret))
                return 0;
        return ret;
@@ -161,6 +163,19 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
                        len += res;
        }
 
+       res = mbo_ap_get_info(sta, buf + len, buflen - len);
+       if (res >= 0)
+               len += res;
+
+       if (sta->supp_op_classes &&
+           buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
+               len += os_snprintf(buf + len, buflen - len, "supp_op_classes=");
+               len += wpa_snprintf_hex(buf + len, buflen - len,
+                                       sta->supp_op_classes + 1,
+                                       sta->supp_op_classes[0]);
+               len += os_snprintf(buf + len, buflen - len, "\n");
+       }
+
        return len;
 }
 
@@ -244,7 +259,7 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
        int ret;
        u8 *pos;
 
-       if (hapd->driver->send_frame == NULL)
+       if (!hapd->drv_priv || !hapd->driver->send_frame)
                return -1;
 
        mgmt = os_zalloc(sizeof(*mgmt) + 100);
@@ -255,7 +270,7 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
        wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
                " with minor reason code %u (stype=%u (%s))",
                MAC2STR(addr), minor_reason_code, stype,
-               fc2str(mgmt->frame_control));
+               fc2str(le_to_host16(mgmt->frame_control)));
 
        os_memcpy(mgmt->da, addr, ETH_ALEN);
        os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
@@ -311,7 +326,7 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
        if (pos) {
                struct ieee80211_mgmt mgmt;
                int encrypt;
-               if (hapd->driver->send_frame == NULL)
+               if (!hapd->drv_priv || !hapd->driver->send_frame)
                        return -1;
                pos += 6;
                encrypt = atoi(pos);
@@ -338,7 +353,10 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
        }
 #endif /* CONFIG_P2P_MANAGER */
 
-       hostapd_drv_sta_deauth(hapd, addr, reason);
+       if (os_strstr(txtaddr, " tx=0"))
+               hostapd_drv_sta_remove(hapd, addr);
+       else
+               hostapd_drv_sta_deauth(hapd, addr, reason);
        sta = ap_get_sta(hapd, addr);
        if (sta)
                ap_sta_deauthenticate(hapd, sta, reason);
@@ -371,7 +389,7 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
        if (pos) {
                struct ieee80211_mgmt mgmt;
                int encrypt;
-               if (hapd->driver->send_frame == NULL)
+               if (!hapd->drv_priv || !hapd->driver->send_frame)
                        return -1;
                pos += 6;
                encrypt = atoi(pos);
@@ -398,7 +416,10 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
        }
 #endif /* CONFIG_P2P_MANAGER */
 
-       hostapd_drv_sta_disassoc(hapd, addr, reason);
+       if (os_strstr(txtaddr, " tx=0"))
+               hostapd_drv_sta_remove(hapd, addr);
+       else
+               hostapd_drv_sta_disassoc(hapd, addr, reason);
        sta = ap_get_sta(hapd, addr);
        if (sta)
                ap_sta_disassociate(hapd, sta, reason);
@@ -409,6 +430,49 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
 }
 
 
+#ifdef CONFIG_TAXONOMY
+int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
+                                const char *txtaddr,
+                                char *buf, size_t buflen)
+{
+       u8 addr[ETH_ALEN];
+       struct sta_info *sta;
+
+       wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE SIGNATURE %s", txtaddr);
+
+       if (hwaddr_aton(txtaddr, addr))
+               return -1;
+
+       sta = ap_get_sta(hapd, addr);
+       if (!sta)
+               return -1;
+
+       return retrieve_sta_taxonomy(hapd, sta, buf, buflen);
+}
+#endif /* CONFIG_TAXONOMY */
+
+
+int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
+                               const char *txtaddr)
+{
+       u8 addr[ETH_ALEN];
+       struct sta_info *sta;
+
+       wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE POLL_STA %s", txtaddr);
+
+       if (hwaddr_aton(txtaddr, addr))
+               return -1;
+
+       sta = ap_get_sta(hapd, addr);
+       if (!sta)
+               return -1;
+
+       hostapd_drv_poll_client(hapd, hapd->own_addr, addr,
+                               sta->flags & WLAN_STA_WMM);
+       return 0;
+}
+
+
 int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
                              size_t buflen)
 {
@@ -473,20 +537,28 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
                          "channel=%u\n"
                          "secondary_channel=%d\n"
                          "ieee80211n=%d\n"
-                         "ieee80211ac=%d\n"
-                         "vht_oper_chwidth=%d\n"
-                         "vht_oper_centr_freq_seg0_idx=%d\n"
-                         "vht_oper_centr_freq_seg1_idx=%d\n",
+                         "ieee80211ac=%d\n",
                          iface->conf->channel,
-                         iface->conf->secondary_channel,
-                         iface->conf->ieee80211n,
-                         iface->conf->ieee80211ac,
-                         iface->conf->vht_oper_chwidth,
-                         iface->conf->vht_oper_centr_freq_seg0_idx,
-                         iface->conf->vht_oper_centr_freq_seg1_idx);
+                         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);
        if (os_snprintf_error(buflen - len, ret))
                return len;
        len += ret;
+       if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
+               ret = os_snprintf(buf + len, buflen - len,
+                                 "vht_oper_chwidth=%d\n"
+                                 "vht_oper_centr_freq_seg0_idx=%d\n"
+                                 "vht_oper_centr_freq_seg1_idx=%d\n",
+                                 iface->conf->vht_oper_chwidth,
+                                 iface->conf->vht_oper_centr_freq_seg0_idx,
+                                 iface->conf->vht_oper_centr_freq_seg1_idx);
+               if (os_snprintf_error(buflen - len, ret))
+                       return len;
+               len += ret;
+       }
 
        for (i = 0; i < iface->num_bss; i++) {
                struct hostapd_data *bss = iface->bss[i];
@@ -554,3 +626,16 @@ int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
 {
        return hostapd_drv_stop_ap(hapd);
 }
+
+
+int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
+                                 size_t len)
+{
+       return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
+}
+
+
+void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
+{
+       wpa_auth_pmksa_flush(hapd->wpa_auth);
+}
index e5297d0..4f99680 100644 (file)
@@ -19,10 +19,18 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
                                      const char *txtaddr);
 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
                                    const char *txtaddr);
+int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
+                                const char *txtaddr,
+                                char *buf, size_t buflen);
+int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
+                               const char *txtaddr);
 int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
                              size_t buflen);
 int hostapd_parse_csa_settings(const char *pos,
                               struct csa_settings *settings);
 int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd);
+int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
+                                 size_t len);
+void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd);
 
 #endif /* CTRL_IFACE_AP_H */
index 715f19b..47adba7 100644 (file)
@@ -450,7 +450,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
                return NULL;
 
        if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
-               _rand = os_random();
+               return NULL;
        chan_idx = _rand % num_available_chandefs;
        dfs_find_channel(iface, &chan, chan_idx, skip_radar);
 
@@ -704,7 +704,8 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
                                                        skip_radar);
                        if (!channel) {
                                wpa_printf(MSG_ERROR, "could not get valid channel");
-                               return -1;
+                               hostapd_set_state(iface, HAPD_IFACE_DFS);
+                               return 0;
                        }
 
                        iface->freq = channel->freq;
@@ -793,7 +794,6 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
 
        if (!channel) {
                wpa_printf(MSG_ERROR, "No valid channel available");
-               hostapd_setup_interface_complete(iface, err);
                return err;
        }
 
@@ -817,16 +817,6 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
 }
 
 
-static int hostapd_csa_in_progress(struct hostapd_iface *iface)
-{
-       unsigned int i;
-       for (i = 0; i < iface->num_bss; i++)
-               if (iface->bss[i]->csa_in_progress)
-                       return 1;
-       return 0;
-}
-
-
 static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
 {
        struct hostapd_channel_data *channel;
@@ -868,8 +858,9 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
                                                &vht_oper_centr_freq_seg1_idx,
                                                skip_radar);
                if (!channel) {
-                       /* FIXME: Wait for channel(s) to become available */
-                       hostapd_disable_iface(iface);
+                       wpa_printf(MSG_INFO,
+                                  "%s: no DFS channels left, waiting for NOP to finish",
+                                  __func__);
                        return err;
                }
 
@@ -992,6 +983,11 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
        /* TODO add correct implementation here */
        set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
                      cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
+
+       /* Handle cases where all channels were initially unavailable */
+       if (iface->state == HAPD_IFACE_DFS && !iface->cac_started)
+               hostapd_handle_dfs(iface);
+
        return 0;
 }
 
index 3a77225..f0212fb 100644 (file)
@@ -121,7 +121,8 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
 
                wpa_printf(MSG_DEBUG, "dhcp_snoop: Found DHCPACK for " MACSTR
                           " @ IPv4 address %s/%d",
-                          MAC2STR(sta->addr), ipaddr_str(ntohl(b->your_ip)),
+                          MAC2STR(sta->addr),
+                          ipaddr_str(be_to_host32(b->your_ip)),
                           prefixlen);
 
                if (sta->ipaddr == b->your_ip)
index ca8b75c..3552b3e 100644 (file)
@@ -22,6 +22,7 @@
 #include "wnm_ap.h"
 #include "hostapd.h"
 #include "ieee802_11.h"
+#include "ieee802_11_auth.h"
 #include "sta_info.h"
 #include "accounting.h"
 #include "tkip_countermeasures.h"
@@ -33,6 +34,7 @@
 #include "hw_features.h"
 #include "dfs.h"
 #include "beacon.h"
+#include "mbo_ap.h"
 
 
 int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
@@ -114,6 +116,21 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
        }
        sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
 
+       /*
+        * ACL configurations to the drivers (implementing AP SME and ACL
+        * offload) without hostapd's knowledge, can result in a disconnection
+        * though the driver accepts the connection. Skip the hostapd check for
+        * ACL if the driver supports ACL offload to avoid potentially
+        * conflicting ACL rules.
+        */
+       if (hapd->iface->drv_max_acl_mac_addrs == 0 &&
+           hostapd_check_acl(hapd, addr, NULL) != HOSTAPD_ACL_ACCEPT) {
+               wpa_printf(MSG_INFO, "STA " MACSTR " not allowed to connect",
+                          MAC2STR(addr));
+               reason = WLAN_REASON_UNSPECIFIED;
+               goto fail;
+       }
+
 #ifdef CONFIG_P2P
        if (elems.p2p) {
                wpabuf_free(sta->p2p_ie);
@@ -164,6 +181,11 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
                sta->mb_ies = NULL;
 #endif /* CONFIG_FST */
 
+       mbo_ap_check_sta_assoc(hapd, sta, &elems);
+
+       ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
+                                   elems.supp_op_classes_len);
+
        if (hapd->conf->wpa) {
                if (ie == NULL || ielen == 0) {
 #ifdef CONFIG_WPS
@@ -338,6 +360,17 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
                        return WLAN_STATUS_INVALID_IE;
 #endif /* CONFIG_HS20 */
        }
+
+#ifdef CONFIG_MBO
+       if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
+           elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
+           hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+               wpa_printf(MSG_INFO,
+                          "MBO: Reject WPA2 association without PMF");
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+#endif /* CONFIG_MBO */
+
 #ifdef CONFIG_WPS
 skip_wpa_check:
 #endif /* CONFIG_WPS */
@@ -447,7 +480,8 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
                             int offset, int width, int cf1, int cf2)
 {
 #ifdef NEED_AP_MLME
-       int channel, chwidth, seg0_idx = 0, seg1_idx = 0, is_dfs;
+       int channel, chwidth, is_dfs;
+       u8 seg0_idx = 0, seg1_idx = 0;
 
        hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
                       HOSTAPD_LEVEL_INFO,
@@ -491,8 +525,8 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
                        seg1_idx = (cf2 - 5000) / 5;
                break;
        default:
-               seg0_idx = hostapd_hw_get_channel(hapd, cf1);
-               seg1_idx = hostapd_hw_get_channel(hapd, cf2);
+               ieee80211_freq_to_chan(cf1, &seg0_idx);
+               ieee80211_freq_to_chan(cf2, &seg1_idx);
                break;
        }
 
@@ -539,10 +573,11 @@ void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
 
 
 #ifdef CONFIG_ACS
-static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
-                                        struct acs_selected_channels *acs_res)
+void hostapd_acs_channel_selected(struct hostapd_data *hapd,
+                                 struct acs_selected_channels *acs_res)
 {
        int ret, i;
+       int err = 0;
 
        if (hapd->iconf->channel) {
                wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
@@ -564,7 +599,8 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
                        hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
                                       HOSTAPD_LEVEL_WARNING,
                                       "driver selected to bad hw_mode");
-                       return;
+                       err = 1;
+                       goto out;
                }
        }
 
@@ -574,7 +610,8 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
                hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_WARNING,
                               "driver switched to bad channel");
-               return;
+               err = 1;
+               goto out;
        }
 
        hapd->iconf->channel = acs_res->pri_channel;
@@ -588,7 +625,8 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
                hapd->iconf->secondary_channel = 1;
        else {
                wpa_printf(MSG_ERROR, "Invalid secondary channel!");
-               return;
+               err = 1;
+               goto out;
        }
 
        if (hapd->iface->conf->ieee80211ac) {
@@ -617,7 +655,8 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
                }
        }
 
-       ret = hostapd_acs_completed(hapd->iface, 0);
+out:
+       ret = hostapd_acs_completed(hapd->iface, err);
        if (ret) {
                wpa_printf(MSG_ERROR,
                           "ACS: Possibly channel configuration is invalid");
@@ -884,11 +923,24 @@ static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
                               size_t len, u16 stype, int ok)
 {
        struct ieee80211_hdr *hdr;
+       struct hostapd_data *orig_hapd = hapd;
 
        hdr = (struct ieee80211_hdr *) buf;
        hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
-       if (hapd == NULL || hapd == HAPD_BROADCAST)
+       if (!hapd)
                return;
+       if (hapd == HAPD_BROADCAST) {
+               if (stype != WLAN_FC_STYPE_ACTION || len <= 25 ||
+                   buf[24] != WLAN_ACTION_PUBLIC)
+                       return;
+               hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2);
+               if (!hapd || hapd == HAPD_BROADCAST)
+                       return;
+               /*
+                * Allow processing of TX status for a Public Action frame that
+                * used wildcard BBSID.
+                */
+       }
        ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
 }
 
@@ -935,6 +987,8 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
        ieee802_1x_receive(hapd, src, data, data_len);
 }
 
+#endif /* HOSTAPD */
+
 
 static struct hostapd_channel_data * hostapd_get_mode_channel(
        struct hostapd_iface *iface, unsigned int freq)
@@ -944,8 +998,6 @@ static struct hostapd_channel_data * hostapd_get_mode_channel(
 
        for (i = 0; i < iface->current_mode->num_channels; i++) {
                chan = &iface->current_mode->channels[i];
-               if (!chan)
-                       return NULL;
                if ((unsigned int) chan->freq == freq)
                        return chan;
        }
@@ -1009,10 +1061,9 @@ static void hostapd_single_channel_get_survey(struct hostapd_iface *iface,
 }
 
 
-static void hostapd_event_get_survey(struct hostapd_data *hapd,
-                                    struct survey_results *survey_results)
+void hostapd_event_get_survey(struct hostapd_iface *iface,
+                             struct survey_results *survey_results)
 {
-       struct hostapd_iface *iface = hapd->iface;
        struct freq_survey *survey, *tmp;
        struct hostapd_channel_data *chan;
 
@@ -1044,6 +1095,7 @@ static void hostapd_event_get_survey(struct hostapd_data *hapd,
 }
 
 
+#ifdef HOSTAPD
 #ifdef NEED_AP_MLME
 
 static void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
@@ -1251,7 +1303,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                        data->connect_failed_reason.code);
                break;
        case EVENT_SURVEY:
-               hostapd_event_get_survey(hapd, &data->survey_results);
+               hostapd_event_get_survey(hapd->iface, &data->survey_results);
                break;
 #ifdef NEED_AP_MLME
        case EVENT_INTERFACE_UNAVAILABLE:
@@ -1321,4 +1373,31 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
        }
 }
 
+
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+                                union wpa_event_data *data)
+{
+       struct hapd_interfaces *interfaces = ctx;
+       struct hostapd_data *hapd;
+
+       if (event != EVENT_INTERFACE_STATUS)
+               return;
+
+       hapd = hostapd_get_iface(interfaces, data->interface_status.ifname);
+       if (hapd && hapd->driver && hapd->driver->get_ifindex &&
+           hapd->drv_priv) {
+               unsigned int ifindex;
+
+               ifindex = hapd->driver->get_ifindex(hapd->drv_priv);
+               if (ifindex != data->interface_status.ifindex) {
+                       wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+                               "interface status ifindex %d mismatch (%d)",
+                               ifindex, data->interface_status.ifindex);
+                       return;
+               }
+       }
+       if (hapd)
+               wpa_supplicant_event(hapd, event, data);
+}
+
 #endif /* HOSTAPD */
index 9d19f98..6ce178d 100644 (file)
@@ -101,6 +101,7 @@ gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
                if (sta->gas_dialog[i].dialog_token != dialog_token ||
                    !sta->gas_dialog[i].valid)
                        continue;
+               ap_sta_replenish_timeout(hapd, sta, 5);
                return &sta->gas_dialog[i];
        }
        wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for "
@@ -167,27 +168,107 @@ static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
 #endif /* CONFIG_HS20 */
 
 
+static struct anqp_element * get_anqp_elem(struct hostapd_data *hapd,
+                                          u16 infoid)
+{
+       struct anqp_element *elem;
+
+       dl_list_for_each(elem, &hapd->conf->anqp_elem, struct anqp_element,
+                        list) {
+               if (elem->infoid == infoid)
+                       return elem;
+       }
+
+       return NULL;
+}
+
+
+static void anqp_add_elem(struct hostapd_data *hapd, struct wpabuf *buf,
+                         u16 infoid)
+{
+       struct anqp_element *elem;
+
+       elem = get_anqp_elem(hapd, infoid);
+       if (!elem)
+               return;
+       if (wpabuf_tailroom(buf) < 2 + 2 + wpabuf_len(elem->payload)) {
+               wpa_printf(MSG_DEBUG, "ANQP: No room for InfoID %u payload",
+                          infoid);
+               return;
+       }
+
+       wpabuf_put_le16(buf, infoid);
+       wpabuf_put_le16(buf, wpabuf_len(elem->payload));
+       wpabuf_put_buf(buf, elem->payload);
+}
+
+
+static int anqp_add_override(struct hostapd_data *hapd, struct wpabuf *buf,
+                            u16 infoid)
+{
+       if (get_anqp_elem(hapd, infoid)) {
+               anqp_add_elem(hapd, buf, infoid);
+               return 1;
+       }
+
+       return 0;
+}
+
+
 static void anqp_add_capab_list(struct hostapd_data *hapd,
                                struct wpabuf *buf)
 {
        u8 *len;
+       u16 id;
+
+       if (anqp_add_override(hapd, buf, ANQP_CAPABILITY_LIST))
+               return;
 
        len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST);
        wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
-       if (hapd->conf->venue_name)
+       if (hapd->conf->venue_name || get_anqp_elem(hapd, ANQP_VENUE_NAME))
                wpabuf_put_le16(buf, ANQP_VENUE_NAME);
-       if (hapd->conf->network_auth_type)
+       if (get_anqp_elem(hapd, ANQP_EMERGENCY_CALL_NUMBER))
+               wpabuf_put_le16(buf, ANQP_EMERGENCY_CALL_NUMBER);
+       if (hapd->conf->network_auth_type ||
+           get_anqp_elem(hapd, ANQP_NETWORK_AUTH_TYPE))
                wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
-       if (hapd->conf->roaming_consortium)
+       if (hapd->conf->roaming_consortium ||
+           get_anqp_elem(hapd, ANQP_ROAMING_CONSORTIUM))
                wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
-       if (hapd->conf->ipaddr_type_configured)
+       if (hapd->conf->ipaddr_type_configured ||
+           get_anqp_elem(hapd, ANQP_IP_ADDR_TYPE_AVAILABILITY))
                wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
-       if (hapd->conf->nai_realm_data)
+       if (hapd->conf->nai_realm_data ||
+           get_anqp_elem(hapd, ANQP_NAI_REALM))
                wpabuf_put_le16(buf, ANQP_NAI_REALM);
-       if (hapd->conf->anqp_3gpp_cell_net)
+       if (hapd->conf->anqp_3gpp_cell_net ||
+           get_anqp_elem(hapd, ANQP_3GPP_CELLULAR_NETWORK))
                wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
-       if (hapd->conf->domain_name)
+       if (get_anqp_elem(hapd, ANQP_AP_GEOSPATIAL_LOCATION))
+               wpabuf_put_le16(buf, ANQP_AP_GEOSPATIAL_LOCATION);
+       if (get_anqp_elem(hapd, ANQP_AP_CIVIC_LOCATION))
+               wpabuf_put_le16(buf, ANQP_AP_CIVIC_LOCATION);
+       if (get_anqp_elem(hapd, ANQP_AP_LOCATION_PUBLIC_URI))
+               wpabuf_put_le16(buf, ANQP_AP_LOCATION_PUBLIC_URI);
+       if (hapd->conf->domain_name || get_anqp_elem(hapd, ANQP_DOMAIN_NAME))
                wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
+       if (get_anqp_elem(hapd, ANQP_EMERGENCY_ALERT_URI))
+               wpabuf_put_le16(buf, ANQP_EMERGENCY_ALERT_URI);
+       if (get_anqp_elem(hapd, ANQP_EMERGENCY_NAI))
+               wpabuf_put_le16(buf, ANQP_EMERGENCY_NAI);
+       if (get_anqp_elem(hapd, ANQP_NEIGHBOR_REPORT))
+               wpabuf_put_le16(buf, ANQP_NEIGHBOR_REPORT);
+       for (id = 273; id < 277; id++) {
+               if (get_anqp_elem(hapd, id))
+                       wpabuf_put_le16(buf, id);
+       }
+       if (get_anqp_elem(hapd, ANQP_VENUE_URL))
+               wpabuf_put_le16(buf, ANQP_VENUE_URL);
+       if (get_anqp_elem(hapd, ANQP_ADVICE_OF_CHARGE))
+               wpabuf_put_le16(buf, ANQP_ADVICE_OF_CHARGE);
+       if (get_anqp_elem(hapd, ANQP_LOCAL_CONTENT))
+               wpabuf_put_le16(buf, ANQP_LOCAL_CONTENT);
 #ifdef CONFIG_HS20
        anqp_add_hs_capab_list(hapd, buf);
 #endif /* CONFIG_HS20 */
@@ -197,6 +278,9 @@ static void anqp_add_capab_list(struct hostapd_data *hapd,
 
 static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
 {
+       if (anqp_add_override(hapd, buf, ANQP_VENUE_NAME))
+               return;
+
        if (hapd->conf->venue_name) {
                u8 *len;
                unsigned int i;
@@ -218,6 +302,9 @@ static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
 static void anqp_add_network_auth_type(struct hostapd_data *hapd,
                                       struct wpabuf *buf)
 {
+       if (anqp_add_override(hapd, buf, ANQP_NETWORK_AUTH_TYPE))
+               return;
+
        if (hapd->conf->network_auth_type) {
                wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
                wpabuf_put_le16(buf, hapd->conf->network_auth_type_len);
@@ -233,6 +320,9 @@ static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
        unsigned int i;
        u8 *len;
 
+       if (anqp_add_override(hapd, buf, ANQP_ROAMING_CONSORTIUM))
+               return;
+
        len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM);
        for (i = 0; i < hapd->conf->roaming_consortium_count; i++) {
                struct hostapd_roaming_consortium *rc;
@@ -247,6 +337,9 @@ static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
 static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd,
                                               struct wpabuf *buf)
 {
+       if (anqp_add_override(hapd, buf, ANQP_IP_ADDR_TYPE_AVAILABILITY))
+               return;
+
        if (hapd->conf->ipaddr_type_configured) {
                wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
                wpabuf_put_le16(buf, 1);
@@ -309,7 +402,7 @@ static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
 
        pos = home_realm;
        end = pos + home_realm_len;
-       if (pos + 1 > end) {
+       if (end - pos < 1) {
                wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query",
                            home_realm, home_realm_len);
                return -1;
@@ -317,7 +410,7 @@ static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
        num_realms = *pos++;
 
        for (i = 0; i < num_realms && num_matching < 10; i++) {
-               if (pos + 2 > end) {
+               if (end - pos < 2) {
                        wpa_hexdump(MSG_DEBUG,
                                    "Truncated NAI Home Realm Query",
                                    home_realm, home_realm_len);
@@ -325,7 +418,7 @@ static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
                }
                encoding = *pos++;
                realm_len = *pos++;
-               if (pos + realm_len > end) {
+               if (realm_len > end - pos) {
                        wpa_hexdump(MSG_DEBUG,
                                    "Truncated NAI Home Realm Query",
                                    home_realm, home_realm_len);
@@ -391,6 +484,10 @@ static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
                               const u8 *home_realm, size_t home_realm_len,
                               int nai_realm, int nai_home_realm)
 {
+       if (nai_realm && !nai_home_realm &&
+           anqp_add_override(hapd, buf, ANQP_NAI_REALM))
+               return;
+
        if (nai_realm && hapd->conf->nai_realm_data) {
                u8 *len;
                unsigned int i, j;
@@ -424,6 +521,9 @@ static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
 static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
                                           struct wpabuf *buf)
 {
+       if (anqp_add_override(hapd, buf, ANQP_3GPP_CELLULAR_NETWORK))
+               return;
+
        if (hapd->conf->anqp_3gpp_cell_net) {
                wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
                wpabuf_put_le16(buf,
@@ -436,6 +536,9 @@ static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
 
 static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
 {
+       if (anqp_add_override(hapd, buf, ANQP_DOMAIN_NAME))
+               return;
+
        if (hapd->conf->domain_name) {
                wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
                wpabuf_put_le16(buf, hapd->conf->domain_name_len);
@@ -683,20 +786,42 @@ static void anqp_add_icon_binary_file(struct hostapd_data *hapd,
 #endif /* CONFIG_HS20 */
 
 
+static size_t anqp_get_required_len(struct hostapd_data *hapd,
+                                   const u16 *infoid,
+                                   unsigned int num_infoid)
+{
+       size_t len = 0;
+       unsigned int i;
+
+       for (i = 0; i < num_infoid; i++) {
+               struct anqp_element *elem = get_anqp_elem(hapd, infoid[i]);
+
+               if (elem)
+                       len += 2 + 2 + wpabuf_len(elem->payload);
+       }
+
+       return len;
+}
+
+
 static struct wpabuf *
 gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
                                unsigned int request,
                                const u8 *home_realm, size_t home_realm_len,
-                               const u8 *icon_name, size_t icon_name_len)
+                               const u8 *icon_name, size_t icon_name_len,
+                               const u16 *extra_req,
+                               unsigned int num_extra_req)
 {
        struct wpabuf *buf;
        size_t len;
+       unsigned int i;
 
        len = 1400;
        if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
                len += 1000;
        if (request & ANQP_REQ_ICON_REQUEST)
                len += 65536;
+       len += anqp_get_required_len(hapd, extra_req, num_extra_req);
 
        buf = wpabuf_alloc(len);
        if (buf == NULL)
@@ -706,6 +831,8 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
                anqp_add_capab_list(hapd, buf);
        if (request & ANQP_REQ_VENUE_NAME)
                anqp_add_venue_name(hapd, buf);
+       if (request & ANQP_REQ_EMERGENCY_CALL_NUMBER)
+               anqp_add_elem(hapd, buf, ANQP_EMERGENCY_CALL_NUMBER);
        if (request & ANQP_REQ_NETWORK_AUTH_TYPE)
                anqp_add_network_auth_type(hapd, buf);
        if (request & ANQP_REQ_ROAMING_CONSORTIUM)
@@ -718,8 +845,23 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
                                   request & ANQP_REQ_NAI_HOME_REALM);
        if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK)
                anqp_add_3gpp_cellular_network(hapd, buf);
+       if (request & ANQP_REQ_AP_GEOSPATIAL_LOCATION)
+               anqp_add_elem(hapd, buf, ANQP_AP_GEOSPATIAL_LOCATION);
+       if (request & ANQP_REQ_AP_CIVIC_LOCATION)
+               anqp_add_elem(hapd, buf, ANQP_AP_CIVIC_LOCATION);
+       if (request & ANQP_REQ_AP_LOCATION_PUBLIC_URI)
+               anqp_add_elem(hapd, buf, ANQP_AP_LOCATION_PUBLIC_URI);
        if (request & ANQP_REQ_DOMAIN_NAME)
                anqp_add_domain_name(hapd, buf);
+       if (request & ANQP_REQ_EMERGENCY_ALERT_URI)
+               anqp_add_elem(hapd, buf, ANQP_EMERGENCY_ALERT_URI);
+       if (request & ANQP_REQ_TDLS_CAPABILITY)
+               anqp_add_elem(hapd, buf, ANQP_TDLS_CAPABILITY);
+       if (request & ANQP_REQ_EMERGENCY_NAI)
+               anqp_add_elem(hapd, buf, ANQP_EMERGENCY_NAI);
+
+       for (i = 0; i < num_extra_req; i++)
+               anqp_add_elem(hapd, buf, extra_req[i]);
 
 #ifdef CONFIG_HS20
        if (request & ANQP_REQ_HS_CAPABILITY_LIST)
@@ -742,6 +884,8 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
 }
 
 
+#define ANQP_MAX_EXTRA_REQ 20
+
 struct anqp_query_info {
        unsigned int request;
        const u8 *home_realm_query;
@@ -749,6 +893,8 @@ struct anqp_query_info {
        const u8 *icon_name;
        size_t icon_name_len;
        int p2p_sd;
+       u16 extra_req[ANQP_MAX_EXTRA_REQ];
+       unsigned int num_extra_req;
 };
 
 
@@ -776,6 +922,11 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
                set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
                             hapd->conf->venue_name != NULL, qi);
                break;
+       case ANQP_EMERGENCY_CALL_NUMBER:
+               set_anqp_req(ANQP_REQ_EMERGENCY_CALL_NUMBER,
+                            "Emergency Call Number",
+                            get_anqp_elem(hapd, info_id) != NULL, qi);
+               break;
        case ANQP_NETWORK_AUTH_TYPE:
                set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
                             hapd->conf->network_auth_type != NULL, qi);
@@ -798,13 +949,55 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
                             "3GPP Cellular Network",
                             hapd->conf->anqp_3gpp_cell_net != NULL, qi);
                break;
+       case ANQP_AP_GEOSPATIAL_LOCATION:
+               set_anqp_req(ANQP_REQ_AP_GEOSPATIAL_LOCATION,
+                            "AP Geospatial Location",
+                            get_anqp_elem(hapd, info_id) != NULL, qi);
+               break;
+       case ANQP_AP_CIVIC_LOCATION:
+               set_anqp_req(ANQP_REQ_AP_CIVIC_LOCATION,
+                            "AP Civic Location",
+                            get_anqp_elem(hapd, info_id) != NULL, qi);
+               break;
+       case ANQP_AP_LOCATION_PUBLIC_URI:
+               set_anqp_req(ANQP_REQ_AP_LOCATION_PUBLIC_URI,
+                            "AP Location Public URI",
+                            get_anqp_elem(hapd, info_id) != NULL, qi);
+               break;
        case ANQP_DOMAIN_NAME:
                set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
                             hapd->conf->domain_name != NULL, qi);
                break;
+       case ANQP_EMERGENCY_ALERT_URI:
+               set_anqp_req(ANQP_REQ_EMERGENCY_ALERT_URI,
+                            "Emergency Alert URI",
+                            get_anqp_elem(hapd, info_id) != NULL, qi);
+               break;
+       case ANQP_TDLS_CAPABILITY:
+               set_anqp_req(ANQP_REQ_TDLS_CAPABILITY,
+                            "TDLS Capability",
+                            get_anqp_elem(hapd, info_id) != NULL, qi);
+               break;
+       case ANQP_EMERGENCY_NAI:
+               set_anqp_req(ANQP_REQ_EMERGENCY_NAI,
+                            "Emergency NAI",
+                            get_anqp_elem(hapd, info_id) != NULL, qi);
+               break;
        default:
-               wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
-                          info_id);
+               if (!get_anqp_elem(hapd, info_id)) {
+                       wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
+                                  info_id);
+                       break;
+               }
+               if (qi->num_extra_req == ANQP_MAX_EXTRA_REQ) {
+                       wpa_printf(MSG_DEBUG,
+                                  "ANQP: No more room for extra requests - ignore Info Id %u",
+                                  info_id);
+                       break;
+               }
+               wpa_printf(MSG_DEBUG, "ANQP: Info Id %u (local)", info_id);
+               qi->extra_req[qi->num_extra_req] = info_id;
+               qi->num_extra_req++;
                break;
        }
 }
@@ -817,7 +1010,7 @@ static void rx_anqp_query_list(struct hostapd_data *hapd,
        wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list",
                   (unsigned int) (end - pos) / 2);
 
-       while (pos + 2 <= end) {
+       while (end - pos >= 2) {
                rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi);
                pos += 2;
        }
@@ -906,7 +1099,7 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
        u32 oui;
        u8 subtype;
 
-       if (pos + 4 > end) {
+       if (end - pos < 4) {
                wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
                           "Query element");
                return;
@@ -942,7 +1135,7 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
        }
        pos++;
 
-       if (pos + 1 >= end)
+       if (end - pos <= 1)
                return;
 
        subtype = *pos++;
@@ -973,14 +1166,16 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
 
 static void gas_serv_req_local_processing(struct hostapd_data *hapd,
                                          const u8 *sa, u8 dialog_token,
-                                         struct anqp_query_info *qi, int prot)
+                                         struct anqp_query_info *qi, int prot,
+                                         int std_addr3)
 {
        struct wpabuf *buf, *tx_buf;
 
        buf = gas_serv_build_gas_resp_payload(hapd, qi->request,
                                              qi->home_realm_query,
                                              qi->home_realm_query_len,
-                                             qi->icon_name, qi->icon_name_len);
+                                             qi->icon_name, qi->icon_name_len,
+                                             qi->extra_req, qi->num_extra_req);
        wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
                        buf);
        if (!buf)
@@ -1033,15 +1228,22 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
                return;
        if (prot)
                convert_to_protected_dual(tx_buf);
-       hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
-                               wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+       if (std_addr3)
+               hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+                                       wpabuf_head(tx_buf),
+                                       wpabuf_len(tx_buf));
+       else
+               hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
+                                                wpabuf_head(tx_buf),
+                                                wpabuf_len(tx_buf));
        wpabuf_free(tx_buf);
 }
 
 
 static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
                                        const u8 *sa,
-                                       const u8 *data, size_t len, int prot)
+                                       const u8 *data, size_t len, int prot,
+                                       int std_addr3)
 {
        const u8 *pos = data;
        const u8 *end = data + len;
@@ -1069,12 +1271,12 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
        adv_proto = pos++;
 
        slen = *pos++;
-       next = pos + slen;
-       if (next > end || slen < 2) {
+       if (slen > end - pos || slen < 2) {
                wpa_msg(hapd->msg_ctx, MSG_DEBUG,
                        "GAS: Invalid IE in GAS Initial Request");
                return;
        }
+       next = pos + slen;
        pos++; /* skip QueryRespLenLimit and PAME-BI */
 
        if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
@@ -1093,19 +1295,26 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
                wpabuf_put_le16(buf, 0); /* Query Response Length */
                if (prot)
                        convert_to_protected_dual(buf);
-               hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
-                                       wpabuf_head(buf), wpabuf_len(buf));
+               if (std_addr3)
+                       hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+                                               wpabuf_head(buf),
+                                               wpabuf_len(buf));
+               else
+                       hostapd_drv_send_action_addr3_ap(hapd,
+                                                        hapd->iface->freq, 0,
+                                                        sa, wpabuf_head(buf),
+                                                        wpabuf_len(buf));
                wpabuf_free(buf);
                return;
        }
 
        pos = next;
        /* Query Request */
-       if (pos + 2 > end)
+       if (end - pos < 2)
                return;
        slen = WPA_GET_LE16(pos);
        pos += 2;
-       if (pos + slen > end)
+       if (slen > end - pos)
                return;
        end = pos + slen;
 
@@ -1113,7 +1322,7 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
        while (pos < end) {
                u16 info_id, elen;
 
-               if (pos + 4 > end)
+               if (end - pos < 4)
                        return;
 
                info_id = WPA_GET_LE16(pos);
@@ -1121,7 +1330,7 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
                elen = WPA_GET_LE16(pos);
                pos += 2;
 
-               if (pos + elen > end) {
+               if (elen > end - pos) {
                        wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
                        return;
                }
@@ -1144,13 +1353,15 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
                pos += elen;
        }
 
-       gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot);
+       gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot,
+                                     std_addr3);
 }
 
 
 static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
                                         const u8 *sa,
-                                        const u8 *data, size_t len, int prot)
+                                        const u8 *data, size_t len, int prot,
+                                        int std_addr3)
 {
        struct gas_dialog_info *dialog;
        struct wpabuf *buf, *tx_buf;
@@ -1226,8 +1437,14 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
 send_resp:
        if (prot)
                convert_to_protected_dual(tx_buf);
-       hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
-                               wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+       if (std_addr3)
+               hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+                                       wpabuf_head(tx_buf),
+                                       wpabuf_len(tx_buf));
+       else
+               hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
+                                                wpabuf_head(tx_buf),
+                                                wpabuf_len(tx_buf));
        wpabuf_free(tx_buf);
 }
 
@@ -1238,7 +1455,7 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
        struct hostapd_data *hapd = ctx;
        const struct ieee80211_mgmt *mgmt;
        const u8 *sa, *data;
-       int prot;
+       int prot, std_addr3;
 
        mgmt = (const struct ieee80211_mgmt *) buf;
        if (len < IEEE80211_HDRLEN + 2)
@@ -1253,14 +1470,22 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
         */
        prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL;
        sa = mgmt->sa;
+       if (hapd->conf->gas_address3 == 1)
+               std_addr3 = 1;
+       else if (hapd->conf->gas_address3 == 2)
+               std_addr3 = 0;
+       else
+               std_addr3 = is_broadcast_ether_addr(mgmt->bssid);
        len -= IEEE80211_HDRLEN + 1;
        data = buf + IEEE80211_HDRLEN + 1;
        switch (data[0]) {
        case WLAN_PA_GAS_INITIAL_REQ:
-               gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot);
+               gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot,
+                                           std_addr3);
                break;
        case WLAN_PA_GAS_COMEBACK_REQ:
-               gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot);
+               gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot,
+                                            std_addr3);
                break;
        }
 }
index 4ec3201..9051e4f 100644 (file)
@@ -9,10 +9,13 @@
 #ifndef GAS_SERV_H
 #define GAS_SERV_H
 
+/* First 16 ANQP InfoIDs can be included in the optimized bitmap */
 #define ANQP_REQ_CAPABILITY_LIST \
        (1 << (ANQP_CAPABILITY_LIST - ANQP_QUERY_LIST))
 #define ANQP_REQ_VENUE_NAME \
        (1 << (ANQP_VENUE_NAME - ANQP_QUERY_LIST))
+#define ANQP_REQ_EMERGENCY_CALL_NUMBER \
+       (1 << (ANQP_EMERGENCY_CALL_NUMBER - ANQP_QUERY_LIST))
 #define ANQP_REQ_NETWORK_AUTH_TYPE \
        (1 << (ANQP_NETWORK_AUTH_TYPE - ANQP_QUERY_LIST))
 #define ANQP_REQ_ROAMING_CONSORTIUM \
        (1 << (ANQP_NAI_REALM - ANQP_QUERY_LIST))
 #define ANQP_REQ_3GPP_CELLULAR_NETWORK \
        (1 << (ANQP_3GPP_CELLULAR_NETWORK - ANQP_QUERY_LIST))
+#define ANQP_REQ_AP_GEOSPATIAL_LOCATION \
+       (1 << (ANQP_AP_GEOSPATIAL_LOCATION - ANQP_QUERY_LIST))
+#define ANQP_REQ_AP_CIVIC_LOCATION \
+       (1 << (ANQP_AP_CIVIC_LOCATION - ANQP_QUERY_LIST))
+#define ANQP_REQ_AP_LOCATION_PUBLIC_URI \
+       (1 << (ANQP_AP_LOCATION_PUBLIC_URI - ANQP_QUERY_LIST))
 #define ANQP_REQ_DOMAIN_NAME \
        (1 << (ANQP_DOMAIN_NAME - ANQP_QUERY_LIST))
+#define ANQP_REQ_EMERGENCY_ALERT_URI \
+       (1 << (ANQP_EMERGENCY_ALERT_URI - ANQP_QUERY_LIST))
+#define ANQP_REQ_TDLS_CAPABILITY \
+       (1 << (ANQP_TDLS_CAPABILITY - ANQP_QUERY_LIST))
+#define ANQP_REQ_EMERGENCY_NAI \
+       (1 << (ANQP_EMERGENCY_NAI - ANQP_QUERY_LIST))
+/*
+ * First 16 Hotspot 2.0 vendor specific ANQP-elements can be included in the
+ * optimized bitmap.
+ */
 #define ANQP_REQ_HS_CAPABILITY_LIST \
        (0x10000 << HS20_STYPE_CAPABILITY_LIST)
 #define ANQP_REQ_OPERATOR_FRIENDLY_NAME \
index c09c17a..9fafc7f 100644 (file)
@@ -12,6 +12,7 @@
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "common/wpa_ctrl.h"
+#include "common/hw_features_common.h"
 #include "radius/radius_client.h"
 #include "radius/radius_das.h"
 #include "eap_server/tncs.h"
@@ -42,6 +43,8 @@
 #include "x_snoop.h"
 #include "dhcp_snoop.h"
 #include "ndisc_snoop.h"
+#include "neighbor_db.h"
+#include "rrm.h"
 
 
 static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
@@ -203,10 +206,12 @@ int hostapd_reload_config(struct hostapd_iface *iface)
 
 
 static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
-                                             char *ifname)
+                                             const char *ifname)
 {
        int i;
 
+       if (!ifname)
+               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)) {
@@ -334,6 +339,8 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
        wpabuf_free(hapd->mesh_pending_auth);
        hapd->mesh_pending_auth = NULL;
 #endif /* CONFIG_MESH */
+
+       hostapd_clean_rrm(hapd);
 }
 
 
@@ -367,7 +374,7 @@ static void sta_track_deinit(struct hostapd_iface *iface)
                                     list))) {
                dl_list_del(&info->list);
                iface->num_sta_seen--;
-               os_free(info);
+               sta_track_del(info);
        }
 }
 
@@ -511,6 +518,9 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
        if (hostapd_drv_none(hapd))
                return 0;
 
+       if (iface->conf->use_driver_iface_addr)
+               return 0;
+
        /* Generate BSSID mask that is large enough to cover the BSSIDs. */
 
        /* Determine the bits necessary to cover the number of BSSIDs. */
@@ -520,7 +530,7 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
        /* Determine the bits necessary to any configured BSSIDs,
           if they are higher than the number of BSSIDs. */
        for (j = 0; j < iface->conf->num_bss; j++) {
-               if (hostapd_mac_comp_empty(iface->conf->bss[j]->bssid) == 0) {
+               if (is_zero_ether_addr(iface->conf->bss[j]->bssid)) {
                        if (j)
                                auto_addr++;
                        continue;
@@ -672,7 +682,7 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
 
        if (attr->acct_session_id) {
                num_attr++;
-               if (attr->acct_session_id_len != 17) {
+               if (attr->acct_session_id_len != 16) {
                        wpa_printf(MSG_DEBUG,
                                   "RADIUS DAS: Acct-Session-Id cannot match");
                        return NULL;
@@ -682,10 +692,9 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
                for (sta = hapd->sta_list; sta; sta = sta->next) {
                        if (!sta->radius_das_match)
                                continue;
-                       os_snprintf(buf, sizeof(buf), "%08X-%08X",
-                                   sta->acct_session_id_hi,
-                                   sta->acct_session_id_lo);
-                       if (os_memcmp(attr->acct_session_id, buf, 17) != 0)
+                       os_snprintf(buf, sizeof(buf), "%016llX",
+                                   (unsigned long long) sta->acct_session_id);
+                       if (os_memcmp(attr->acct_session_id, buf, 16) != 0)
                                sta->radius_das_match = 0;
                        else
                                count++;
@@ -701,7 +710,7 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
 
        if (attr->acct_multi_session_id) {
                num_attr++;
-               if (attr->acct_multi_session_id_len != 17) {
+               if (attr->acct_multi_session_id_len != 16) {
                        wpa_printf(MSG_DEBUG,
                                   "RADIUS DAS: Acct-Multi-Session-Id cannot match");
                        return NULL;
@@ -712,14 +721,14 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
                        if (!sta->radius_das_match)
                                continue;
                        if (!sta->eapol_sm ||
-                           !sta->eapol_sm->acct_multi_session_id_hi) {
+                           !sta->eapol_sm->acct_multi_session_id) {
                                sta->radius_das_match = 0;
                                continue;
                        }
-                       os_snprintf(buf, sizeof(buf), "%08X+%08X",
-                                   sta->eapol_sm->acct_multi_session_id_hi,
-                                   sta->eapol_sm->acct_multi_session_id_lo);
-                       if (os_memcmp(attr->acct_multi_session_id, buf, 17) !=
+                       os_snprintf(buf, sizeof(buf), "%016llX",
+                                   (unsigned long long)
+                                   sta->eapol_sm->acct_multi_session_id);
+                       if (os_memcmp(attr->acct_multi_session_id, buf, 16) !=
                            0)
                                sta->radius_das_match = 0;
                        else
@@ -905,12 +914,9 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
        hapd->started = 1;
 
        if (!first || first == -1) {
-               if (hostapd_mac_comp_empty(conf->bssid) == 0) {
-                       /* Allocate the next available BSSID. */
-                       do {
-                               inc_byte_array(hapd->own_addr, ETH_ALEN);
-                       } while (mac_in_conf(hapd->iconf, hapd->own_addr));
-               } else {
+               u8 *addr = hapd->own_addr;
+
+               if (!is_zero_ether_addr(conf->bssid)) {
                        /* Allocate the configured BSSID. */
                        os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN);
 
@@ -922,11 +928,18 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
                                           "the radio", conf->iface);
                                return -1;
                        }
+               } else if (hapd->iconf->use_driver_iface_addr) {
+                       addr = NULL;
+               } else {
+                       /* Allocate the next available BSSID. */
+                       do {
+                               inc_byte_array(hapd->own_addr, ETH_ALEN);
+                       } while (mac_in_conf(hapd->iconf, hapd->own_addr));
                }
 
                hapd->interface_added = 1;
                if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
-                                  conf->iface, hapd->own_addr, hapd,
+                                  conf->iface, addr, hapd,
                                   &hapd->drv_priv, force_ifname, if_addr,
                                   conf->bridge[0] ? conf->bridge : NULL,
                                   first == -1)) {
@@ -935,11 +948,19 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
                        hapd->interface_added = 0;
                        return -1;
                }
+
+               if (!addr)
+                       os_memcpy(hapd->own_addr, if_addr, ETH_ALEN);
        }
 
        if (conf->wmm_enabled < 0)
                conf->wmm_enabled = hapd->iconf->ieee80211n;
 
+#ifdef CONFIG_IEEE80211R
+       if (is_zero_ether_addr(conf->r1_key_holder))
+               os_memcpy(conf->r1_key_holder, hapd->own_addr, ETH_ALEN);
+#endif /* CONFIG_IEEE80211R */
+
 #ifdef CONFIG_MESH
        if (hapd->iface->mconf == NULL)
                flush_old_stations = 0;
@@ -1022,6 +1043,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
                das_conf.time_window = conf->radius_das_time_window;
                das_conf.require_event_timestamp =
                        conf->radius_das_require_event_timestamp;
+               das_conf.require_message_authenticator =
+                       conf->radius_das_require_message_authenticator;
                das_conf.ctx = hapd;
                das_conf.disconnect = hostapd_das_disconnect;
                hapd->radius_das = radius_das_init(&das_conf);
@@ -1509,15 +1532,128 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
 #endif /* CONFIG_FST */
 
 
-/**
- * hostapd_setup_interface_complete - Complete interface setup
- *
- * This function is called when previous steps in the interface setup has been
- * completed. This can also start operations, e.g., DFS, that will require
- * additional processing before interface is ready to be enabled. Such
- * operations will call this function from eloop callbacks when finished.
- */
-int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
+#ifdef NEED_AP_MLME
+static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
+                                                   int ht, int vht)
+{
+       if (!ht && !vht)
+               return NR_CHAN_WIDTH_20;
+       if (!hapd->iconf->secondary_channel)
+               return NR_CHAN_WIDTH_20;
+       if (!vht || hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT)
+               return NR_CHAN_WIDTH_40;
+       if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
+               return NR_CHAN_WIDTH_80;
+       if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ)
+               return NR_CHAN_WIDTH_160;
+       if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ)
+               return NR_CHAN_WIDTH_80P80;
+       return NR_CHAN_WIDTH_20;
+}
+#endif /* NEED_AP_MLME */
+
+
+static void hostapd_set_own_neighbor_report(struct hostapd_data *hapd)
+{
+#ifdef NEED_AP_MLME
+       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;
+       struct wpa_ssid_value ssid;
+       u8 channel, op_class;
+       int center_freq1 = 0, center_freq2 = 0;
+       enum nr_chan_width width;
+       u32 bssid_info;
+       struct wpabuf *nr;
+
+       if (!(hapd->conf->radio_measurements[0] &
+             WLAN_RRM_CAPS_NEIGHBOR_REPORT))
+               return;
+
+       bssid_info = 3; /* AP is reachable */
+       bssid_info |= NEI_REP_BSSID_INFO_SECURITY; /* "same as the AP" */
+       bssid_info |= NEI_REP_BSSID_INFO_KEY_SCOPE; /* "same as the AP" */
+
+       if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT)
+               bssid_info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
+
+       bssid_info |= NEI_REP_BSSID_INFO_RM; /* RRM is supported */
+
+       if (hapd->conf->wmm_enabled) {
+               bssid_info |= NEI_REP_BSSID_INFO_QOS;
+
+               if (hapd->conf->wmm_uapsd &&
+                   (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
+                       bssid_info |= NEI_REP_BSSID_INFO_APSD;
+       }
+
+       if (ht) {
+               bssid_info |= NEI_REP_BSSID_INFO_HT |
+                       NEI_REP_BSSID_INFO_DELAYED_BA;
+
+               /* VHT bit added in IEEE P802.11-REVmc/D4.3 */
+               if (vht)
+                       bssid_info |= NEI_REP_BSSID_INFO_VHT;
+       }
+
+       /* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
+
+       ieee80211_freq_to_channel_ext(hapd->iface->freq,
+                                     hapd->iconf->secondary_channel,
+                                     hapd->iconf->vht_oper_chwidth,
+                                     &op_class, &channel);
+       width = hostapd_get_nr_chan_width(hapd, ht, vht);
+       if (vht) {
+               center_freq1 = ieee80211_chan_to_freq(
+                       NULL, op_class,
+                       hapd->iconf->vht_oper_centr_freq_seg0_idx);
+               if (width == NR_CHAN_WIDTH_80P80)
+                       center_freq2 = ieee80211_chan_to_freq(
+                               NULL, op_class,
+                               hapd->iconf->vht_oper_centr_freq_seg1_idx);
+       } else if (ht) {
+               center_freq1 = hapd->iface->freq +
+                       10 * hapd->iconf->secondary_channel;
+       }
+
+       ssid.ssid_len = hapd->conf->ssid.ssid_len;
+       os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
+
+       /*
+        * Neighbor Report element size = BSSID + BSSID info + op_class + chan +
+        * phy type + wide bandwidth channel subelement.
+        */
+       nr = wpabuf_alloc(ETH_ALEN + 4 + 1 + 1 + 1 + 5);
+       if (!nr)
+               return;
+
+       wpabuf_put_data(nr, hapd->own_addr, ETH_ALEN);
+       wpabuf_put_le32(nr, bssid_info);
+       wpabuf_put_u8(nr, op_class);
+       wpabuf_put_u8(nr, channel);
+       wpabuf_put_u8(nr, ieee80211_get_phy_type(hapd->iface->freq, ht, vht));
+
+       /*
+        * Wide Bandwidth Channel subelement may be needed to allow the
+        * receiving STA to send packets to the AP. See IEEE P802.11-REVmc/D5.0
+        * Figure 9-301.
+        */
+       wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN);
+       wpabuf_put_u8(nr, 3);
+       wpabuf_put_u8(nr, width);
+       wpabuf_put_u8(nr, center_freq1);
+       wpabuf_put_u8(nr, center_freq2);
+
+       hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci,
+                            hapd->iconf->civic);
+
+       wpabuf_free(nr);
+#endif /* NEED_AP_MLME */
+}
+
+
+static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
+                                                int err)
 {
        struct hostapd_data *hapd = iface->bss[0];
        size_t j;
@@ -1633,7 +1769,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
                        } while (j-- > 0);
                        goto fail;
                }
-               if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
+               if (is_zero_ether_addr(hapd->conf->bssid))
                        prev_addr = hapd->own_addr;
        }
        hapd = iface->bss[0];
@@ -1641,7 +1777,6 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
        hostapd_tx_queue_params(iface);
 
        ap_list_init(iface);
-       dl_list_init(&iface->sta_seen);
 
        hostapd_set_acl(hapd);
 
@@ -1701,6 +1836,9 @@ dfs_offload:
        if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
                iface->interfaces->terminate_on_error--;
 
+       for (j = 0; j < iface->num_bss; j++)
+               hostapd_set_own_neighbor_report(iface->bss[j]);
+
        return 0;
 
 fail:
@@ -1720,6 +1858,89 @@ fail:
 
 
 /**
+ * hostapd_setup_interface_complete - Complete interface setup
+ *
+ * This function is called when previous steps in the interface setup has been
+ * completed. This can also start operations, e.g., DFS, that will require
+ * additional processing before interface is ready to be enabled. Such
+ * operations will call this function from eloop callbacks when finished.
+ */
+int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
+{
+       struct hapd_interfaces *interfaces = iface->interfaces;
+       struct hostapd_data *hapd = iface->bss[0];
+       unsigned int i;
+       int not_ready_in_sync_ifaces = 0;
+
+       if (!iface->need_to_start_in_sync)
+               return hostapd_setup_interface_complete_sync(iface, err);
+
+       if (err) {
+               wpa_printf(MSG_ERROR, "Interface initialization failed");
+               hostapd_set_state(iface, HAPD_IFACE_DISABLED);
+               iface->need_to_start_in_sync = 0;
+               wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
+               if (interfaces && interfaces->terminate_on_error)
+                       eloop_terminate();
+               return -1;
+       }
+
+       if (iface->ready_to_start_in_sync) {
+               /* Already in ready and waiting. should never happpen */
+               return 0;
+       }
+
+       for (i = 0; i < interfaces->count; i++) {
+               if (interfaces->iface[i]->need_to_start_in_sync &&
+                   !interfaces->iface[i]->ready_to_start_in_sync)
+                       not_ready_in_sync_ifaces++;
+       }
+
+       /*
+        * Check if this is the last interface, if yes then start all the other
+        * waiting interfaces. If not, add this interface to the waiting list.
+        */
+       if (not_ready_in_sync_ifaces > 1 && iface->state == HAPD_IFACE_DFS) {
+               /*
+                * If this interface went through CAC, do not synchronize, just
+                * start immediately.
+                */
+               iface->need_to_start_in_sync = 0;
+               wpa_printf(MSG_INFO,
+                          "%s: Finished CAC - bypass sync and start interface",
+                          iface->bss[0]->conf->iface);
+               return hostapd_setup_interface_complete_sync(iface, err);
+       }
+
+       if (not_ready_in_sync_ifaces > 1) {
+               /* need to wait as there are other interfaces still coming up */
+               iface->ready_to_start_in_sync = 1;
+               wpa_printf(MSG_INFO,
+                          "%s: Interface waiting to sync with other interfaces",
+                          iface->bss[0]->conf->iface);
+               return 0;
+       }
+
+       wpa_printf(MSG_INFO,
+                  "%s: Last interface to sync - starting all interfaces",
+                  iface->bss[0]->conf->iface);
+       iface->need_to_start_in_sync = 0;
+       hostapd_setup_interface_complete_sync(iface, err);
+       for (i = 0; i < interfaces->count; i++) {
+               if (interfaces->iface[i]->need_to_start_in_sync &&
+                   interfaces->iface[i]->ready_to_start_in_sync) {
+                       hostapd_setup_interface_complete_sync(
+                               interfaces->iface[i], 0);
+                       /* Only once the interfaces are sync started */
+                       interfaces->iface[i]->need_to_start_in_sync = 0;
+               }
+       }
+
+       return 0;
+}
+
+
+/**
  * hostapd_setup_interface - Setup of an interface
  * @iface: Pointer to interface data.
  * Returns: 0 on success, -1 on failure
@@ -1778,6 +1999,8 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
        hapd->iface = hapd_iface;
        hapd->driver = hapd->iconf->driver;
        hapd->ctrl_sock = -1;
+       dl_list_init(&hapd->ctrl_dst);
+       dl_list_init(&hapd->nr_db);
 
        return hapd;
 }
@@ -1785,6 +2008,8 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
 
 static void hostapd_bss_deinit(struct hostapd_data *hapd)
 {
+       if (!hapd)
+               return;
        wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
                   hapd->conf->iface);
        hostapd_bss_deinit_no_free(hapd);
@@ -1819,8 +2044,11 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
        }
 #endif /* CONFIG_FST */
 
-       for (j = iface->num_bss - 1; j >= 0; j--)
+       for (j = iface->num_bss - 1; j >= 0; j--) {
+               if (!iface->bss)
+                       break;
                hostapd_bss_deinit(iface->bss[j]);
+       }
 }
 
 
@@ -1829,6 +2057,8 @@ void hostapd_interface_free(struct hostapd_iface *iface)
        size_t j;
        wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
        for (j = 0; j < iface->num_bss; j++) {
+               if (!iface->bss)
+                       break;
                wpa_printf(MSG_DEBUG, "%s: free hapd %p",
                           __func__, iface->bss[j]);
                os_free(iface->bss[j]);
@@ -1837,6 +2067,20 @@ void hostapd_interface_free(struct hostapd_iface *iface)
 }
 
 
+struct hostapd_iface * hostapd_alloc_iface(void)
+{
+       struct hostapd_iface *hapd_iface;
+
+       hapd_iface = os_zalloc(sizeof(*hapd_iface));
+       if (!hapd_iface)
+               return NULL;
+
+       dl_list_init(&hapd_iface->sta_seen);
+
+       return hapd_iface;
+}
+
+
 /**
  * hostapd_init - Allocate and initialize per-interface data
  * @config_file: Path to the configuration file
@@ -1854,7 +2098,7 @@ struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
        struct hostapd_data *hapd;
        size_t i;
 
-       hapd_iface = os_zalloc(sizeof(*hapd_iface));
+       hapd_iface = hostapd_alloc_iface();
        if (hapd_iface == NULL)
                goto fail;
 
@@ -2190,7 +2434,7 @@ hostapd_iface_alloc(struct hapd_interfaces *interfaces)
                return NULL;
        interfaces->iface = iface;
        hapd_iface = interfaces->iface[interfaces->count] =
-               os_zalloc(sizeof(*hapd_iface));
+               hostapd_alloc_iface();
        if (hapd_iface == NULL) {
                wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
                           "the interface", __func__);
@@ -2557,6 +2801,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)
@@ -2590,9 +2835,10 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
                wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
 
        if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
-               wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
-                          "for " MACSTR " (%d seconds - ap_max_inactivity)",
-                          __func__, MAC2STR(sta->addr),
+               wpa_printf(MSG_DEBUG,
+                          "%s: %s: reschedule ap_handle_timer timeout for "
+                          MACSTR " (%d seconds - ap_max_inactivity)",
+                          hapd->conf->iface, __func__, MAC2STR(sta->addr),
                           hapd->conf->ap_max_inactivity);
                eloop_cancel_timeout(ap_handle_timer, hapd, sta);
                eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
@@ -2627,12 +2873,23 @@ const char * hostapd_state_text(enum hostapd_iface_state s)
 void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s)
 {
        wpa_printf(MSG_INFO, "%s: interface state %s->%s",
-                  iface->conf->bss[0]->iface, hostapd_state_text(iface->state),
-                  hostapd_state_text(s));
+                  iface->conf ? iface->conf->bss[0]->iface : "N/A",
+                  hostapd_state_text(iface->state), hostapd_state_text(s));
        iface->state = s;
 }
 
 
+int hostapd_csa_in_progress(struct hostapd_iface *iface)
+{
+       unsigned int i;
+
+       for (i = 0; i < iface->num_bss; i++)
+               if (iface->bss[i]->csa_in_progress)
+                       return 1;
+       return 0;
+}
+
+
 #ifdef NEED_AP_MLME
 
 static void free_beacon_data(struct beacon_data *beacon)
@@ -2744,9 +3001,9 @@ free_ap_params:
 
 
 /*
- * TODO: This flow currently supports only changing frequency within the
- * same hw_mode. Any other changes to MAC parameters or provided settings (even
- * width) are not supported.
+ * TODO: This flow currently supports only changing channel and width within
+ * the same hw_mode. Any other changes to MAC parameters or provided settings
+ * are not supported.
  */
 static int hostapd_change_config_freq(struct hostapd_data *hapd,
                                      struct hostapd_config *conf,
@@ -2765,15 +3022,44 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
                return -1;
 
        /* if a pointer to old_params is provided we save previous state */
-       if (old_params) {
-               old_params->channel = conf->channel;
-               old_params->ht_enabled = conf->ieee80211n;
-               old_params->sec_channel_offset = conf->secondary_channel;
+       if (old_params &&
+           hostapd_set_freq_params(old_params, conf->hw_mode,
+                                   hostapd_hw_get_freq(hapd, conf->channel),
+                                   conf->channel, conf->ieee80211n,
+                                   conf->ieee80211ac,
+                                   conf->secondary_channel,
+                                   conf->vht_oper_chwidth,
+                                   conf->vht_oper_centr_freq_seg0_idx,
+                                   conf->vht_oper_centr_freq_seg1_idx,
+                                   conf->vht_capab))
+               return -1;
+
+       switch (params->bandwidth) {
+       case 0:
+       case 20:
+       case 40:
+               conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+               break;
+       case 80:
+               if (params->center_freq2)
+                       conf->vht_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
+               else
+                       conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+               break;
+       case 160:
+               conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ;
+               break;
+       default:
+               return -1;
        }
 
        conf->channel = channel;
        conf->ieee80211n = params->ht_enabled;
        conf->secondary_channel = params->sec_channel_offset;
+       ieee80211_freq_to_chan(params->center_freq1,
+                              &conf->vht_oper_centr_freq_seg0_idx);
+       ieee80211_freq_to_chan(params->center_freq2,
+                              &conf->vht_oper_centr_freq_seg1_idx);
 
        /* TODO: maybe call here hostapd_config_check here? */
 
@@ -2787,11 +3073,43 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
        struct hostapd_iface *iface = hapd->iface;
        struct hostapd_freq_params old_freq;
        int ret;
+       u8 chan, vht_bandwidth;
 
        os_memset(&old_freq, 0, sizeof(old_freq));
        if (!iface || !iface->freq || hapd->csa_in_progress)
                return -1;
 
+       switch (settings->freq_params.bandwidth) {
+       case 80:
+               if (settings->freq_params.center_freq2)
+                       vht_bandwidth = VHT_CHANWIDTH_80P80MHZ;
+               else
+                       vht_bandwidth = VHT_CHANWIDTH_80MHZ;
+               break;
+       case 160:
+               vht_bandwidth = VHT_CHANWIDTH_160MHZ;
+               break;
+       default:
+               vht_bandwidth = VHT_CHANWIDTH_USE_HT;
+               break;
+       }
+
+       if (ieee80211_freq_to_channel_ext(
+                   settings->freq_params.freq,
+                   settings->freq_params.sec_channel_offset,
+                   vht_bandwidth,
+                   &hapd->iface->cs_oper_class,
+                   &chan) == NUM_HOSTAPD_MODES) {
+               wpa_printf(MSG_DEBUG,
+                          "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d)",
+                          settings->freq_params.freq,
+                          settings->freq_params.sec_channel_offset,
+                          settings->freq_params.vht_enabled);
+               return -1;
+       }
+
+       settings->freq_params.channel = chan;
+
        ret = hostapd_change_config_freq(iface->bss[0], iface->conf,
                                         &settings->freq_params,
                                         &old_freq);
@@ -2818,8 +3136,10 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
                return ret;
        }
 
-       settings->counter_offset_beacon = hapd->cs_c_off_beacon;
-       settings->counter_offset_presp = hapd->cs_c_off_proberesp;
+       settings->counter_offset_beacon[0] = hapd->cs_c_off_beacon;
+       settings->counter_offset_presp[0] = hapd->cs_c_off_proberesp;
+       settings->counter_offset_beacon[1] = hapd->cs_c_off_ecsa_beacon;
+       settings->counter_offset_presp[1] = hapd->cs_c_off_ecsa_proberesp;
 
        return 0;
 }
@@ -2833,6 +3153,8 @@ void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
        hapd->cs_c_off_beacon = 0;
        hapd->cs_c_off_proberesp = 0;
        hapd->csa_in_progress = 0;
+       hapd->cs_c_off_ecsa_beacon = 0;
+       hapd->cs_c_off_ecsa_proberesp = 0;
 }
 
 
@@ -2920,6 +3242,8 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
        hostapd_enable_iface(iface);
 }
 
+#endif /* NEED_AP_MLME */
+
 
 struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
                                        const char *ifname)
@@ -2940,8 +3264,6 @@ struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
        return NULL;
 }
 
-#endif /* NEED_AP_MLME */
-
 
 void hostapd_periodic_iface(struct hostapd_iface *iface)
 {
index dcf51f0..dec46f6 100644 (file)
@@ -41,7 +41,7 @@ struct hapd_interfaces {
 
        size_t count;
        int global_ctrl_sock;
-       struct wpa_ctrl_dst *global_ctrl_dst;
+       struct dl_list global_ctrl_dst;
        char *global_iface_path;
        char *global_iface_name;
 #ifndef CONFIG_NATIVE_WINDOWS
@@ -53,6 +53,7 @@ struct hapd_interfaces {
 #ifndef CONFIG_NO_VLAN
        struct dynamic_iface *vlan_priv;
 #endif /* CONFIG_NO_VLAN */
+       int eloop_initialized;
 };
 
 enum hostapd_chan_status {
@@ -99,6 +100,16 @@ struct wps_stat {
        u8 peer_addr[ETH_ALEN];
 };
 
+struct hostapd_neighbor_entry {
+       struct dl_list list;
+       u8 bssid[ETH_ALEN];
+       struct wpa_ssid_value ssid;
+       struct wpabuf *nr;
+       struct wpabuf *lci;
+       struct wpabuf *civic;
+       /* LCI update time */
+       struct os_time lci_date;
+};
 
 /**
  * struct hostapd_data - hostapd per-BSS data structure
@@ -138,7 +149,7 @@ struct hostapd_data {
        void *msg_ctx_parent; /* parent interface ctx for wpa_msg() calls */
 
        struct radius_client_data *radius;
-       u32 acct_session_id_hi, acct_session_id_lo;
+       u64 acct_session_id;
        struct radius_das_data *radius_das;
 
        struct iapp_data *iapp;
@@ -155,7 +166,7 @@ struct hostapd_data {
        int tkip_countermeasures;
 
        int ctrl_sock;
-       struct wpa_ctrl_dst *ctrl_dst;
+       struct dl_list ctrl_dst;
 
        void *ssl_ctx;
        void *eap_sim_db_priv;
@@ -228,6 +239,8 @@ struct hostapd_data {
        unsigned int cs_c_off_beacon;
        unsigned int cs_c_off_proberesp;
        int csa_in_progress;
+       unsigned int cs_c_off_ecsa_beacon;
+       unsigned int cs_c_off_ecsa_proberesp;
 
        /* BSS Load */
        unsigned int bss_load_update_timeout;
@@ -256,9 +269,11 @@ struct hostapd_data {
 #ifdef CONFIG_MESH
        int num_plinks;
        int max_plinks;
-       void (*mesh_sta_free_cb)(struct sta_info *sta);
+       void (*mesh_sta_free_cb)(struct hostapd_data *hapd,
+                                struct sta_info *sta);
        struct wpabuf *mesh_pending_auth;
        struct os_reltime mesh_pending_auth_time;
+       u8 mesh_required_peer[ETH_ALEN];
 #endif /* CONFIG_MESH */
 
 #ifdef CONFIG_SQLITE
@@ -278,6 +293,17 @@ struct hostapd_data {
 
        struct l2_packet_data *l2_test;
 #endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_MBO
+       unsigned int mbo_assoc_disallow;
+#endif /* CONFIG_MBO */
+
+       struct dl_list nr_db;
+
+       u8 lci_req_token;
+       u8 range_req_token;
+       unsigned int lci_req_active:1;
+       unsigned int range_req_active:1;
 };
 
 
@@ -285,6 +311,9 @@ struct hostapd_sta_info {
        struct dl_list list;
        u8 addr[ETH_ALEN];
        struct os_reltime last_seen;
+#ifdef CONFIG_TAXONOMY
+       struct wpabuf *probe_ie_taxonomy;
+#endif /* CONFIG_TAXONOMY */
 };
 
 /**
@@ -327,6 +356,15 @@ struct hostapd_iface {
         */
        unsigned int driver_ap_teardown:1;
 
+       /*
+        * When set, indicates that this interface is part of list of
+        * interfaces that need to be started together (synchronously).
+        */
+       unsigned int need_to_start_in_sync:1;
+
+       /* Ready to start but waiting for other interfaces to become ready. */
+       unsigned int ready_to_start_in_sync:1;
+
        int num_ap; /* number of entries in ap_list */
        struct ap_info *ap_list; /* AP info list head */
        struct ap_info *ap_hash[STA_HASH_SIZE];
@@ -402,6 +440,9 @@ struct hostapd_iface {
        u64 last_channel_time_busy;
        u8 channel_utilization;
 
+       /* eCSA IE will be added only if operating class is specified */
+       u8 cs_oper_class;
+
        unsigned int dfs_cac_ms;
        struct os_reltime dfs_cac_start;
 
@@ -433,6 +474,7 @@ int hostapd_setup_interface(struct hostapd_iface *iface);
 int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
 void hostapd_interface_deinit(struct hostapd_iface *iface);
 void hostapd_interface_free(struct hostapd_iface *iface);
+struct hostapd_iface * hostapd_alloc_iface(void);
 struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
                                    const char *config_file);
 struct hostapd_iface *
@@ -449,6 +491,7 @@ 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);
 int hostapd_switch_channel(struct hostapd_data *hapd,
                           struct csa_settings *settings);
 void
@@ -478,6 +521,11 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
                         int ssi_signal);
 void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
                             int offset, int width, int cf1, int cf2);
+struct survey_results;
+void hostapd_event_get_survey(struct hostapd_iface *iface,
+                             struct survey_results *survey_results);
+void hostapd_acs_channel_selected(struct hostapd_data *hapd,
+                                 struct acs_selected_channels *acs_res);
 
 const struct hostapd_eap_user *
 hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
index fc8786d..16887ac 100644 (file)
@@ -329,6 +329,7 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
        res = ieee80211n_allowed_ht40_channel_pair(iface);
        if (!res) {
                iface->conf->secondary_channel = 0;
+               res = 1;
                wpa_printf(MSG_INFO, "Fallback to 20 MHz");
        }
 
@@ -472,8 +473,9 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
        struct wpa_driver_scan_params params;
        int ret;
 
-       if (!iface->conf->secondary_channel)
-               return 0; /* HT40 not used */
+       /* Check that HT40 is used and PRI / SEC switch is allowed */
+       if (!iface->conf->secondary_channel || iface->conf->no_pri_sec_switch)
+               return 0;
 
        hostapd_set_state(iface, HAPD_IFACE_HT_SCAN);
        wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
index 99aa04d..2556da3 100644 (file)
 #include "utils/includes.h"
 #include <net/if.h>
 #include <sys/ioctl.h>
-#ifdef USE_KERNEL_HEADERS
-#include <linux/if_packet.h>
-#else /* USE_KERNEL_HEADERS */
 #include <netpacket/packet.h>
-#endif /* USE_KERNEL_HEADERS */
 
 #include "utils/common.h"
 #include "utils/eloop.h"
@@ -385,6 +381,7 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
        struct sockaddr_in *paddr, uaddr;
        struct iapp_data *iapp;
        struct ip_mreqn mreq;
+       int reuseaddr = 1;
 
        iapp = os_zalloc(sizeof(*iapp));
        if (iapp == NULL)
@@ -447,6 +444,18 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
        os_memset(&uaddr, 0, sizeof(uaddr));
        uaddr.sin_family = AF_INET;
        uaddr.sin_port = htons(IAPP_UDP_PORT);
+
+       if (setsockopt(iapp->udp_sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
+                      sizeof(reuseaddr)) < 0) {
+               wpa_printf(MSG_INFO,
+                          "iapp_init - setsockopt[UDP,SO_REUSEADDR]: %s",
+                          strerror(errno));
+               /*
+                * Ignore this and try to continue. This is fine for single
+                * BSS cases, but may fail if multiple BSSes enable IAPP.
+                */
+       }
+
        if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
                 sizeof(uaddr)) < 0) {
                wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s",
index 7bb18c0..4e04169 100644 (file)
@@ -42,6 +42,9 @@
 #include "hw_features.h"
 #include "ieee802_11.h"
 #include "dfs.h"
+#include "mbo_ap.h"
+#include "rrm.h"
+#include "taxonomy.h"
 
 
 u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
@@ -139,6 +142,7 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd)
        int capab = WLAN_CAPABILITY_ESS;
        int privacy;
        int dfs;
+       int i;
 
        /* Check if any of configured channels require DFS */
        dfs = hostapd_is_dfs_required(hapd->iface);
@@ -186,8 +190,12 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd)
            (hapd->iconf->spectrum_mgmt_required || dfs))
                capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
 
-       if (hapd->conf->radio_measurements)
-               capab |= IEEE80211_CAP_RRM;
+       for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
+               if (hapd->conf->radio_measurements[i]) {
+                       capab |= IEEE80211_CAP_RRM;
+                       break;
+               }
+       }
 
        return capab;
 }
@@ -207,16 +215,17 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
                if (!sta->challenge) {
                        /* Generate a pseudo-random challenge */
                        u8 key[8];
-                       struct os_time now;
-                       int r;
+
                        sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN);
                        if (sta->challenge == NULL)
                                return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
-                       os_get_time(&now);
-                       r = os_random();
-                       os_memcpy(key, &now.sec, 4);
-                       os_memcpy(key + 4, &r, 4);
+                       if (os_get_random(key, sizeof(key)) < 0) {
+                               os_free(sta->challenge);
+                               sta->challenge = NULL;
+                               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+                       }
+
                        rc4_skip(key, sizeof(key), 0,
                                 sta->challenge, WLAN_AUTH_CHALLENGE_LEN);
                }
@@ -250,19 +259,20 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
 #endif /* CONFIG_NO_RC4 */
 
 
-static void send_auth_reply(struct hostapd_data *hapd,
-                           const u8 *dst, const u8 *bssid,
-                           u16 auth_alg, u16 auth_transaction, u16 resp,
-                           const u8 *ies, size_t ies_len)
+static int send_auth_reply(struct hostapd_data *hapd,
+                          const u8 *dst, const u8 *bssid,
+                          u16 auth_alg, u16 auth_transaction, u16 resp,
+                          const u8 *ies, size_t ies_len)
 {
        struct ieee80211_mgmt *reply;
        u8 *buf;
        size_t rlen;
+       int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
 
        rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
        buf = os_zalloc(rlen);
        if (buf == NULL)
-               return;
+               return -1;
 
        reply = (struct ieee80211_mgmt *) buf;
        reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -283,9 +293,13 @@ static void send_auth_reply(struct hostapd_data *hapd,
                   MAC2STR(dst), auth_alg, auth_transaction,
                   resp, (unsigned long) ies_len);
        if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
-               wpa_printf(MSG_INFO, "send_auth_reply: send");
+               wpa_printf(MSG_INFO, "send_auth_reply: send failed");
+       else
+               reply_res = WLAN_STATUS_SUCCESS;
 
        os_free(buf);
+
+       return reply_res;
 }
 
 
@@ -296,17 +310,25 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
 {
        struct hostapd_data *hapd = ctx;
        struct sta_info *sta;
+       int reply_res;
 
-       send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT, auth_transaction,
-                       status, ies, ies_len);
-
-       if (status != WLAN_STATUS_SUCCESS)
-               return;
+       reply_res = send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT,
+                                   auth_transaction, status, ies, ies_len);
 
        sta = ap_get_sta(hapd, dst);
        if (sta == NULL)
                return;
 
+       if (sta->added_unassoc && (reply_res != WLAN_STATUS_SUCCESS ||
+                                  status != WLAN_STATUS_SUCCESS)) {
+               hostapd_drv_sta_remove(hapd, sta->addr);
+               sta->added_unassoc = 0;
+               return;
+       }
+
+       if (status != WLAN_STATUS_SUCCESS)
+               return;
+
        hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
                       HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
        sta->flags |= WLAN_STA_AUTH;
@@ -369,18 +391,19 @@ static int auth_sae_send_commit(struct hostapd_data *hapd,
                                const u8 *bssid, int update)
 {
        struct wpabuf *data;
+       int reply_res;
 
        data = auth_build_sae_commit(hapd, sta, update);
        if (data == NULL)
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
-       send_auth_reply(hapd, sta->addr, bssid,
-                       WLAN_AUTH_SAE, 1, WLAN_STATUS_SUCCESS,
-                       wpabuf_head(data), wpabuf_len(data));
+       reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1,
+                                   WLAN_STATUS_SUCCESS, wpabuf_head(data),
+                                   wpabuf_len(data));
 
        wpabuf_free(data);
 
-       return WLAN_STATUS_SUCCESS;
+       return reply_res;
 }
 
 
@@ -389,18 +412,19 @@ static int auth_sae_send_confirm(struct hostapd_data *hapd,
                                 const u8 *bssid)
 {
        struct wpabuf *data;
+       int reply_res;
 
        data = auth_build_sae_confirm(hapd, sta);
        if (data == NULL)
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
-       send_auth_reply(hapd, sta->addr, bssid,
-                       WLAN_AUTH_SAE, 2, WLAN_STATUS_SUCCESS,
-                       wpabuf_head(data), wpabuf_len(data));
+       reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2,
+                                   WLAN_STATUS_SUCCESS, wpabuf_head(data),
+                                   wpabuf_len(data));
 
        wpabuf_free(data);
 
-       return WLAN_STATUS_SUCCESS;
+       return reply_res;
 }
 
 
@@ -495,6 +519,9 @@ static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
        if (sae_check_big_sync(sta))
                return;
        sta->sae->sync++;
+       wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR
+                  " (sync=%d state=%d)",
+                  MAC2STR(sta->addr), sta->sae->sync, sta->sae->state);
 
        switch (sta->sae->state) {
        case SAE_COMMITTED:
@@ -537,6 +564,18 @@ static void sae_set_retransmit_timer(struct hostapd_data *hapd,
 }
 
 
+void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
+{
+       sta->flags |= WLAN_STA_AUTH;
+       sta->auth_alg = WLAN_AUTH_SAE;
+       mlme_authenticate_indication(hapd, sta);
+       wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+       sta->sae->state = SAE_ACCEPTED;
+       wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
+                              sta->sae->pmk, sta->sae->pmkid);
+}
+
+
 static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
                       const u8 *bssid, u8 auth_transaction)
 {
@@ -580,7 +619,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
                                 * message now to get alternating sequence of
                                 * Authentication frames between the AP and STA.
                                 * Confirm will be sent in
-                                * Commited -> Confirmed/Accepted transition
+                                * Committed -> Confirmed/Accepted transition
                                 * when receiving Confirm from STA.
                                 */
                        }
@@ -659,13 +698,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
 
                        sae_set_retransmit_timer(hapd, sta);
                } else {
-                       sta->flags |= WLAN_STA_AUTH;
-                       sta->auth_alg = WLAN_AUTH_SAE;
-                       mlme_authenticate_indication(hapd, sta);
-                       wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
-                       sta->sae->state = SAE_ACCEPTED;
-                       wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
-                                              sta->sae->pmk);
+                       sae_accept_sta(hapd, sta);
                }
                break;
        case SAE_ACCEPTED:
@@ -674,6 +707,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
                                   ") doing reauthentication",
                                   MAC2STR(sta->addr));
                        ap_free_sta(hapd, sta);
+                       wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
                } else {
                        if (sae_check_big_sync(sta))
                                return WLAN_STATUS_SUCCESS;
@@ -694,23 +728,73 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
 }
 
 
+static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
+{
+       struct sae_data *sae = sta->sae;
+       int i, *groups = hapd->conf->sae_groups;
+
+       if (sae->state != SAE_COMMITTED)
+               return;
+
+       wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
+
+       for (i = 0; groups && groups[i] > 0; i++) {
+               if (sae->group == groups[i])
+                       break;
+       }
+
+       if (!groups || groups[i] <= 0) {
+               wpa_printf(MSG_DEBUG,
+                          "SAE: Previously selected group not found from the current configuration");
+               return;
+       }
+
+       for (;;) {
+               i++;
+               if (groups[i] <= 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "SAE: No alternative group enabled");
+                       return;
+               }
+
+               if (sae_set_group(sae, groups[i]) < 0)
+                       continue;
+
+               break;
+       }
+       wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]);
+}
+
+
 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)
 {
-       u16 resp = WLAN_STATUS_SUCCESS;
+       int resp = WLAN_STATUS_SUCCESS;
        struct wpabuf *data = NULL;
 
        if (!sta->sae) {
-               if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
-                       return;
+               if (auth_transaction != 1 ||
+                   status_code != WLAN_STATUS_SUCCESS) {
+                       resp = -1;
+                       goto remove_sta;
+               }
                sta->sae = os_zalloc(sizeof(*sta->sae));
-               if (sta->sae == NULL)
-                       return;
+               if (!sta->sae) {
+                       resp = -1;
+                       goto remove_sta;
+               }
                sta->sae->state = SAE_NOTHING;
                sta->sae->sync = 0;
        }
 
+       if (sta->mesh_sae_pmksa_caching) {
+               wpa_printf(MSG_DEBUG,
+                          "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication");
+               wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+               sta->mesh_sae_pmksa_caching = 0;
+       }
+
        if (auth_transaction == 1) {
                const u8 *token = NULL, *pos, *end;
                size_t token_len = 0;
@@ -746,7 +830,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                        if (sta->sae->tmp->anti_clogging_token == NULL) {
                                wpa_printf(MSG_ERROR,
                                           "SAE: Failed to alloc for anti-clogging token");
-                               return;
+                               resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                               goto remove_sta;
                        }
 
                        /*
@@ -756,10 +841,11 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                         * Authentication frame, and the commit-scalar and
                         * COMMIT-ELEMENT previously sent.
                         */
-                       if (auth_sae_send_commit(hapd, sta, mgmt->bssid, 0)) {
+                       resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0);
+                       if (resp != WLAN_STATUS_SUCCESS) {
                                wpa_printf(MSG_ERROR,
                                           "SAE: Failed to send commit message");
-                               return;
+                               goto remove_sta;
                        }
                        sta->sae->state = SAE_COMMITTED;
                        sta->sae->sync = 0;
@@ -767,8 +853,18 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                        return;
                }
 
+               if ((hapd->conf->mesh & MESH_ENABLED) &&
+                   status_code ==
+                   WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+                   sta->sae->tmp) {
+                       wpa_printf(MSG_DEBUG,
+                                  "SAE: Peer did not accept our SAE group");
+                       sae_pick_next_group(hapd, sta);
+                       goto remove_sta;
+               }
+
                if (status_code != WLAN_STATUS_SUCCESS)
-                       return;
+                       goto remove_sta;
 
                resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
                                        ((const u8 *) mgmt) + len -
@@ -778,14 +874,15 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                        wpa_printf(MSG_DEBUG,
                                   "SAE: Drop commit message from " MACSTR " due to reflection attack",
                                   MAC2STR(sta->addr));
-                       return;
+                       goto remove_sta;
                }
                if (token && check_sae_token(hapd, sta->addr, token, token_len)
                    < 0) {
                        wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
                                   "incorrect token from " MACSTR,
                                   MAC2STR(sta->addr));
-                       return;
+                       resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                       goto remove_sta;
                }
 
                if (resp != WLAN_STATUS_SUCCESS)
@@ -810,7 +907,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                               "SAE authentication (RX confirm, status=%u)",
                               status_code);
                if (status_code != WLAN_STATUS_SUCCESS)
-                       return;
+                       goto remove_sta;
                if (sta->sae->state >= SAE_CONFIRMED ||
                    !(hapd->conf->mesh & MESH_ENABLED)) {
                        if (sae_check_confirm(sta->sae, mgmt->u.auth.variable,
@@ -827,7 +924,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                               "unexpected SAE authentication transaction %u (status=%u)",
                               auth_transaction, status_code);
                if (status_code != WLAN_STATUS_SUCCESS)
-                       return;
+                       goto remove_sta;
                resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
        }
 
@@ -838,6 +935,13 @@ reply:
                                data ? wpabuf_head(data) : (u8 *) "",
                                data ? wpabuf_len(data) : 0);
        }
+
+remove_sta:
+       if (sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
+                                  status_code != WLAN_STATUS_SUCCESS)) {
+               hostapd_drv_sta_remove(hapd, sta->addr);
+               sta->added_unassoc = 0;
+       }
        wpabuf_free(data);
 }
 
@@ -882,11 +986,11 @@ static void handle_auth(struct hostapd_data *hapd,
        u16 auth_alg, auth_transaction, status_code;
        u16 resp = WLAN_STATUS_SUCCESS;
        struct sta_info *sta = NULL;
-       int res;
+       int res, reply_res;
        u16 fc;
        const u8 *challenge = NULL;
        u32 session_timeout, acct_interim_interval;
-       int vlan_id = 0;
+       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;
@@ -894,6 +998,8 @@ static void handle_auth(struct hostapd_data *hapd,
        char *radius_cui = NULL;
        u16 seq_ctrl;
 
+       os_memset(&vlan_id, 0, sizeof(vlan_id));
+
        if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
                wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
                           (unsigned long) len);
@@ -1067,13 +1173,22 @@ static void handle_auth(struct hostapd_data *hapd,
                                       seq_ctrl);
                        return;
                }
+#ifdef CONFIG_MESH
+               if ((hapd->conf->mesh & MESH_ENABLED) &&
+                   sta->plink_state == PLINK_BLOCKED) {
+                       wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
+                                  " is blocked - drop Authentication frame",
+                                  MAC2STR(mgmt->sa));
+                       return;
+               }
+#endif /* CONFIG_MESH */
        } else {
 #ifdef CONFIG_MESH
                if (hapd->conf->mesh & MESH_ENABLED) {
                        /* if the mesh peer is not available, we don't do auth.
                         */
                        wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
-                                  " not yet known - drop Authentiation frame",
+                                  " not yet known - drop Authentication frame",
                                   MAC2STR(mgmt->sa));
                        /*
                         * Save a copy of the frame so that it can be processed
@@ -1095,19 +1210,23 @@ static void handle_auth(struct hostapd_data *hapd,
        sta->last_seq_ctrl = seq_ctrl;
        sta->last_subtype = WLAN_FC_STYPE_AUTH;
 
-       if (vlan_id > 0) {
-               if (!hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
-                       hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
-                                      HOSTAPD_LEVEL_INFO, "Invalid VLAN ID "
-                                      "%d received from RADIUS server",
-                                      vlan_id);
-                       resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
-                       goto fail;
-               }
-               sta->vlan_id = vlan_id;
+       if (vlan_id.notempty &&
+           !hostapd_vlan_valid(hapd->conf->vlan, &vlan_id)) {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
-                              HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
+                              HOSTAPD_LEVEL_INFO,
+                              "Invalid VLAN %d%s received from RADIUS server",
+                              vlan_id.untagged,
+                              vlan_id.tagged[0] ? "+" : "");
+               resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+               goto fail;
        }
+       if (ap_sta_set_vlan(hapd, sta, &vlan_id) < 0) {
+               resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+               goto fail;
+       }
+       if (sta->vlan_id)
+               hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+                              HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
 
        hostapd_free_psk_list(sta->psk);
        if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
@@ -1132,6 +1251,46 @@ static void handle_auth(struct hostapd_data *hapd,
        else
                ap_sta_no_session_timeout(hapd, sta);
 
+       /*
+        * If the driver supports full AP client state, add a station to the
+        * driver before sending authentication reply to make sure the driver
+        * has resources, and not to go through the entire authentication and
+        * association handshake, and fail it at the end.
+        *
+        * If this is not the first transaction, in a multi-step authentication
+        * algorithm, the station already exists in the driver
+        * (sta->added_unassoc = 1) so skip it.
+        *
+        * In mesh mode, the station was already added to the driver when the
+        * NEW_PEER_CANDIDATE event is received.
+        */
+       if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
+           !(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.
+                */
+               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, NULL, 0, 0,
+                                   NULL, 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");
+                       resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+                       goto fail;
+               }
+
+               sta->added_unassoc = 1;
+       }
+
        switch (auth_alg) {
        case WLAN_AUTH_OPEN:
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -1205,12 +1364,19 @@ static void handle_auth(struct hostapd_data *hapd,
        os_free(radius_cui);
        hostapd_free_psk_list(psk);
 
-       send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
-                       auth_transaction + 1, resp, resp_ies, resp_ies_len);
+       reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
+                                   auth_transaction + 1, resp, resp_ies,
+                                   resp_ies_len);
+
+       if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
+                                         reply_res != WLAN_STATUS_SUCCESS)) {
+               hostapd_drv_sta_remove(hapd, sta->addr);
+               sta->added_unassoc = 0;
+       }
 }
 
 
-static int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
+int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
 {
        int i, j = 32, aid;
 
@@ -1220,6 +1386,9 @@ static int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
                return 0;
        }
 
+       if (TEST_FAIL())
+               return -1;
+
        for (i = 0; i < AID_WORDS; i++) {
                if (hapd->sta_aid[i] == (u32) -1)
                        continue;
@@ -1327,6 +1496,9 @@ static u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
        }
 #endif /* CONFIG_INTERWORKING */
 
+       if (ext_capab_ie_len > 0)
+               sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2));
+
        return WLAN_STATUS_SUCCESS;
 }
 
@@ -1617,6 +1789,27 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                sta->mb_ies = NULL;
 #endif /* CONFIG_FST */
 
+#ifdef CONFIG_MBO
+       mbo_ap_check_sta_assoc(hapd, sta, &elems);
+
+       if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
+           elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
+           hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+               wpa_printf(MSG_INFO,
+                          "MBO: Reject WPA2 association without PMF");
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+#endif /* CONFIG_MBO */
+
+       ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
+                                   elems.supp_op_classes_len);
+
+       if ((sta->capability & WLAN_CAPABILITY_RADIO_MEASUREMENT) &&
+           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));
+
        return WLAN_STATUS_SUCCESS;
 }
 
@@ -1643,9 +1836,66 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
 }
 
 
-static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
-                           u16 status_code, int reassoc, const u8 *ies,
-                           size_t ies_len)
+static int add_associated_sta(struct hostapd_data *hapd,
+                             struct sta_info *sta)
+{
+       struct ieee80211_ht_capabilities ht_cap;
+       struct ieee80211_vht_capabilities vht_cap;
+
+       /*
+        * Remove the STA entry to ensure the STA PS state gets cleared and
+        * configuration gets updated. This is relevant for cases, such as
+        * FT-over-the-DS, where a station re-associates back to the same AP but
+        * skips the authentication flow, or if working with a driver that
+        * does not support full AP client state.
+        */
+       if (!sta->added_unassoc)
+               hostapd_drv_sta_remove(hapd, sta->addr);
+
+#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);
+#endif /* CONFIG_IEEE80211AC */
+
+       /*
+        * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
+        * will be set when the ACK frame for the (Re)Association Response frame
+        * is processed (TX status driver event).
+        */
+       if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
+                           sta->supported_rates, sta->supported_rates_len,
+                           sta->listen_interval,
+                           sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
+                           sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
+                           sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
+                           sta->vht_opmode, sta->p2p_ie ? 1 : 0,
+                           sta->added_unassoc)) {
+               hostapd_logger(hapd, sta->addr,
+                              HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
+                              "Could not %s STA to kernel driver",
+                              sta->added_unassoc ? "set" : "add");
+
+               if (sta->added_unassoc) {
+                       hostapd_drv_sta_remove(hapd, sta->addr);
+                       sta->added_unassoc = 0;
+               }
+
+               return -1;
+       }
+
+       sta->added_unassoc = 0;
+
+       return 0;
+}
+
+
+static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
+                          u16 status_code, int reassoc, const u8 *ies,
+                          size_t ies_len)
 {
        int send_len;
        u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
@@ -1695,7 +1945,23 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 
 #ifdef CONFIG_IEEE80211AC
        if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
-               p = hostapd_eid_vht_capabilities(hapd, p);
+               u32 nsts = 0, sta_nsts;
+
+               if (hapd->conf->use_sta_nsts && sta->vht_capabilities) {
+                       struct ieee80211_vht_capabilities *capa;
+
+                       nsts = (hapd->iface->conf->vht_capab >>
+                               VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+                       capa = sta->vht_capabilities;
+                       sta_nsts = (le_to_host32(capa->vht_capabilities_info) >>
+                                   VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+
+                       if (nsts < sta_nsts)
+                               nsts = 0;
+                       else
+                               nsts = sta_nsts;
+               }
+               p = hostapd_eid_vht_capabilities(hapd, p, nsts);
                p = hostapd_eid_vht_operation(hapd, p);
        }
 #endif /* CONFIG_IEEE80211AC */
@@ -1734,7 +2000,7 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 #endif /* CONFIG_WPS */
 
 #ifdef CONFIG_P2P
-       if (sta->p2p_ie) {
+       if (sta->p2p_ie && hapd->p2p_group) {
                struct wpabuf *p2p_resp_ie;
                enum p2p_status_code status;
                switch (status_code) {
@@ -1763,11 +2029,25 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
                p = hostapd_eid_p2p_manage(hapd, p);
 #endif /* CONFIG_P2P_MANAGER */
 
+       p = hostapd_eid_mbo(hapd, p, buf + sizeof(buf) - p);
+
+       if (hapd->conf->assocresp_elements &&
+           (size_t) (buf + sizeof(buf) - p) >=
+           wpabuf_len(hapd->conf->assocresp_elements)) {
+               os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
+                         wpabuf_len(hapd->conf->assocresp_elements));
+               p += wpabuf_len(hapd->conf->assocresp_elements);
+       }
+
        send_len += p - reply->u.assoc_resp.variable;
 
-       if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0)
+       if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
                wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
                           strerror(errno));
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+
+       return WLAN_STATUS_SUCCESS;
 }
 
 
@@ -1776,7 +2056,7 @@ static void handle_assoc(struct hostapd_data *hapd,
                         int reassoc)
 {
        u16 capab_info, listen_interval, seq_ctrl, fc;
-       u16 resp = WLAN_STATUS_SUCCESS;
+       u16 resp = WLAN_STATUS_SUCCESS, reply_res;
        const u8 *pos;
        int left, i;
        struct sta_info *sta;
@@ -1843,6 +2123,12 @@ static void handle_assoc(struct hostapd_data *hapd,
                wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
                           "prior to authentication since it is using "
                           "over-the-DS FT", MAC2STR(mgmt->sa));
+
+               /*
+                * Mark station as authenticated, to avoid adding station
+                * entry in the driver as associated and not authenticated
+                */
+               sta->flags |= WLAN_STA_AUTH;
        } else
 #endif /* CONFIG_IEEE80211R */
        if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
@@ -1886,6 +2172,19 @@ static void handle_assoc(struct hostapd_data *hapd,
                goto fail;
        }
 
+#ifdef CONFIG_MBO
+       if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
+               resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+               goto fail;
+       }
+#endif /* CONFIG_MBO */
+
+       /*
+        * sta->capability is used in check_assoc_ies() for RRM enabled
+        * capability element.
+        */
+       sta->capability = capab_info;
+
        /* followed by SSID and Supported rates; and HT capabilities if 802.11n
         * is used */
        resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
@@ -1899,7 +2198,6 @@ static void handle_assoc(struct hostapd_data *hapd,
                goto fail;
        }
 
-       sta->capability = capab_info;
        sta->listen_interval = listen_interval;
 
        if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
@@ -1969,8 +2267,44 @@ static void handle_assoc(struct hostapd_data *hapd,
         * remove the STA immediately. */
        sta->timeout_next = STA_NULLFUNC;
 
+#ifdef CONFIG_TAXONOMY
+       taxonomy_sta_info_assoc_req(hapd, sta, pos, left);
+#endif /* CONFIG_TAXONOMY */
+
  fail:
-       send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
+       /*
+        * In case of a successful response, add the station to the driver.
+        * Otherwise, the kernel may ignore Data frames before we process the
+        * ACK frame (TX status). In case of a failure, this station will be
+        * removed.
+        *
+        * Note that this is not compliant with the IEEE 802.11 standard that
+        * states that a non-AP station should transition into the
+        * authenticated/associated state only after the station acknowledges
+        * the (Re)Association Response frame. However, still do this as:
+        *
+        * 1. In case the station does not acknowledge the (Re)Association
+        *    Response frame, it will be removed.
+        * 2. Data frames will be dropped in the kernel until the station is
+        *    set into authorized state, and there are no significant known
+        *    issues with processing other non-Data Class 3 frames during this
+        *    window.
+        */
+       if (resp == WLAN_STATUS_SUCCESS && add_associated_sta(hapd, sta))
+               resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+
+       reply_res = send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
+
+       /*
+        * Remove the station in case tranmission of a success response fails
+        * (the STA was added associated to the driver) or if the station was
+        * previously added unassociated.
+        */
+       if ((reply_res != WLAN_STATUS_SUCCESS &&
+            resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc) {
+               hostapd_drv_sta_remove(hapd, sta->addr);
+               sta->added_unassoc = 0;
+       }
 }
 
 
@@ -2007,11 +2341,12 @@ static void handle_disassoc(struct hostapd_data *hapd,
        /* Stop Accounting and IEEE 802.1X sessions, but leave the STA
         * authenticated. */
        accounting_sta_stop(hapd, sta);
-       ieee802_1x_free_station(sta);
+       ieee802_1x_free_station(hapd, sta);
        if (sta->ipaddr)
                hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
        ap_sta_ip6addr_del(hapd, sta);
        hostapd_drv_sta_remove(hapd, sta->addr);
+       sta->added_unassoc = 0;
 
        if (sta->timeout_next == STA_NULLFUNC ||
            sta->timeout_next == STA_DISASSOC) {
@@ -2233,6 +2568,9 @@ static int handle_action(struct hostapd_data *hapd,
                                return 1;
                }
                break;
+       case WLAN_ACTION_RADIO_MEASUREMENT:
+               hostapd_handle_radio_measurement(hapd, (const u8 *) mgmt, len);
+               return 1;
        }
 
        hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -2240,8 +2578,9 @@ static int handle_action(struct hostapd_data *hapd,
                       "handle_action - unknown action category %d or invalid "
                       "frame",
                       mgmt->u.action.category);
-       if (!(mgmt->da[0] & 0x01) && !(mgmt->u.action.category & 0x80) &&
-           !(mgmt->sa[0] & 0x01)) {
+       if (!is_multicast_ether_addr(mgmt->da) &&
+           !(mgmt->u.action.category & 0x80) &&
+           !is_multicast_ether_addr(mgmt->sa)) {
                struct ieee80211_mgmt *resp;
 
                /*
@@ -2288,7 +2627,6 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
                    struct hostapd_frame_info *fi)
 {
        struct ieee80211_mgmt *mgmt;
-       int broadcast;
        u16 fc, stype;
        int ret = 0;
 
@@ -2304,11 +2642,7 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
                return 1;
        }
 
-       broadcast = mgmt->bssid[0] == 0xff && mgmt->bssid[1] == 0xff &&
-               mgmt->bssid[2] == 0xff && mgmt->bssid[3] == 0xff &&
-               mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff;
-
-       if (!broadcast &&
+       if (!is_broadcast_ether_addr(mgmt->bssid) &&
 #ifdef CONFIG_P2P
            /* Invitation responses can be sent with the peer MAC as BSSID */
            !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
@@ -2388,28 +2722,28 @@ static void handle_auth_cb(struct hostapd_data *hapd,
        u16 auth_alg, auth_transaction, status_code;
        struct sta_info *sta;
 
+       sta = ap_get_sta(hapd, mgmt->da);
+       if (!sta) {
+               wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found",
+                          MAC2STR(mgmt->da));
+               return;
+       }
+
+       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);
+
        if (!ok) {
                hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_NOTICE,
                               "did not acknowledge authentication response");
-               return;
+               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);
-               return;
-       }
-
-       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);
-
-       sta = ap_get_sta(hapd, mgmt->da);
-       if (!sta) {
-               wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found",
-                          MAC2STR(mgmt->da));
-               return;
+               goto fail;
        }
 
        if (status_code == WLAN_STATUS_SUCCESS &&
@@ -2418,6 +2752,15 @@ static void handle_auth_cb(struct hostapd_data *hapd,
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_INFO, "authenticated");
                sta->flags |= WLAN_STA_AUTH;
+               if (sta->added_unassoc)
+                       hostapd_set_sta_flags(hapd, sta);
+               return;
+       }
+
+fail:
+       if (status_code != WLAN_STATUS_SUCCESS && sta->added_unassoc) {
+               hostapd_drv_sta_remove(hapd, sta->addr);
+               sta->added_unassoc = 0;
        }
 }
 
@@ -2453,15 +2796,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
        u16 status;
        struct sta_info *sta;
        int new_assoc = 1;
-       struct ieee80211_ht_capabilities ht_cap;
-       struct ieee80211_vht_capabilities vht_cap;
-
-       if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
-                                     sizeof(mgmt->u.assoc_resp))) {
-               wpa_printf(MSG_INFO, "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
-                          reassoc, (unsigned long) len);
-               return;
-       }
 
        sta = ap_get_sta(hapd, mgmt->da);
        if (!sta) {
@@ -2470,11 +2804,12 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
                return;
        }
 
-       if (!ok) {
-               hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
-                              HOSTAPD_LEVEL_DEBUG,
-                              "did not acknowledge association response");
-               sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
+       if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
+                                     sizeof(mgmt->u.assoc_resp))) {
+               wpa_printf(MSG_INFO,
+                          "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
+                          reassoc, (unsigned long) len);
+               hostapd_drv_sta_remove(hapd, sta->addr);
                return;
        }
 
@@ -2483,6 +2818,18 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
        else
                status = le_to_host16(mgmt->u.assoc_resp.status_code);
 
+       if (!ok) {
+               hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
+                              HOSTAPD_LEVEL_DEBUG,
+                              "did not acknowledge association response");
+               sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
+               /* The STA is added only in case of SUCCESS */
+               if (status == WLAN_STATUS_SUCCESS)
+                       hostapd_drv_sta_remove(hapd, sta->addr);
+
+               return;
+       }
+
        if (status != WLAN_STATUS_SUCCESS)
                return;
 
@@ -2517,38 +2864,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
        sta->sa_query_timed_out = 0;
 #endif /* CONFIG_IEEE80211W */
 
-       /*
-        * Remove the STA entry in order to make sure the STA PS state gets
-        * cleared and configuration gets updated in case of reassociation back
-        * to the same AP.
-        */
-       hostapd_drv_sta_remove(hapd, sta->addr);
-
-#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);
-#endif /* CONFIG_IEEE80211AC */
-
-       if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
-                           sta->supported_rates, sta->supported_rates_len,
-                           sta->listen_interval,
-                           sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
-                           sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
-                           sta->flags, sta->qosinfo, sta->vht_opmode)) {
-               hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-                              HOSTAPD_LEVEL_NOTICE,
-                              "Could not add STA to kernel driver");
-
-               ap_sta_disconnect(hapd, sta, sta->addr,
-                                 WLAN_REASON_DISASSOC_AP_BUSY);
-
-               return;
-       }
-
        if (sta->flags & WLAN_STA_WDS) {
                int ret;
                char ifname_wds[IFNAMSIZ + 1];
@@ -2580,8 +2895,26 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
        else
                wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
        hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
-
        ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
+
+       if (sta->pending_eapol_rx) {
+               struct os_reltime now, age;
+
+               os_get_reltime(&now);
+               os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age);
+               if (age.sec == 0 && age.usec < 200000) {
+                       wpa_printf(MSG_DEBUG,
+                                  "Process pending EAPOL frame that was received from " MACSTR " just before association notification",
+                                  MAC2STR(sta->addr));
+                       ieee802_1x_receive(
+                               hapd, mgmt->da,
+                               wpabuf_head(sta->pending_eapol_rx->buf),
+                               wpabuf_len(sta->pending_eapol_rx->buf));
+               }
+               wpabuf_free(sta->pending_eapol_rx->buf);
+               os_free(sta->pending_eapol_rx);
+               sta->pending_eapol_rx = NULL;
+       }
 }
 
 
@@ -2590,7 +2923,7 @@ static void handle_deauth_cb(struct hostapd_data *hapd,
                             size_t len, int ok)
 {
        struct sta_info *sta;
-       if (mgmt->da[0] & 0x01)
+       if (is_multicast_ether_addr(mgmt->da))
                return;
        sta = ap_get_sta(hapd, mgmt->da);
        if (!sta) {
@@ -2614,7 +2947,7 @@ static void handle_disassoc_cb(struct hostapd_data *hapd,
                               size_t len, int ok)
 {
        struct sta_info *sta;
-       if (mgmt->da[0] & 0x01)
+       if (is_multicast_ether_addr(mgmt->da))
                return;
        sta = ap_get_sta(hapd, mgmt->da);
        if (!sta) {
@@ -2670,7 +3003,7 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
                handle_assoc_cb(hapd, mgmt, len, 1, ok);
                break;
        case WLAN_FC_STYPE_PROBE_RESP:
-               wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb");
+               wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb ok=%d", ok);
                break;
        case WLAN_FC_STYPE_DEAUTH:
                wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
@@ -2681,7 +3014,7 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
                handle_disassoc_cb(hapd, mgmt, len, ok);
                break;
        case WLAN_FC_STYPE_ACTION:
-               wpa_printf(MSG_DEBUG, "mgmt::action cb");
+               wpa_printf(MSG_DEBUG, "mgmt::action cb ok=%d", ok);
                break;
        default:
                wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
@@ -2779,6 +3112,8 @@ void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
        }
        if (sta == NULL)
                return;
+       wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POLL_OK MACSTR,
+               MAC2STR(sta->addr));
        if (!(sta->flags & WLAN_STA_PENDING_POLL))
                return;
 
@@ -2817,7 +3152,7 @@ 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 (src[0] & 0x01) {
+       if (is_multicast_ether_addr(src)) {
                /* Broadcast bit set in SA?! Ignore the frame silently. */
                return;
        }
index 44c1bff..0327dec 100644 (file)
@@ -49,9 +49,13 @@ 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_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_vht_capabilities(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);
+u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_txpower_envelope(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,
                                  const u8 *addr, const u8 *trans_id);
@@ -61,6 +65,7 @@ void hostapd_get_ht_capab(struct hostapd_data *hapd,
 void hostapd_get_vht_capab(struct hostapd_data *hapd,
                           struct ieee80211_vht_capabilities *vht_cap,
                           struct ieee80211_vht_capabilities *neg_vht_cap);
+int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
 u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
                      const u8 *ht_capab);
 u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
@@ -97,6 +102,7 @@ int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
 #ifdef CONFIG_SAE
 void sae_clear_retransmit_timer(struct hostapd_data *hapd,
                                struct sta_info *sta);
+void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta);
 #else /* CONFIG_SAE */
 static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
                                              struct sta_info *sta)
@@ -104,4 +110,29 @@ static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
 }
 #endif /* CONFIG_SAE */
 
+#ifdef CONFIG_MBO
+
+u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len);
+
+u8 hostapd_mbo_ie_len(struct hostapd_data *hapd);
+
+#else /* CONFIG_MBO */
+
+static inline u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid,
+                                  size_t len)
+{
+       return eid;
+}
+
+static inline u8 hostapd_mbo_ie_len(struct hostapd_data *hapd)
+{
+       return 0;
+}
+
+#endif /* CONFIG_MBO */
+
+void ap_copy_sta_supp_op_classes(struct sta_info *sta,
+                                const u8 *supp_op_classes,
+                                size_t supp_op_classes_len);
+
 #endif /* IEEE802_11_H */
index 531a67d..b890537 100644 (file)
@@ -15,7 +15,6 @@
 
 #include "utils/common.h"
 #include "utils/eloop.h"
-#include "crypto/sha1.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "hostapd.h"
@@ -35,7 +34,7 @@ struct hostapd_cached_radius_acl {
        struct hostapd_cached_radius_acl *next;
        u32 session_timeout;
        u32 acct_interim_interval;
-       int vlan_id;
+       struct vlan_description vlan_id;
        struct hostapd_sta_wpa_psk_short *psk;
        char *identity;
        char *radius_cui;
@@ -77,29 +76,20 @@ 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)
 {
-       struct hostapd_sta_wpa_psk_short **copy_to;
-       struct hostapd_sta_wpa_psk_short *copy_from;
-
-       /* Copy PSK linked list */
-       copy_to = psk;
-       copy_from = src;
-       while (copy_from && copy_to) {
-               *copy_to = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
-               if (*copy_to == NULL)
-                       break;
-               os_memcpy(*copy_to, copy_from,
-                         sizeof(struct hostapd_sta_wpa_psk_short));
-               copy_from = copy_from->next;
-               copy_to = &((*copy_to)->next);
-       }
-       if (copy_to)
-               *copy_to = NULL;
+       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, int *vlan_id,
+                                u32 *acct_interim_interval,
+                                struct vlan_description *vlan_id,
                                 struct hostapd_sta_wpa_psk_short **psk,
                                 char **identity, char **radius_cui)
 {
@@ -165,7 +155,10 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
        if (msg == NULL)
                return -1;
 
-       radius_msg_make_authenticator(msg, addr, ETH_ALEN);
+       if (radius_msg_make_authenticator(msg) < 0) {
+               wpa_printf(MSG_INFO, "Could not make Request Authenticator");
+               goto fail;
+       }
 
        os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
        if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
@@ -213,6 +206,33 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
 
 
 /**
+ * hostapd_check_acl - Check a specified STA against accept/deny ACLs
+ * @hapd: hostapd BSS data
+ * @addr: MAC address of the STA
+ * @vlan_id: Buffer for returning VLAN ID
+ * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
+ */
+int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
+                     struct vlan_description *vlan_id)
+{
+       if (hostapd_maclist_found(hapd->conf->accept_mac,
+                                 hapd->conf->num_accept_mac, addr, vlan_id))
+               return HOSTAPD_ACL_ACCEPT;
+
+       if (hostapd_maclist_found(hapd->conf->deny_mac,
+                                 hapd->conf->num_deny_mac, addr, vlan_id))
+               return HOSTAPD_ACL_REJECT;
+
+       if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
+               return HOSTAPD_ACL_ACCEPT;
+       if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
+               return HOSTAPD_ACL_REJECT;
+
+       return HOSTAPD_ACL_PENDING;
+}
+
+
+/**
  * hostapd_allowed_address - Check whether a specified STA can be authenticated
  * @hapd: hostapd BSS data
  * @addr: MAC address of the STA
@@ -231,16 +251,19 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
  */
 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
                            const u8 *msg, size_t len, u32 *session_timeout,
-                           u32 *acct_interim_interval, int *vlan_id,
+                           u32 *acct_interim_interval,
+                           struct vlan_description *vlan_id,
                            struct hostapd_sta_wpa_psk_short **psk,
                            char **identity, char **radius_cui)
 {
+       int res;
+
        if (session_timeout)
                *session_timeout = 0;
        if (acct_interim_interval)
                *acct_interim_interval = 0;
        if (vlan_id)
-               *vlan_id = 0;
+               os_memset(vlan_id, 0, sizeof(*vlan_id));
        if (psk)
                *psk = NULL;
        if (identity)
@@ -248,18 +271,9 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
        if (radius_cui)
                *radius_cui = NULL;
 
-       if (hostapd_maclist_found(hapd->conf->accept_mac,
-                                 hapd->conf->num_accept_mac, addr, vlan_id))
-               return HOSTAPD_ACL_ACCEPT;
-
-       if (hostapd_maclist_found(hapd->conf->deny_mac,
-                                 hapd->conf->num_deny_mac, addr, vlan_id))
-               return HOSTAPD_ACL_REJECT;
-
-       if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
-               return HOSTAPD_ACL_ACCEPT;
-       if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
-               return HOSTAPD_ACL_REJECT;
+       res = hostapd_check_acl(hapd, addr, vlan_id);
+       if (res != HOSTAPD_ACL_PENDING)
+               return res;
 
        if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
 #ifdef CONFIG_NO_RADIUS
@@ -268,10 +282,9 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
                struct hostapd_acl_query_data *query;
 
                /* Check whether ACL cache has an entry for this station */
-               int 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, session_timeout,
+                                           acct_interim_interval, vlan_id, psk,
+                                           identity, radius_cui);
                if (res == HOSTAPD_ACL_ACCEPT ||
                    res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
                        return res;
@@ -419,7 +432,7 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd,
                                    struct hostapd_cached_radius_acl *cache)
 {
        int passphraselen;
-       char *passphrase, *strpassphrase;
+       char *passphrase;
        size_t i;
        struct hostapd_sta_wpa_psk_short *psk;
 
@@ -436,24 +449,42 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd,
                 */
                if (passphrase == NULL)
                        break;
+
+               /*
+                * Passphase should be 8..63 chars (to be hashed with SSID)
+                * or 64 chars hex string (no separate hashing with SSID).
+                */
+
+               if (passphraselen < MIN_PASSPHRASE_LEN ||
+                   passphraselen > MAX_PASSPHRASE_LEN + 1)
+                       goto free_pass;
+
                /*
                 * passphrase does not contain the NULL termination.
                 * Add it here as pbkdf2_sha1() requires it.
                 */
-               strpassphrase = os_zalloc(passphraselen + 1);
                psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
-               if (strpassphrase && psk) {
-                       os_memcpy(strpassphrase, passphrase, passphraselen);
-                       pbkdf2_sha1(strpassphrase,
-                                   hapd->conf->ssid.ssid,
-                                   hapd->conf->ssid.ssid_len, 4096,
-                                   psk->psk, PMK_LEN);
+               if (psk) {
+                       if ((passphraselen == MAX_PASSPHRASE_LEN + 1) &&
+                           (hexstr2bin(passphrase, psk->psk, PMK_LEN) < 0)) {
+                               hostapd_logger(hapd, cache->addr,
+                                              HOSTAPD_MODULE_RADIUS,
+                                              HOSTAPD_LEVEL_WARNING,
+                                              "invalid hex string (%d chars) in Tunnel-Password",
+                                              passphraselen);
+                               goto skip;
+                       } else if (passphraselen <= MAX_PASSPHRASE_LEN) {
+                               os_memcpy(psk->passphrase, passphrase,
+                                         passphraselen);
+                               psk->is_passphrase = 1;
+                       }
                        psk->next = cache->psk;
                        cache->psk = psk;
                        psk = NULL;
                }
-               os_free(strpassphrase);
+skip:
                os_free(psk);
+free_pass:
                os_free(passphrase);
        }
 }
@@ -478,6 +509,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
        struct hostapd_acl_query_data *query, *prev;
        struct hostapd_cached_radius_acl *cache;
        struct radius_hdr *hdr = radius_msg_get_hdr(msg);
+       int *untagged, *tagged, *notempty;
 
        query = hapd->acl_queries;
        prev = NULL;
@@ -535,7 +567,12 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
                        cache->acct_interim_interval = 0;
                }
 
-               cache->vlan_id = radius_msg_get_vlanid(msg);
+               notempty = &cache->vlan_id.notempty;
+               untagged = &cache->vlan_id.untagged;
+               tagged = cache->vlan_id.tagged;
+               *notempty = !!radius_msg_get_vlanid(msg, untagged,
+                                                   MAX_NUM_TAGGED_VLAN,
+                                                   tagged);
 
                decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
                                        msg, req, cache);
@@ -558,17 +595,18 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
                    !cache->psk)
                        cache->accepted = HOSTAPD_ACL_REJECT;
 
-               if (cache->vlan_id &&
-                   !hostapd_vlan_id_valid(hapd->conf->vlan, cache->vlan_id)) {
+               if (cache->vlan_id.notempty &&
+                   !hostapd_vlan_valid(hapd->conf->vlan, &cache->vlan_id)) {
                        hostapd_logger(hapd, query->addr,
                                       HOSTAPD_MODULE_RADIUS,
                                       HOSTAPD_LEVEL_INFO,
-                                      "Invalid VLAN ID %d received from RADIUS server",
-                                      cache->vlan_id);
-                       cache->vlan_id = 0;
+                                      "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));
                }
                if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
-                   !cache->vlan_id)
+                   !cache->vlan_id.notempty)
                        cache->accepted = HOSTAPD_ACL_REJECT;
        } else
                cache->accepted = HOSTAPD_ACL_REJECT;
@@ -640,6 +678,12 @@ void hostapd_acl_deinit(struct hostapd_data *hapd)
 
 void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
 {
+       if (psk && psk->ref) {
+               /* This will be freed when the last reference is dropped. */
+               psk->ref--;
+               return;
+       }
+
        while (psk) {
                struct hostapd_sta_wpa_psk_short *prev = psk;
                psk = psk->next;
index b66f244..71f53b9 100644 (file)
@@ -16,9 +16,12 @@ enum {
        HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
 };
 
+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, int *vlan_id,
+                           u32 *acct_interim_interval,
+                           struct vlan_description *vlan_id,
                            struct hostapd_sta_wpa_psk_short **psk,
                            char **identity, char **radius_cui);
 int hostapd_acl_init(struct hostapd_data *hapd);
index 11fde2a..5eb1060 100644 (file)
@@ -108,6 +108,29 @@ 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
index d462ac8..259413b 100644 (file)
@@ -172,6 +172,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
        case 0: /* Bits 0-7 */
                if (hapd->iconf->obss_interval)
                        *pos |= 0x01; /* Bit 0 - Coexistence management */
+               if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)
+                       *pos |= 0x04; /* Bit 2 - Extended Channel Switching */
                break;
        case 1: /* Bits 8-15 */
                if (hapd->conf->proxy_arp)
@@ -207,11 +209,21 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
                if (hapd->conf->hs20)
                        *pos |= 0x40; /* Bit 46 - WNM-Notification */
 #endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+               if (hapd->conf->mbo_enabled)
+                       *pos |= 0x40; /* Bit 46 - WNM-Notification */
+#endif /* CONFIG_MBO */
                break;
        case 6: /* Bits 48-55 */
                if (hapd->conf->ssid.utf8_ssid)
                        *pos |= 0x01; /* Bit 48 - UTF-8 SSID */
                break;
+       case 8: /* Bits 64-71 */
+               if (hapd->conf->ftm_responder)
+                       *pos |= 0x40; /* Bit 70 - FTM responder */
+               if (hapd->conf->ftm_initiator)
+                       *pos |= 0x80; /* Bit 71 - FTM initiator */
+               break;
        }
 }
 
@@ -231,6 +243,9 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
                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
        if (len < 4)
                len = 4;
@@ -239,6 +254,10 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
        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 */
        if (len < hapd->iface->extended_capa_len)
                len = hapd->iface->extended_capa_len;
        if (len == 0)
@@ -506,3 +525,62 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
 
        return pos;
 }
+
+
+#ifdef CONFIG_MBO
+
+u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+       u8 mbo[6], *mbo_pos = mbo;
+       u8 *pos = eid;
+
+       if (!hapd->conf->mbo_enabled)
+               return eid;
+
+       *mbo_pos++ = MBO_ATTR_ID_AP_CAPA_IND;
+       *mbo_pos++ = 1;
+       /* Not Cellular aware */
+       *mbo_pos++ = 0;
+
+       if (hapd->mbo_assoc_disallow) {
+               *mbo_pos++ = MBO_ATTR_ID_ASSOC_DISALLOW;
+               *mbo_pos++ = 1;
+               *mbo_pos++ = hapd->mbo_assoc_disallow;
+       }
+
+       pos += mbo_add_ie(pos, len, mbo, mbo_pos - mbo);
+
+       return pos;
+}
+
+
+u8 hostapd_mbo_ie_len(struct hostapd_data *hapd)
+{
+       if (!hapd->conf->mbo_enabled)
+               return 0;
+
+       /*
+        * MBO IE header (6) + Capability Indication attribute (3) +
+        * Association Disallowed attribute (3) = 12
+        */
+       return 6 + 3 + (hapd->mbo_assoc_disallow ? 3 : 0);
+}
+
+#endif /* CONFIG_MBO */
+
+
+void ap_copy_sta_supp_op_classes(struct sta_info *sta,
+                                const u8 *supp_op_classes,
+                                size_t supp_op_classes_len)
+{
+       if (!supp_op_classes)
+               return;
+       os_free(sta->supp_op_classes);
+       sta->supp_op_classes = os_malloc(1 + supp_op_classes_len);
+       if (!sta->supp_op_classes)
+               return;
+
+       sta->supp_op_classes[0] = supp_op_classes_len;
+       os_memcpy(sta->supp_op_classes + 1, supp_op_classes,
+                 supp_op_classes_len);
+}
index 5bf1b5d..f30f63b 100644 (file)
 #include "sta_info.h"
 #include "beacon.h"
 #include "ieee802_11.h"
+#include "dfs.h"
 
 
-u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts)
 {
        struct ieee80211_vht_capabilities *cap;
        struct hostapd_hw_modes *mode = hapd->iface->current_mode;
@@ -49,6 +50,18 @@ u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
        cap->vht_capabilities_info = host_to_le32(
                hapd->iface->conf->vht_capab);
 
+       if (nsts != 0) {
+               u32 hapd_nsts;
+
+               hapd_nsts = le_to_host32(cap->vht_capabilities_info);
+               hapd_nsts = (hapd_nsts >> VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+               cap->vht_capabilities_info &=
+                       ~(host_to_le32(hapd_nsts <<
+                                      VHT_CAP_BEAMFORMEE_STS_OFFSET));
+               cap->vht_capabilities_info |=
+                       host_to_le32(nsts << VHT_CAP_BEAMFORMEE_STS_OFFSET);
+       }
+
        /* Supported MCS set comes from hw */
        os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
 
@@ -80,6 +93,26 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
                hapd->iconf->vht_oper_centr_freq_seg1_idx;
 
        oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
+       if (hapd->iconf->vht_oper_chwidth == 2) {
+               /*
+                * Convert 160 MHz channel width to new style as interop
+                * workaround.
+                */
+               oper->vht_op_info_chwidth = 1;
+               oper->vht_op_info_chan_center_freq_seg1_idx =
+                       oper->vht_op_info_chan_center_freq_seg0_idx;
+               if (hapd->iconf->channel <
+                   hapd->iconf->vht_oper_centr_freq_seg0_idx)
+                       oper->vht_op_info_chan_center_freq_seg0_idx -= 8;
+               else
+                       oper->vht_op_info_chan_center_freq_seg0_idx += 8;
+       } else if (hapd->iconf->vht_oper_chwidth == 3) {
+               /*
+                * Convert 80+80 MHz channel width to new style as interop
+                * workaround.
+                */
+               oper->vht_op_info_chwidth = 1;
+       }
 
        /* VHT Basic MCS set comes from hw */
        /* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
@@ -131,6 +164,171 @@ 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 VHT_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 VHT_CHANWIDTH_80MHZ:
+               /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
+               tx_pwr_count = 2;
+               break;
+       case VHT_CHANWIDTH_80P80MHZ:
+       case VHT_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)
 {
@@ -212,7 +410,7 @@ u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
        WPA_PUT_BE32(pos, (OUI_BROADCOM << 8) | VENDOR_VHT_TYPE);
        pos += 4;
        *pos++ = VENDOR_VHT_SUBTYPE;
-       pos = hostapd_eid_vht_capabilities(hapd, pos);
+       pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
        pos = hostapd_eid_vht_operation(hapd, pos);
 
        return pos;
index 0f2d428..80ff996 100644 (file)
@@ -34,6 +34,9 @@
 #include "ieee802_1x.h"
 
 
+#ifdef CONFIG_HS20
+static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx);
+#endif /* CONFIG_HS20 */
 static void ieee802_1x_finished(struct hostapd_data *hapd,
                                struct sta_info *sta, int success,
                                int remediation);
@@ -219,7 +222,7 @@ static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
                   MAC2STR(sta->addr));
 
 #ifndef CONFIG_NO_VLAN
-       if (sta->vlan_id > 0 && sta->vlan_id <= MAX_VLAN_ID) {
+       if (sta->vlan_id > 0) {
                wpa_printf(MSG_ERROR, "Using WEP with vlans is not supported.");
                return;
        }
@@ -402,7 +405,16 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
        char buf[128];
 
        if (!hostapd_config_get_radius_attr(req_attr,
+                                           RADIUS_ATTR_SERVICE_TYPE) &&
+           !radius_msg_add_attr_int32(msg, RADIUS_ATTR_SERVICE_TYPE,
+                                      RADIUS_SERVICE_TYPE_FRAMED)) {
+               wpa_printf(MSG_ERROR, "Could not add Service-Type");
+               return -1;
+       }
+
+       if (!hostapd_config_get_radius_attr(req_attr,
                                            RADIUS_ATTR_NAS_PORT) &&
+           sta->aid > 0 &&
            !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
                wpa_printf(MSG_ERROR, "Could not add NAS-Port");
                return -1;
@@ -435,9 +447,9 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
                return -1;
        }
 
-       if (sta->acct_session_id_hi || sta->acct_session_id_lo) {
-               os_snprintf(buf, sizeof(buf), "%08X-%08X",
-                           sta->acct_session_id_hi, sta->acct_session_id_lo);
+       if (sta->acct_session_id) {
+               os_snprintf(buf, sizeof(buf), "%016llX",
+                           (unsigned long long) sta->acct_session_id);
                if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
                                         (u8 *) buf, os_strlen(buf))) {
                        wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id");
@@ -445,6 +457,21 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
                }
        }
 
+       if ((hapd->conf->wpa & 2) &&
+           !hapd->conf->disable_pmksa_caching &&
+           sta->eapol_sm && sta->eapol_sm->acct_multi_session_id) {
+               os_snprintf(buf, sizeof(buf), "%016llX",
+                           (unsigned long long)
+                           sta->eapol_sm->acct_multi_session_id);
+               if (!radius_msg_add_attr(
+                           msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
+                           (u8 *) buf, os_strlen(buf))) {
+                       wpa_printf(MSG_INFO,
+                                  "Could not add Acct-Multi-Session-Id");
+                       return -1;
+               }
+       }
+
 #ifdef CONFIG_IEEE80211R
        if (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
            sta->wpa_sm &&
@@ -475,6 +502,7 @@ int add_common_radius_attr(struct hostapd_data *hapd,
 {
        char buf[128];
        struct hostapd_radius_attr *attr;
+       int len;
 
        if (!hostapd_config_get_radius_attr(req_attr,
                                            RADIUS_ATTR_NAS_IP_ADDRESS) &&
@@ -506,15 +534,15 @@ int add_common_radius_attr(struct hostapd_data *hapd,
                return -1;
        }
 
-       os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
-                   MAC2STR(hapd->own_addr),
-                   wpa_ssid_txt(hapd->conf->ssid.ssid,
-                                hapd->conf->ssid.ssid_len));
-       buf[sizeof(buf) - 1] = '\0';
+       len = os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":",
+                         MAC2STR(hapd->own_addr));
+       os_memcpy(&buf[len], hapd->conf->ssid.ssid,
+                 hapd->conf->ssid.ssid_len);
+       len += hapd->conf->ssid.ssid_len;
        if (!hostapd_config_get_radius_attr(req_attr,
                                            RADIUS_ATTR_CALLED_STATION_ID) &&
            !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
-                                (u8 *) buf, os_strlen(buf))) {
+                                (u8 *) buf, len)) {
                wpa_printf(MSG_ERROR, "Could not add Called-Station-Id");
                return -1;
        }
@@ -583,7 +611,10 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
                return;
        }
 
-       radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
+       if (radius_msg_make_authenticator(msg) < 0) {
+               wpa_printf(MSG_INFO, "Could not make Request Authenticator");
+               goto fail;
+       }
 
        if (sm->identity &&
            !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
@@ -831,6 +862,29 @@ ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
 }
 
 
+static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf,
+                                 size_t len)
+{
+       if (sta->pending_eapol_rx) {
+               wpabuf_free(sta->pending_eapol_rx->buf);
+       } else {
+               sta->pending_eapol_rx =
+                       os_malloc(sizeof(*sta->pending_eapol_rx));
+               if (!sta->pending_eapol_rx)
+                       return;
+       }
+
+       sta->pending_eapol_rx->buf = wpabuf_alloc_copy(buf, len);
+       if (!sta->pending_eapol_rx->buf) {
+               os_free(sta->pending_eapol_rx);
+               sta->pending_eapol_rx = NULL;
+               return;
+       }
+
+       os_get_reltime(&sta->pending_eapol_rx->rx_time);
+}
+
+
 /**
  * ieee802_1x_receive - Process the EAPOL frames from the Supplicant
  * @hapd: hostapd BSS data
@@ -861,6 +915,13 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
                     !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
                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
+                                  " for later use", MAC2STR(sta->addr));
+                       ieee802_1x_save_eapol(sta, buf, len);
+               }
+
                return;
        }
 
@@ -1047,7 +1108,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
                 * Clear any possible EAPOL authenticator state to support
                 * reassociation change from WPS to PSK.
                 */
-               ieee802_1x_free_station(sta);
+               ieee802_1x_free_station(hapd, sta);
                return;
        }
 
@@ -1058,7 +1119,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
                 * Clear any possible EAPOL authenticator state to support
                 * reassociation change from WPA-EAP to PSK.
                 */
-               ieee802_1x_free_station(sta);
+               ieee802_1x_free_station(hapd, sta);
                return;
        }
 
@@ -1106,6 +1167,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
                sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
                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);
                /* TODO: get vlan_id from R0KH using RRB message */
@@ -1128,7 +1190,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
                sta->eapol_sm->authFail = FALSE;
                if (sta->eapol_sm->eap)
                        eap_sm_notify_cached(sta->eapol_sm->eap);
-               pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm);
+               pmksa_cache_to_eapol_data(hapd, pmksa, sta->eapol_sm);
                ap_sta_bind_vlan(hapd, sta);
        } else {
                if (reassoc) {
@@ -1144,10 +1206,20 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
 }
 
 
-void ieee802_1x_free_station(struct sta_info *sta)
+void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta)
 {
        struct eapol_state_machine *sm = sta->eapol_sm;
 
+#ifdef CONFIG_HS20
+       eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
+#endif /* CONFIG_HS20 */
+
+       if (sta->pending_eapol_rx) {
+               wpabuf_free(sta->pending_eapol_rx->buf);
+               os_free(sta->pending_eapol_rx);
+               sta->pending_eapol_rx = NULL;
+       }
+
        if (sm == NULL)
                return;
 
@@ -1156,10 +1228,8 @@ void ieee802_1x_free_station(struct sta_info *sta)
 #ifndef CONFIG_NO_RADIUS
        radius_msg_free(sm->last_recv_radius);
        radius_free_class(&sm->radius_class);
-       wpabuf_free(sm->radius_cui);
 #endif /* CONFIG_NO_RADIUS */
 
-       os_free(sm->identity);
        eapol_auth_free(sm);
 }
 
@@ -1592,10 +1662,16 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
        struct hostapd_data *hapd = data;
        struct sta_info *sta;
        u32 session_timeout = 0, termination_action, acct_interim_interval;
-       int session_timeout_set, vlan_id = 0;
+       int session_timeout_set;
        struct eapol_state_machine *sm;
        int override_eapReq = 0;
        struct radius_hdr *hdr = radius_msg_get_hdr(msg);
+       struct vlan_description vlan_desc;
+#ifndef CONFIG_NO_VLAN
+       int *untagged, *tagged, *notempty;
+#endif /* CONFIG_NO_VLAN */
+
+       os_memset(&vlan_desc, 0, sizeof(vlan_desc));
 
        sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
        if (sm == NULL) {
@@ -1659,27 +1735,32 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
 
        switch (hdr->code) {
        case RADIUS_CODE_ACCESS_ACCEPT:
-               if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
-                       vlan_id = 0;
 #ifndef CONFIG_NO_VLAN
-               else
-                       vlan_id = radius_msg_get_vlanid(msg);
-               if (vlan_id > 0 &&
-                   hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
-                       hostapd_logger(hapd, sta->addr,
-                                      HOSTAPD_MODULE_RADIUS,
-                                      HOSTAPD_LEVEL_INFO,
-                                      "VLAN ID %d", vlan_id);
-               } else if (vlan_id > 0) {
+               if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED) {
+                       notempty = &vlan_desc.notempty;
+                       untagged = &vlan_desc.untagged;
+                       tagged = vlan_desc.tagged;
+                       *notempty = !!radius_msg_get_vlanid(msg, untagged,
+                                                           MAX_NUM_TAGGED_VLAN,
+                                                           tagged);
+               }
+
+               if (vlan_desc.notempty &&
+                   !hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
                        sta->eapol_sm->authFail = TRUE;
                        hostapd_logger(hapd, sta->addr,
                                       HOSTAPD_MODULE_RADIUS,
                                       HOSTAPD_LEVEL_INFO,
-                                      "Invalid VLAN ID %d received from RADIUS server",
-                                      vlan_id);
+                                      "Invalid VLAN %d%s received from RADIUS server",
+                                      vlan_desc.untagged,
+                                      vlan_desc.tagged[0] ? "+" : "");
+                       os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+                       ap_sta_set_vlan(hapd, sta, &vlan_desc);
                        break;
-               } else if (hapd->conf->ssid.dynamic_vlan ==
-                          DYNAMIC_VLAN_REQUIRED) {
+               }
+
+               if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
+                   !vlan_desc.notempty) {
                        sta->eapol_sm->authFail = TRUE;
                        hostapd_logger(hapd, sta->addr,
                                       HOSTAPD_MODULE_IEEE8021X,
@@ -1690,7 +1771,18 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
                }
 #endif /* CONFIG_NO_VLAN */
 
-               sta->vlan_id = vlan_id;
+               if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0)
+                       break;
+
+#ifndef CONFIG_NO_VLAN
+               if (sta->vlan_id > 0) {
+                       hostapd_logger(hapd, sta->addr,
+                                      HOSTAPD_MODULE_RADIUS,
+                                      HOSTAPD_LEVEL_INFO,
+                                      "VLAN ID %d", sta->vlan_id);
+               }
+#endif /* CONFIG_NO_VLAN */
+
                if ((sta->flags & WLAN_STA_ASSOC) &&
                    ap_sta_bind_vlan(hapd, sta) < 0)
                        break;
@@ -1715,15 +1807,6 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
                ieee802_1x_check_hs20(hapd, sta, msg,
                                      session_timeout_set ?
                                      (int) session_timeout : -1);
-               if (sm->eap_if->eapKeyAvailable && !sta->remediation &&
-                   !sta->hs20_deauth_requested &&
-                   wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt,
-                                      session_timeout_set ?
-                                      (int) session_timeout : -1, sm) == 0) {
-                       hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-                                      HOSTAPD_LEVEL_DEBUG,
-                                      "Added PMKSA cache entry");
-               }
                break;
        case RADIUS_CODE_ACCESS_REJECT:
                sm->eap_if->aaaFail = TRUE;
@@ -2190,7 +2273,7 @@ void ieee802_1x_deinit(struct hostapd_data *hapd)
 {
        eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
 
-       if (hapd->driver != NULL &&
+       if (hapd->driver && hapd->drv_priv &&
            (hapd->conf->ieee802_1x || hapd->conf->wpa))
                hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
 
@@ -2495,12 +2578,12 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
                          /* TODO: dot1xAuthSessionOctetsTx */
                          /* TODO: dot1xAuthSessionFramesRx */
                          /* TODO: dot1xAuthSessionFramesTx */
-                         "dot1xAuthSessionId=%08X-%08X\n"
+                         "dot1xAuthSessionId=%016llX\n"
                          "dot1xAuthSessionAuthenticMethod=%d\n"
                          "dot1xAuthSessionTime=%u\n"
                          "dot1xAuthSessionTerminateCause=999\n"
                          "dot1xAuthSessionUserName=%s\n",
-                         sta->acct_session_id_hi, sta->acct_session_id_lo,
+                         (unsigned long long) sta->acct_session_id,
                          (wpa_key_mgmt_wpa_ieee8021x(
                                   wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
                          1 : 2,
@@ -2510,11 +2593,11 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
                return len;
        len += ret;
 
-       if (sm->acct_multi_session_id_hi) {
+       if (sm->acct_multi_session_id) {
                ret = os_snprintf(buf + len, buflen - len,
-                                 "authMultiSessionId=%08X+%08X\n",
-                                 sm->acct_multi_session_id_hi,
-                                 sm->acct_multi_session_id_lo);
+                                 "authMultiSessionId=%016llX\n",
+                                 (unsigned long long)
+                                 sm->acct_multi_session_id);
                if (os_snprintf_error(buflen - len, ret))
                        return len;
                len += ret;
@@ -2535,6 +2618,34 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
 }
 
 
+#ifdef CONFIG_HS20
+static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx)
+{
+       struct hostapd_data *hapd = eloop_ctx;
+       struct sta_info *sta = timeout_ctx;
+
+       if (sta->remediation) {
+               wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
+                          MACSTR " to indicate Subscription Remediation",
+                          MAC2STR(sta->addr));
+               hs20_send_wnm_notification(hapd, sta->addr,
+                                          sta->remediation_method,
+                                          sta->remediation_url);
+               os_free(sta->remediation_url);
+               sta->remediation_url = NULL;
+       }
+
+       if (sta->hs20_deauth_req) {
+               wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
+                          MACSTR " to indicate imminent deauthentication",
+                          MAC2STR(sta->addr));
+               hs20_send_wnm_notification_deauth_req(hapd, sta->addr,
+                                                     sta->hs20_deauth_req);
+       }
+}
+#endif /* CONFIG_HS20 */
+
+
 static void ieee802_1x_finished(struct hostapd_data *hapd,
                                struct sta_info *sta, int success,
                                int remediation)
@@ -2554,26 +2665,12 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
                sta->remediation_method = 1; /* SOAP-XML SPP */
        }
 
-       if (success) {
-               if (sta->remediation) {
-                       wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification "
-                                  "to " MACSTR " to indicate Subscription "
-                                  "Remediation",
-                                  MAC2STR(sta->addr));
-                       hs20_send_wnm_notification(hapd, sta->addr,
-                                                  sta->remediation_method,
-                                                  sta->remediation_url);
-                       os_free(sta->remediation_url);
-                       sta->remediation_url = NULL;
-               }
-
-               if (sta->hs20_deauth_req) {
-                       wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification "
-                                  "to " MACSTR " to indicate imminent "
-                                  "deauthentication", MAC2STR(sta->addr));
-                       hs20_send_wnm_notification_deauth_req(
-                               hapd, sta->addr, sta->hs20_deauth_req);
-               }
+       if (success && (sta->remediation || sta->hs20_deauth_req)) {
+               wpa_printf(MSG_DEBUG, "HS 2.0: Schedule WNM-Notification to "
+                          MACSTR " in 100 ms", MAC2STR(sta->addr));
+               eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
+               eloop_register_timeout(0, 100000, ieee802_1x_wnm_notif_send,
+                                      hapd, sta);
        }
 #endif /* CONFIG_HS20 */
 
@@ -2584,7 +2681,7 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
                session_timeout = dot11RSNAConfigPMKLifetime;
        if (success && key && len >= PMK_LEN && !sta->remediation &&
            !sta->hs20_deauth_requested &&
-           wpa_auth_pmksa_add(sta->wpa_sm, key, session_timeout,
+           wpa_auth_pmksa_add(sta->wpa_sm, key, len, session_timeout,
                               sta->eapol_sm) == 0) {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
                               HOSTAPD_LEVEL_DEBUG,
index 14d6955..ec80199 100644 (file)
@@ -21,7 +21,7 @@ struct radius_msg;
 void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
                        size_t len);
 void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta);
-void ieee802_1x_free_station(struct sta_info *sta);
+void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta);
 
 void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta);
 void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
diff --git a/libeap/src/ap/mbo_ap.c b/libeap/src/ap/mbo_ap.c
new file mode 100644 (file)
index 0000000..43b0bf1
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * hostapd - MBO
+ * Copyright (c) 2016, Qualcomm Atheros, Inc.
+ *
+ * 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_defs.h"
+#include "common/ieee802_11_common.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "mbo_ap.h"
+
+
+void mbo_ap_sta_free(struct sta_info *sta)
+{
+       struct mbo_non_pref_chan_info *info, *prev;
+
+       info = sta->non_pref_chan;
+       sta->non_pref_chan = NULL;
+       while (info) {
+               prev = info;
+               info = info->next;
+               os_free(prev);
+       }
+}
+
+
+static void mbo_ap_parse_non_pref_chan(struct sta_info *sta,
+                                      const u8 *buf, size_t len)
+{
+       struct mbo_non_pref_chan_info *info, *tmp;
+       char channels[200], *pos, *end;
+       size_t num_chan, i;
+       int ret;
+
+       if (len <= 3)
+               return; /* Not enough room for any channels */
+
+       num_chan = len - 3;
+       info = os_zalloc(sizeof(*info) + num_chan);
+       if (!info)
+               return;
+       info->op_class = buf[0];
+       info->pref = buf[len - 2];
+       info->reason_code = buf[len - 1];
+       info->num_channels = num_chan;
+       buf++;
+       os_memcpy(info->channels, buf, num_chan);
+       if (!sta->non_pref_chan) {
+               sta->non_pref_chan = info;
+       } else {
+               tmp = sta->non_pref_chan;
+               while (tmp->next)
+                       tmp = tmp->next;
+               tmp->next = info;
+       }
+
+       pos = channels;
+       end = pos + sizeof(channels);
+       *pos = '\0';
+       for (i = 0; i < num_chan; i++) {
+               ret = os_snprintf(pos, end - pos, "%s%u",
+                                 i == 0 ? "" : " ", buf[i]);
+               if (os_snprintf_error(end - pos, ret)) {
+                       *pos = '\0';
+                       break;
+               }
+               pos += ret;
+       }
+
+       wpa_printf(MSG_DEBUG, "MBO: STA " MACSTR
+                  " non-preferred channel list (op class %u, pref %u, reason code %u, channels %s)",
+                  MAC2STR(sta->addr), info->op_class, info->pref,
+                  info->reason_code, channels);
+}
+
+
+void mbo_ap_check_sta_assoc(struct hostapd_data *hapd, struct sta_info *sta,
+                           struct ieee802_11_elems *elems)
+{
+       const u8 *pos, *attr, *end;
+       size_t len;
+
+       if (!hapd->conf->mbo_enabled || !elems->mbo)
+               return;
+
+       pos = elems->mbo + 4;
+       len = elems->mbo_len - 4;
+       wpa_hexdump(MSG_DEBUG, "MBO: Association Request attributes", pos, len);
+
+       attr = get_ie(pos, len, MBO_ATTR_ID_CELL_DATA_CAPA);
+       if (attr && attr[1] >= 1)
+               sta->cell_capa = attr[2];
+
+       mbo_ap_sta_free(sta);
+       end = pos + len;
+       while (end - pos > 1) {
+               u8 ie_len = pos[1];
+
+               if (2 + ie_len > end - pos)
+                       break;
+
+               if (pos[0] == MBO_ATTR_ID_NON_PREF_CHAN_REPORT)
+                       mbo_ap_parse_non_pref_chan(sta, pos + 2, ie_len);
+               pos += 2 + pos[1];
+       }
+}
+
+
+int mbo_ap_get_info(struct sta_info *sta, char *buf, size_t buflen)
+{
+       char *pos = buf, *end = buf + buflen;
+       int ret;
+       struct mbo_non_pref_chan_info *info;
+       u8 i;
+       unsigned int count = 0;
+
+       if (!sta->cell_capa)
+               return 0;
+
+       ret = os_snprintf(pos, end - pos, "mbo_cell_capa=%u\n", sta->cell_capa);
+       if (os_snprintf_error(end - pos, ret))
+               return pos - buf;
+       pos += ret;
+
+       for (info = sta->non_pref_chan; info; info = info->next) {
+               char *pos2 = pos;
+
+               ret = os_snprintf(pos2, end - pos2,
+                                 "non_pref_chan[%u]=%u:%u:%u:",
+                                 count, info->op_class, info->pref,
+                                 info->reason_code);
+               count++;
+               if (os_snprintf_error(end - pos2, ret))
+                       break;
+               pos2 += ret;
+
+               for (i = 0; i < info->num_channels; i++) {
+                       ret = os_snprintf(pos2, end - pos2, "%u%s",
+                                         info->channels[i],
+                                         i + 1 < info->num_channels ?
+                                         "," : "");
+                       if (os_snprintf_error(end - pos2, ret)) {
+                               pos2 = NULL;
+                               break;
+                       }
+                       pos2 += ret;
+               }
+
+               if (!pos2)
+                       break;
+               ret = os_snprintf(pos2, end - pos2, "\n");
+               if (os_snprintf_error(end - pos2, ret))
+                       break;
+               pos2 += ret;
+               pos = pos2;
+       }
+
+       return pos - buf;
+}
+
+
+static void mbo_ap_wnm_notif_req_cell_capa(struct sta_info *sta,
+                                          const u8 *buf, size_t len)
+{
+       if (len < 1)
+               return;
+       wpa_printf(MSG_DEBUG, "MBO: STA " MACSTR
+                  " updated cellular data capability: %u",
+                  MAC2STR(sta->addr), buf[0]);
+       sta->cell_capa = buf[0];
+}
+
+
+static void mbo_ap_wnm_notif_req_elem(struct sta_info *sta, u8 type,
+                                     const u8 *buf, size_t len,
+                                     int *first_non_pref_chan)
+{
+       switch (type) {
+       case WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT:
+               if (*first_non_pref_chan) {
+                       /*
+                        * Need to free the previously stored entries now to
+                        * allow the update to replace all entries.
+                        */
+                       *first_non_pref_chan = 0;
+                       mbo_ap_sta_free(sta);
+               }
+               mbo_ap_parse_non_pref_chan(sta, buf, len);
+               break;
+       case WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA:
+               mbo_ap_wnm_notif_req_cell_capa(sta, buf, len);
+               break;
+       default:
+               wpa_printf(MSG_DEBUG,
+                          "MBO: Ignore unknown WNM Notification WFA subelement %u",
+                          type);
+               break;
+       }
+}
+
+
+void mbo_ap_wnm_notification_req(struct hostapd_data *hapd, const u8 *addr,
+                                const u8 *buf, size_t len)
+{
+       const u8 *pos, *end;
+       u8 ie_len;
+       struct sta_info *sta;
+       int first_non_pref_chan = 1;
+
+       if (!hapd->conf->mbo_enabled)
+               return;
+
+       sta = ap_get_sta(hapd, addr);
+       if (!sta)
+               return;
+
+       pos = buf;
+       end = buf + len;
+
+       while (end - pos > 1) {
+               ie_len = pos[1];
+
+               if (2 + ie_len > end - pos)
+                       break;
+
+               if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
+                   ie_len >= 4 && WPA_GET_BE24(pos + 2) == OUI_WFA)
+                       mbo_ap_wnm_notif_req_elem(sta, pos[5],
+                                                 pos + 6, ie_len - 4,
+                                                 &first_non_pref_chan);
+               else
+                       wpa_printf(MSG_DEBUG,
+                                  "MBO: Ignore unknown WNM Notification element %u (len=%u)",
+                                  pos[0], pos[1]);
+
+               pos += 2 + pos[1];
+       }
+}
diff --git a/libeap/src/ap/mbo_ap.h b/libeap/src/ap/mbo_ap.h
new file mode 100644 (file)
index 0000000..9f37f28
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * MBO related functions and structures
+ * Copyright (c) 2016, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MBO_AP_H
+#define MBO_AP_H
+
+struct hostapd_data;
+struct sta_info;
+struct ieee802_11_elems;
+
+#ifdef CONFIG_MBO
+
+void mbo_ap_check_sta_assoc(struct hostapd_data *hapd, struct sta_info *sta,
+                           struct ieee802_11_elems *elems);
+int mbo_ap_get_info(struct sta_info *sta, char *buf, size_t buflen);
+void mbo_ap_wnm_notification_req(struct hostapd_data *hapd, const u8 *addr,
+                                const u8 *buf, size_t len);
+void mbo_ap_sta_free(struct sta_info *sta);
+
+#else /* CONFIG_MBO */
+
+static inline void mbo_ap_check_sta_assoc(struct hostapd_data *hapd,
+                                         struct sta_info *sta,
+                                         struct ieee802_11_elems *elems)
+{
+}
+
+static inline int mbo_ap_get_info(struct sta_info *sta, char *buf,
+                                 size_t buflen)
+{
+       return 0;
+}
+
+static inline void mbo_ap_wnm_notification_req(struct hostapd_data *hapd,
+                                              const u8 *addr,
+                                              const u8 *buf, size_t len)
+{
+}
+
+static inline void mbo_ap_sta_free(struct sta_info *sta)
+{
+}
+
+#endif /* CONFIG_MBO */
+
+#endif /* MBO_AP_H */
index 4a87721..3c086bf 100644 (file)
@@ -17,6 +17,7 @@
 #include "ap_drv_ops.h"
 #include "list.h"
 #include "x_snoop.h"
+#include "ndisc_snoop.h"
 
 struct ip6addr {
        struct in6_addr addr;
diff --git a/libeap/src/ap/neighbor_db.c b/libeap/src/ap/neighbor_db.c
new file mode 100644 (file)
index 0000000..a2efff6
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * hostapd / Neighboring APs DB
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ *
+ * 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 "hostapd.h"
+#include "neighbor_db.h"
+
+
+struct hostapd_neighbor_entry *
+hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
+                    const struct wpa_ssid_value *ssid)
+{
+       struct hostapd_neighbor_entry *nr;
+
+       dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
+                        list) {
+               if (os_memcmp(bssid, nr->bssid, ETH_ALEN) == 0 &&
+                   (!ssid ||
+                    (ssid->ssid_len == nr->ssid.ssid_len &&
+                     os_memcmp(ssid->ssid, nr->ssid.ssid,
+                               ssid->ssid_len) == 0)))
+                       return nr;
+       }
+       return NULL;
+}
+
+
+static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
+{
+       wpabuf_free(nr->nr);
+       nr->nr = NULL;
+       wpabuf_free(nr->lci);
+       nr->lci = NULL;
+       wpabuf_free(nr->civic);
+       nr->civic = NULL;
+       os_memset(nr->bssid, 0, sizeof(nr->bssid));
+       os_memset(&nr->ssid, 0, sizeof(nr->ssid));
+}
+
+
+static struct hostapd_neighbor_entry *
+hostapd_neighbor_add(struct hostapd_data *hapd)
+{
+       struct hostapd_neighbor_entry *nr;
+
+       nr = os_zalloc(sizeof(struct hostapd_neighbor_entry));
+       if (!nr)
+               return NULL;
+
+       dl_list_add(&hapd->nr_db, &nr->list);
+
+       return nr;
+}
+
+
+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,
+                        const struct wpabuf *civic)
+{
+       struct hostapd_neighbor_entry *entry;
+
+       entry = hostapd_neighbor_get(hapd, bssid, ssid);
+       if (!entry)
+               entry = hostapd_neighbor_add(hapd);
+       if (!entry)
+               return -1;
+
+       hostapd_neighbor_clear_entry(entry);
+
+       os_memcpy(entry->bssid, bssid, ETH_ALEN);
+       os_memcpy(&entry->ssid, ssid, sizeof(entry->ssid));
+
+       entry->nr = wpabuf_dup(nr);
+       if (!entry->nr)
+               goto fail;
+
+       if (lci) {
+               entry->lci = wpabuf_dup(lci);
+               if (!entry->lci || os_get_time(&entry->lci_date))
+                       goto fail;
+       }
+
+       if (civic) {
+               entry->civic = wpabuf_dup(civic);
+               if (!entry->civic)
+                       goto fail;
+       }
+
+       return 0;
+
+fail:
+       hostapd_neighbor_remove(hapd, bssid, ssid);
+       return -1;
+}
+
+
+int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
+                           const struct wpa_ssid_value *ssid)
+{
+       struct hostapd_neighbor_entry *nr;
+
+       nr = hostapd_neighbor_get(hapd, bssid, ssid);
+       if (!nr)
+               return -1;
+
+       hostapd_neighbor_clear_entry(nr);
+       dl_list_del(&nr->list);
+       os_free(nr);
+
+       return 0;
+}
+
+
+void hostpad_free_neighbor_db(struct hostapd_data *hapd)
+{
+       struct hostapd_neighbor_entry *nr, *prev;
+
+       dl_list_for_each_safe(nr, prev, &hapd->nr_db,
+                             struct hostapd_neighbor_entry, list) {
+               hostapd_neighbor_clear_entry(nr);
+               dl_list_del(&nr->list);
+               os_free(nr);
+       }
+}
diff --git a/libeap/src/ap/neighbor_db.h b/libeap/src/ap/neighbor_db.h
new file mode 100644 (file)
index 0000000..c22e043
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * hostapd / Neighboring APs DB
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef NEIGHBOR_DB_H
+#define NEIGHBOR_DB_H
+
+struct hostapd_neighbor_entry *
+hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
+                    const struct wpa_ssid_value *ssid);
+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,
+                        const struct wpabuf *civic);
+int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
+                           const struct wpa_ssid_value *ssid);
+void hostpad_free_neighbor_db(struct hostapd_data *hapd);
+
+#endif /* NEIGHBOR_DB_H */
index 877affe..d610e7e 100644 (file)
@@ -38,6 +38,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
 
 static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
 {
+       os_free(entry->vlan_desc);
        os_free(entry->identity);
        wpabuf_free(entry->cui);
 #ifndef CONFIG_NO_RADIUS
@@ -91,6 +92,20 @@ void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
 }
 
 
+/**
+ * pmksa_cache_auth_flush - Flush all PMKSA cache entries
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ */
+void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa)
+{
+       while (pmksa->pmksa) {
+               wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry for "
+                          MACSTR, MAC2STR(pmksa->pmksa->spa));
+               pmksa_cache_free_entry(pmksa, pmksa->pmksa);
+       }
+}
+
+
 static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
 {
        struct rsn_pmksa_cache *pmksa = eloop_ctx;
@@ -126,6 +141,8 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
 static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
                                        struct eapol_state_machine *eapol)
 {
+       struct vlan_description *vlan_desc;
+
        if (eapol == NULL)
                return;
 
@@ -146,14 +163,22 @@ static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
 #endif /* CONFIG_NO_RADIUS */
 
        entry->eap_type_authsrv = eapol->eap_type_authsrv;
-       entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id;
 
-       entry->acct_multi_session_id_hi = eapol->acct_multi_session_id_hi;
-       entry->acct_multi_session_id_lo = eapol->acct_multi_session_id_lo;
+       vlan_desc = ((struct sta_info *) eapol->sta)->vlan_desc;
+       if (vlan_desc && vlan_desc->notempty) {
+               entry->vlan_desc = os_zalloc(sizeof(struct vlan_description));
+               if (entry->vlan_desc)
+                       *entry->vlan_desc = *vlan_desc;
+       } else {
+               entry->vlan_desc = NULL;
+       }
+
+       entry->acct_multi_session_id = eapol->acct_multi_session_id;
 }
 
 
-void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
+void pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
+                              struct rsn_pmksa_cache_entry *entry,
                               struct eapol_state_machine *eapol)
 {
        if (entry == NULL || eapol == NULL)
@@ -186,10 +211,11 @@ void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
        }
 
        eapol->eap_type_authsrv = entry->eap_type_authsrv;
-       ((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id;
+#ifndef CONFIG_NO_VLAN
+       ap_sta_set_vlan(hapd, eapol->sta, entry->vlan_desc);
+#endif /* CONFIG_NO_VLAN */
 
-       eapol->acct_multi_session_id_hi = entry->acct_multi_session_id_hi;
-       eapol->acct_multi_session_id_lo = entry->acct_multi_session_id_lo;
+       eapol->acct_multi_session_id = entry->acct_multi_session_id;
 }
 
 
@@ -234,6 +260,7 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
  * @pmk: The new pairwise master key
  * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
+ * @pmkid: Calculated PMKID
  * @kck: Key confirmation key or %NULL if not yet derived
  * @kck_len: KCK length in bytes
  * @aa: Authenticator address
@@ -250,7 +277,7 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
  */
 struct rsn_pmksa_cache_entry *
 pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
-                    const u8 *pmk, size_t pmk_len,
+                    const u8 *pmk, size_t pmk_len, const u8 *pmkid,
                     const u8 *kck, size_t kck_len,
                     const u8 *aa, const u8 *spa, int session_timeout,
                     struct eapol_state_machine *eapol, int akmp)
@@ -258,7 +285,7 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
        struct rsn_pmksa_cache_entry *entry, *pos;
        struct os_reltime now;
 
-       if (pmk_len > PMK_LEN)
+       if (pmk_len > PMK_LEN_MAX)
                return NULL;
 
        if (wpa_key_mgmt_suite_b(akmp) && !kck)
@@ -269,7 +296,9 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
                return NULL;
        os_memcpy(entry->pmk, pmk, pmk_len);
        entry->pmk_len = pmk_len;
-       if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+       if (pmkid)
+               os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
+       else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
                rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
        else if (wpa_key_mgmt_suite_b(akmp))
                rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
@@ -337,7 +366,13 @@ pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
        radius_copy_class(&entry->radius_class, &old_entry->radius_class);
 #endif /* CONFIG_NO_RADIUS */
        entry->eap_type_authsrv = old_entry->eap_type_authsrv;
-       entry->vlan_id = old_entry->vlan_id;
+       if (old_entry->vlan_desc) {
+               entry->vlan_desc = os_zalloc(sizeof(struct vlan_description));
+               if (entry->vlan_desc)
+                       *entry->vlan_desc = *old_entry->vlan_desc;
+       } else {
+               entry->vlan_desc = NULL;
+       }
        entry->opportunistic = 1;
 
        pmksa_cache_link_entry(pmksa, entry);
@@ -471,12 +506,11 @@ static int das_attr_match(struct rsn_pmksa_cache_entry *entry,
        if (attr->acct_multi_session_id) {
                char buf[20];
 
-               if (attr->acct_multi_session_id_len != 17)
+               if (attr->acct_multi_session_id_len != 16)
                        return 0;
-               os_snprintf(buf, sizeof(buf), "%08X+%08X",
-                           entry->acct_multi_session_id_hi,
-                           entry->acct_multi_session_id_lo);
-               if (os_memcmp(attr->acct_multi_session_id, buf, 17) != 0)
+               os_snprintf(buf, sizeof(buf), "%016llX",
+                           (unsigned long long) entry->acct_multi_session_id);
+               if (os_memcmp(attr->acct_multi_session_id, buf, 16) != 0)
                        return 0;
                match++;
        }
@@ -526,3 +560,48 @@ int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
 
        return found ? 0 : -1;
 }
+
+
+/**
+ * pmksa_cache_auth_list - Dump text list of entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_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 PMKSA cache contents for the ctrl_iface PMKSA command.
+ */
+int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
+{
+       int i, ret;
+       char *pos = buf;
+       struct rsn_pmksa_cache_entry *entry;
+       struct os_reltime now;
+
+       os_get_reltime(&now);
+       ret = os_snprintf(pos, buf + len - pos,
+                         "Index / SPA / PMKID / expiration (in seconds) / opportunistic\n");
+       if (os_snprintf_error(buf + len - pos, ret))
+               return pos - buf;
+       pos += ret;
+       i = 0;
+       entry = pmksa->pmksa;
+       while (entry) {
+               ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
+                                 i, MAC2STR(entry->spa));
+               if (os_snprintf_error(buf + len - pos, ret))
+                       return pos - buf;
+               pos += ret;
+               pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
+                                       PMKID_LEN);
+               ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
+                                 (int) (entry->expiration - now.sec),
+                                 entry->opportunistic);
+               if (os_snprintf_error(buf + len - pos, ret))
+                       return pos - buf;
+               pos += ret;
+               entry = entry->next;
+       }
+       return pos - buf;
+}
index 8b7be12..d8d9c5a 100644 (file)
@@ -17,7 +17,7 @@
 struct rsn_pmksa_cache_entry {
        struct rsn_pmksa_cache_entry *next, *hnext;
        u8 pmkid[PMKID_LEN];
-       u8 pmk[PMK_LEN];
+       u8 pmk[PMK_LEN_MAX];
        size_t pmk_len;
        os_time_t expiration;
        int akmp; /* WPA_KEY_MGMT_* */
@@ -28,11 +28,10 @@ struct rsn_pmksa_cache_entry {
        struct wpabuf *cui;
        struct radius_class_data radius_class;
        u8 eap_type_authsrv;
-       int vlan_id;
+       struct vlan_description *vlan_desc;
        int opportunistic;
 
-       u32 acct_multi_session_id_hi;
-       u32 acct_multi_session_id_lo;
+       u64 acct_multi_session_id;
 };
 
 struct rsn_pmksa_cache;
@@ -49,7 +48,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
        const u8 *pmkid);
 struct rsn_pmksa_cache_entry *
 pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
-                    const u8 *pmk, size_t pmk_len,
+                    const u8 *pmk, size_t pmk_len, const u8 *pmkid,
                     const u8 *kck, size_t kck_len,
                     const u8 *aa, const u8 *spa, int session_timeout,
                     struct eapol_state_machine *eapol, int akmp);
@@ -57,11 +56,14 @@ struct rsn_pmksa_cache_entry *
 pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
                    const struct rsn_pmksa_cache_entry *old_entry,
                    const u8 *aa, const u8 *pmkid);
-void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
+void pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
+                              struct rsn_pmksa_cache_entry *entry,
                               struct eapol_state_machine *eapol);
 void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
                            struct rsn_pmksa_cache_entry *entry);
 int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
                                           struct radius_das_attrs *attr);
+int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
+void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa);
 
 #endif /* PMKSA_CACHE_H */
diff --git a/libeap/src/ap/rrm.c b/libeap/src/ap/rrm.c
new file mode 100644 (file)
index 0000000..3569f95
--- /dev/null
@@ -0,0 +1,544 @@
+/*
+ * hostapd / Radio Measurement (RRM)
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ *
+ * 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 "hostapd.h"
+#include "ap_drv_ops.h"
+#include "sta_info.h"
+#include "eloop.h"
+#include "neighbor_db.h"
+#include "rrm.h"
+
+#define HOSTAPD_RRM_REQUEST_TIMEOUT 5
+
+
+static void hostapd_lci_rep_timeout_handler(void *eloop_data, void *user_ctx)
+{
+       struct hostapd_data *hapd = eloop_data;
+
+       wpa_printf(MSG_DEBUG, "RRM: LCI request (token %u) timed out",
+                  hapd->lci_req_token);
+       hapd->lci_req_active = 0;
+}
+
+
+static void hostapd_handle_lci_report(struct hostapd_data *hapd, u8 token,
+                                     const u8 *pos, size_t len)
+{
+       if (!hapd->lci_req_active || hapd->lci_req_token != token) {
+               wpa_printf(MSG_DEBUG, "Unexpected LCI report, token %u", token);
+               return;
+       }
+
+       hapd->lci_req_active = 0;
+       eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL);
+       wpa_printf(MSG_DEBUG, "LCI report token %u len %zu", token, len);
+}
+
+
+static void hostapd_range_rep_timeout_handler(void *eloop_data, void *user_ctx)
+{
+       struct hostapd_data *hapd = eloop_data;
+
+       wpa_printf(MSG_DEBUG, "RRM: Range request (token %u) timed out",
+                  hapd->range_req_token);
+       hapd->range_req_active = 0;
+}
+
+
+static void hostapd_handle_range_report(struct hostapd_data *hapd, u8 token,
+                                       const u8 *pos, size_t len)
+{
+       if (!hapd->range_req_active || hapd->range_req_token != token) {
+               wpa_printf(MSG_DEBUG, "Unexpected range report, token %u",
+                          token);
+               return;
+       }
+
+       hapd->range_req_active = 0;
+       eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
+       wpa_printf(MSG_DEBUG, "Range report token %u len %zu", token, len);
+}
+
+
+static void hostapd_handle_radio_msmt_report(struct hostapd_data *hapd,
+                                            const u8 *buf, size_t len)
+{
+       const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
+       const u8 *pos, *ie, *end;
+       u8 token;
+
+       end = buf + len;
+       token = mgmt->u.action.u.rrm.dialog_token;
+       pos = mgmt->u.action.u.rrm.variable;
+
+       while ((ie = get_ie(pos, end - pos, WLAN_EID_MEASURE_REPORT))) {
+               if (ie[1] < 5) {
+                       wpa_printf(MSG_DEBUG, "Bad Measurement Report element");
+                       break;
+               }
+
+               wpa_printf(MSG_DEBUG, "Measurement report type %u", ie[4]);
+
+               switch (ie[4]) {
+               case MEASURE_TYPE_LCI:
+                       hostapd_handle_lci_report(hapd, token, ie + 2, ie[1]);
+                       break;
+               case MEASURE_TYPE_FTM_RANGE:
+                       hostapd_handle_range_report(hapd, token, ie + 2, ie[1]);
+                       break;
+               default:
+                       wpa_printf(MSG_DEBUG,
+                                  "Measurement report type %u is not supported",
+                                  ie[4]);
+                       break;
+               }
+
+               pos = ie + ie[1] + 2;
+       }
+}
+
+
+static u16 hostapd_parse_location_lci_req_age(const u8 *buf, size_t len)
+{
+       const u8 *subelem;
+
+       /* Range Request element + Location Subject + Maximum Age subelement */
+       if (len < 3 + 1 + 4)
+               return 0;
+
+       /* Subelements are arranged as IEs */
+       subelem = get_ie(buf + 4, len - 4, LCI_REQ_SUBELEM_MAX_AGE);
+       if (subelem && subelem[1] == 2)
+               return *(u16 *) (subelem + 2);
+
+       return 0;
+}
+
+
+static int hostapd_check_lci_age(struct hostapd_neighbor_entry *nr, u16 max_age)
+{
+       struct os_time curr, diff;
+       unsigned long diff_l;
+
+       if (!max_age)
+               return 0;
+
+       if (max_age == 0xffff)
+               return 1;
+
+       if (os_get_time(&curr))
+               return 0;
+
+       os_time_sub(&curr, &nr->lci_date, &diff);
+
+       /* avoid overflow */
+       if (diff.sec > 0xffff)
+               return 0;
+
+       /* LCI age is calculated in 10th of a second units. */
+       diff_l = diff.sec * 10 + diff.usec / 100000;
+
+       return max_age > diff_l;
+}
+
+
+static size_t hostapd_neighbor_report_len(struct wpabuf *buf,
+                                         struct hostapd_neighbor_entry *nr,
+                                         int send_lci, int send_civic)
+{
+       size_t len = 2 + wpabuf_len(nr->nr);
+
+       if (send_lci && nr->lci)
+               len += 2 + wpabuf_len(nr->lci);
+
+       if (send_civic && nr->civic)
+               len += 2 + wpabuf_len(nr->civic);
+
+       return len;
+}
+
+
+static void hostapd_send_nei_report_resp(struct hostapd_data *hapd,
+                                        const u8 *addr, u8 dialog_token,
+                                        struct wpa_ssid_value *ssid, u8 lci,
+                                        u8 civic, u16 lci_max_age)
+{
+       struct hostapd_neighbor_entry *nr;
+       struct wpabuf *buf;
+       u8 *msmt_token;
+
+       /*
+        * The number and length of the Neighbor Report elements in a Neighbor
+        * Report frame is limited by the maximum allowed MMPDU size; + 3 bytes
+        * of RRM header.
+        */
+       buf = wpabuf_alloc(3 + IEEE80211_MAX_MMPDU_SIZE);
+       if (!buf)
+               return;
+
+       wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+       wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_RESPONSE);
+       wpabuf_put_u8(buf, dialog_token);
+
+       dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
+                        list) {
+               int send_lci;
+               size_t len;
+
+               if (ssid->ssid_len != nr->ssid.ssid_len ||
+                   os_memcmp(ssid->ssid, nr->ssid.ssid, ssid->ssid_len) != 0)
+                       continue;
+
+               send_lci = (lci != 0) && hostapd_check_lci_age(nr, lci_max_age);
+               len = hostapd_neighbor_report_len(buf, nr, send_lci, civic);
+
+               if (len - 2 > 0xff) {
+                       wpa_printf(MSG_DEBUG,
+                                  "NR entry for " MACSTR " exceeds 0xFF bytes",
+                                  MAC2STR(nr->bssid));
+                       continue;
+               }
+
+               if (len > wpabuf_tailroom(buf))
+                       break;
+
+               wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
+               wpabuf_put_u8(buf, len - 2);
+               wpabuf_put_buf(buf, nr->nr);
+
+               if (send_lci && nr->lci) {
+                       wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT);
+                       wpabuf_put_u8(buf, wpabuf_len(nr->lci));
+                       /*
+                        * Override measurement token - the first byte of the
+                        * Measurement Report element.
+                        */
+                       msmt_token = wpabuf_put(buf, 0);
+                       wpabuf_put_buf(buf, nr->lci);
+                       *msmt_token = lci;
+               }
+
+               if (civic && nr->civic) {
+                       wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT);
+                       wpabuf_put_u8(buf, wpabuf_len(nr->civic));
+                       /*
+                        * Override measurement token - the first byte of the
+                        * Measurement Report element.
+                        */
+                       msmt_token = wpabuf_put(buf, 0);
+                       wpabuf_put_buf(buf, nr->civic);
+                       *msmt_token = civic;
+               }
+       }
+
+       hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+                               wpabuf_head(buf), wpabuf_len(buf));
+       wpabuf_free(buf);
+}
+
+
+static void hostapd_handle_nei_report_req(struct hostapd_data *hapd,
+                                         const u8 *buf, size_t len)
+{
+       const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
+       const u8 *pos, *ie, *end;
+       struct wpa_ssid_value ssid = {
+               .ssid_len = 0
+       };
+       u8 token;
+       u8 lci = 0, civic = 0; /* Measurement tokens */
+       u16 lci_max_age = 0;
+
+       if (!(hapd->conf->radio_measurements[0] &
+             WLAN_RRM_CAPS_NEIGHBOR_REPORT))
+               return;
+
+       end = buf + len;
+
+       token = mgmt->u.action.u.rrm.dialog_token;
+       pos = mgmt->u.action.u.rrm.variable;
+       len = end - pos;
+
+       ie = get_ie(pos, len, WLAN_EID_SSID);
+       if (ie && ie[1] && ie[1] <= SSID_MAX_LEN) {
+               ssid.ssid_len = ie[1];
+               os_memcpy(ssid.ssid, ie + 2, ssid.ssid_len);
+       } else {
+               ssid.ssid_len = hapd->conf->ssid.ssid_len;
+               os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
+       }
+
+       while ((ie = get_ie(pos, len, WLAN_EID_MEASURE_REQUEST))) {
+               if (ie[1] < 3)
+                       break;
+
+               wpa_printf(MSG_DEBUG,
+                          "Neighbor report request, measure type %u",
+                          ie[4]);
+
+               switch (ie[4]) { /* Measurement Type */
+               case MEASURE_TYPE_LCI:
+                       lci = ie[2]; /* Measurement Token */
+                       lci_max_age = hostapd_parse_location_lci_req_age(ie + 2,
+                                                                        ie[1]);
+                       break;
+               case MEASURE_TYPE_LOCATION_CIVIC:
+                       civic = ie[2]; /* Measurement token */
+                       break;
+               }
+
+               pos = ie + ie[1] + 2;
+               len = end - pos;
+       }
+
+       hostapd_send_nei_report_resp(hapd, mgmt->sa, token, &ssid, lci, civic,
+                                    lci_max_age);
+}
+
+
+void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
+                                     const u8 *buf, size_t len)
+{
+       const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
+
+       /*
+        * Check for enough bytes: header + (1B)Category + (1B)Action +
+        * (1B)Dialog Token.
+        */
+       if (len < IEEE80211_HDRLEN + 3)
+               return;
+
+       wpa_printf(MSG_DEBUG, "Radio measurement frame, action %u from " MACSTR,
+                  mgmt->u.action.u.rrm.action, MAC2STR(mgmt->sa));
+
+       switch (mgmt->u.action.u.rrm.action) {
+       case WLAN_RRM_RADIO_MEASUREMENT_REPORT:
+               hostapd_handle_radio_msmt_report(hapd, buf, len);
+               break;
+       case WLAN_RRM_NEIGHBOR_REPORT_REQUEST:
+               hostapd_handle_nei_report_req(hapd, buf, len);
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "RRM action %u is not supported",
+                          mgmt->u.action.u.rrm.action);
+               break;
+       }
+}
+
+
+int hostapd_send_lci_req(struct hostapd_data *hapd, const u8 *addr)
+{
+       struct wpabuf *buf;
+       struct sta_info *sta = ap_get_sta(hapd, addr);
+       int ret;
+
+       if (!sta) {
+               wpa_printf(MSG_INFO,
+                          "Request LCI: Destination address is not in station list");
+               return -1;
+       }
+
+       if (!(sta->flags & WLAN_STA_AUTHORIZED)) {
+               wpa_printf(MSG_INFO,
+                          "Request LCI: Destination address is not connected");
+               return -1;
+       }
+
+       if (!(sta->rrm_enabled_capa[1] & WLAN_RRM_CAPS_LCI_MEASUREMENT)) {
+               wpa_printf(MSG_INFO,
+                          "Request LCI: Station does not support LCI in RRM");
+               return -1;
+       }
+
+       if (hapd->lci_req_active) {
+               wpa_printf(MSG_DEBUG,
+                          "Request LCI: LCI request is already in process, overriding");
+               hapd->lci_req_active = 0;
+               eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd,
+                                    NULL);
+       }
+
+       /* Measurement request (5) + Measurement element with LCI (10) */
+       buf = wpabuf_alloc(5 + 10);
+       if (!buf)
+               return -1;
+
+       hapd->lci_req_token++;
+       /* For wraparounds - the token must be nonzero */
+       if (!hapd->lci_req_token)
+               hapd->lci_req_token++;
+
+       wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+       wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
+       wpabuf_put_u8(buf, hapd->lci_req_token);
+       wpabuf_put_le16(buf, 0); /* Number of repetitions */
+
+       wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+       wpabuf_put_u8(buf, 3 + 1 + 4);
+
+       wpabuf_put_u8(buf, 1); /* Measurement Token */
+       /*
+        * Parallel and Enable bits are 0, Duration, Request, and Report are
+        * reserved.
+        */
+       wpabuf_put_u8(buf, 0);
+       wpabuf_put_u8(buf, MEASURE_TYPE_LCI);
+
+       wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
+
+       wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE);
+       wpabuf_put_u8(buf, 2);
+       wpabuf_put_le16(buf, 0xffff);
+
+       ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+                                     wpabuf_head(buf), wpabuf_len(buf));
+       wpabuf_free(buf);
+       if (ret)
+               return ret;
+
+       hapd->lci_req_active = 1;
+
+       eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
+                              hostapd_lci_rep_timeout_handler, hapd, NULL);
+
+       return 0;
+}
+
+
+int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr,
+                          u16 random_interval, u8 min_ap,
+                          const u8 *responders, unsigned int n_responders)
+{
+       struct wpabuf *buf;
+       struct sta_info *sta;
+       u8 *len;
+       unsigned int i;
+       int ret;
+
+       wpa_printf(MSG_DEBUG, "Request range: dest addr " MACSTR
+                  " rand interval %u min AP %u n_responders %u", MAC2STR(addr),
+                  random_interval, min_ap, n_responders);
+
+       if (min_ap == 0 || min_ap > n_responders) {
+               wpa_printf(MSG_INFO, "Request range: Wrong min AP count");
+               return -1;
+       }
+
+       sta = ap_get_sta(hapd, addr);
+       if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
+               wpa_printf(MSG_INFO,
+                          "Request range: Destination address is not connected");
+               return -1;
+       }
+
+       if (!(sta->rrm_enabled_capa[4] & WLAN_RRM_CAPS_FTM_RANGE_REPORT)) {
+               wpa_printf(MSG_ERROR,
+                          "Request range: Destination station does not support FTM range report in RRM");
+               return -1;
+       }
+
+       if (hapd->range_req_active) {
+               wpa_printf(MSG_DEBUG,
+                          "Request range: Range request is already in process; overriding");
+               hapd->range_req_active = 0;
+               eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
+                                      hostapd_range_rep_timeout_handler, hapd,
+                                      NULL);
+       }
+
+       /* Action + measurement type + token + reps + EID + len = 7 */
+       buf = wpabuf_alloc(7 + 255);
+       if (!buf)
+               return -1;
+
+       hapd->range_req_token++;
+       if (!hapd->range_req_token) /* For wraparounds */
+               hapd->range_req_token++;
+
+       /* IEEE P802.11-REVmc/D5.0, 9.6.7.2 */
+       wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+       wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
+       wpabuf_put_u8(buf, hapd->range_req_token); /* Dialog Token */
+       wpabuf_put_le16(buf, 0); /* Number of Repetitions */
+
+       /* IEEE P802.11-REVmc/D5.0, 9.4.2.21 */
+       wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+       len = wpabuf_put(buf, 1); /* Length will be set later */
+
+       wpabuf_put_u8(buf, 1); /* Measurement Token */
+       /*
+        * Parallel and Enable bits are 0; Duration, Request, and Report are
+        * reserved.
+        */
+       wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
+       wpabuf_put_u8(buf, MEASURE_TYPE_FTM_RANGE); /* Measurement Type */
+
+       /* IEEE P802.11-REVmc/D5.0, 9.4.2.21.19 */
+       wpabuf_put_le16(buf, random_interval); /* Randomization Interval */
+       wpabuf_put_u8(buf, min_ap); /* Minimum AP Count */
+
+       /* FTM Range Subelements */
+
+       /*
+        * Taking the neighbor report part of the range request from neighbor
+        * database instead of requesting the separate bits of data from the
+        * user.
+        */
+       for (i = 0; i < n_responders; i++) {
+               struct hostapd_neighbor_entry *nr;
+
+               nr = hostapd_neighbor_get(hapd, responders + ETH_ALEN * i,
+                                         NULL);
+               if (!nr) {
+                       wpa_printf(MSG_INFO, "Missing neighbor report for "
+                                  MACSTR, MAC2STR(responders + ETH_ALEN * i));
+                       wpabuf_free(buf);
+                       return -1;
+               }
+
+               if (wpabuf_tailroom(buf) < 2 + wpabuf_len(nr->nr)) {
+                       wpa_printf(MSG_ERROR, "Too long range request");
+                       wpabuf_free(buf);
+                       return -1;
+               }
+
+               wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
+               wpabuf_put_u8(buf, wpabuf_len(nr->nr));
+               wpabuf_put_buf(buf, nr->nr);
+       }
+
+       /* Action + measurement type + token + reps + EID + len = 7 */
+       *len = wpabuf_len(buf) - 7;
+
+       ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+                                     wpabuf_head(buf), wpabuf_len(buf));
+       wpabuf_free(buf);
+       if (ret)
+               return ret;
+
+       hapd->range_req_active = 1;
+
+       eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
+                              hostapd_range_rep_timeout_handler, hapd, NULL);
+
+       return 0;
+}
+
+
+void hostapd_clean_rrm(struct hostapd_data *hapd)
+{
+       hostpad_free_neighbor_db(hapd);
+       eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL);
+       hapd->lci_req_active = 0;
+       eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
+       hapd->range_req_active = 0;
+}
diff --git a/libeap/src/ap/rrm.h b/libeap/src/ap/rrm.h
new file mode 100644 (file)
index 0000000..f07fd41
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * hostapd / Radio Measurement (RRM)
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef RRM_H
+#define RRM_H
+
+/*
+ * Max measure request length is 255, -6 of the body we have 249 for the
+ * neighbor report elements. Each neighbor report element is at least 2 + 13
+ * bytes, so we can't have more than 16 responders in the request.
+ */
+#define RRM_RANGE_REQ_MAX_RESPONDERS 16
+
+void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
+                                     const u8 *buf, size_t len);
+int hostapd_send_lci_req(struct hostapd_data *hapd, const u8 *addr);
+int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr,
+                          u16 random_interval, u8 min_ap,
+                          const u8 *responders, unsigned int n_responders);
+void hostapd_clean_rrm(struct hostapd_data *hapd);
+
+#endif /* RRM_H */
index d64307c..f12d408 100644 (file)
 #include "ap_drv_ops.h"
 #include "gas_serv.h"
 #include "wnm_ap.h"
+#include "mbo_ap.h"
 #include "ndisc_snoop.h"
 #include "sta_info.h"
+#include "vlan.h"
 
 static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
                                       struct sta_info *sta);
@@ -169,21 +171,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
        ap_sta_ip6addr_del(hapd, sta);
 
        if (!hapd->iface->driver_ap_teardown &&
-           !(sta->flags & WLAN_STA_PREAUTH))
+           !(sta->flags & WLAN_STA_PREAUTH)) {
                hostapd_drv_sta_remove(hapd, sta->addr);
-
-#ifndef CONFIG_NO_VLAN
-       if (sta->vlan_id_bound) {
-               /*
-                * Need to remove the STA entry before potentially removing the
-                * VLAN.
-                */
-               if (hapd->iface->driver_ap_teardown &&
-                   !(sta->flags & WLAN_STA_PREAUTH))
-                       hostapd_drv_sta_remove(hapd, sta->addr);
-               vlan_remove_dynamic(hapd, sta->vlan_id_bound);
+               sta->added_unassoc = 0;
        }
-#endif /* CONFIG_NO_VLAN */
 
        ap_sta_hash_del(hapd, sta);
        ap_sta_list_del(hapd, sta);
@@ -231,6 +222,13 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
                hapd->iface->num_sta_ht_20mhz--;
        }
 
+#ifdef CONFIG_TAXONOMY
+       wpabuf_free(sta->probe_ie_taxonomy);
+       sta->probe_ie_taxonomy = NULL;
+       wpabuf_free(sta->assoc_ie_taxonomy);
+       sta->assoc_ie_taxonomy = NULL;
+#endif /* CONFIG_TAXONOMY */
+
 #ifdef CONFIG_IEEE80211N
        ht40_intolerant_remove(hapd->iface, sta);
 #endif /* CONFIG_IEEE80211N */
@@ -251,7 +249,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
 
 #ifdef CONFIG_MESH
        if (hapd->mesh_sta_free_cb)
-               hapd->mesh_sta_free_cb(sta);
+               hapd->mesh_sta_free_cb(hapd, sta);
 #endif /* CONFIG_MESH */
 
        if (set_beacon)
@@ -262,11 +260,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
        eloop_cancel_timeout(ap_handle_timer, hapd, sta);
        eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
        eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
-       eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
-       eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+       ap_sta_clear_disconnect_timeouts(hapd, sta);
        sae_clear_retransmit_timer(hapd, sta);
 
-       ieee802_1x_free_station(sta);
+       ieee802_1x_free_station(hapd, sta);
        wpa_auth_sta_deinit(sta->wpa_sm);
        rsn_preauth_free_station(hapd, sta);
 #ifndef CONFIG_NO_RADIUS
@@ -274,6 +271,28 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
                radius_client_flush_auth(hapd->radius, sta->addr);
 #endif /* CONFIG_NO_RADIUS */
 
+#ifndef CONFIG_NO_VLAN
+       /*
+        * sta->wpa_sm->group needs to be released before so that
+        * vlan_remove_dynamic() can check that no stations are left on the
+        * AP_VLAN netdev.
+        */
+       if (sta->vlan_id)
+               vlan_remove_dynamic(hapd, sta->vlan_id);
+       if (sta->vlan_id_bound) {
+               /*
+                * Need to remove the STA entry before potentially removing the
+                * VLAN.
+                */
+               if (hapd->iface->driver_ap_teardown &&
+                   !(sta->flags & WLAN_STA_PREAUTH)) {
+                       hostapd_drv_sta_remove(hapd, sta->addr);
+                       sta->added_unassoc = 0;
+               }
+               vlan_remove_dynamic(hapd, sta->vlan_id_bound);
+       }
+#endif /* CONFIG_NO_VLAN */
+
        os_free(sta->challenge);
 
 #ifdef CONFIG_IEEE80211W
@@ -315,6 +334,9 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
        os_free(sta->sae);
 #endif /* CONFIG_SAE */
 
+       mbo_ap_sta_free(sta);
+       os_free(sta->supp_op_classes);
+
        os_free(sta);
 }
 
@@ -354,8 +376,8 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
        unsigned long next_time = 0;
        int reason;
 
-       wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d",
-                  __func__, MAC2STR(sta->addr), sta->flags,
+       wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d",
+                  hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags,
                   sta->timeout_next);
        if (sta->timeout_next == STA_REMOVE) {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -482,7 +504,7 @@ skip_poll:
                        sta->acct_terminate_cause =
                                RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
                accounting_sta_stop(hapd, sta);
-               ieee802_1x_free_station(sta);
+               ieee802_1x_free_station(hapd, sta);
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_INFO, "disassociated due to "
                               "inactivity");
@@ -519,6 +541,8 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
        struct hostapd_data *hapd = eloop_ctx;
        struct sta_info *sta = 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_GAS) {
                        wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
@@ -577,8 +601,8 @@ static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx)
        struct hostapd_data *hapd = eloop_ctx;
        struct sta_info *sta = timeout_ctx;
 
-       wpa_printf(MSG_DEBUG, "WNM: Session warning time reached for " MACSTR,
-                  MAC2STR(sta->addr));
+       wpa_printf(MSG_DEBUG, "%s: WNM: Session warning time reached for "
+                  MACSTR, hapd->conf->iface, MAC2STR(sta->addr));
        if (sta->hs20_session_info_url == NULL)
                return;
 
@@ -619,7 +643,10 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
                return NULL;
        }
        sta->acct_interim_interval = hapd->conf->acct_interim_interval;
-       accounting_sta_get_id(hapd, sta);
+       if (accounting_sta_get_id(hapd, sta) < 0) {
+               os_free(sta);
+               return NULL;
+       }
 
        if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
                wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
@@ -640,6 +667,11 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
        sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
        dl_list_init(&sta->ip6addr);
 
+#ifdef CONFIG_TAXONOMY
+       sta_track_claim_taxonomy_info(hapd->iface, addr,
+                                     &sta->probe_ie_taxonomy);
+#endif /* CONFIG_TAXONOMY */
+
        return sta;
 }
 
@@ -652,14 +684,16 @@ static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
                hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
        ap_sta_ip6addr_del(hapd, sta);
 
-       wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
-                  MAC2STR(sta->addr));
+       wpa_printf(MSG_DEBUG, "%s: Removing STA " MACSTR " from kernel driver",
+                  hapd->conf->iface, MAC2STR(sta->addr));
        if (hostapd_drv_sta_remove(hapd, sta->addr) &&
            sta->flags & WLAN_STA_ASSOC) {
-               wpa_printf(MSG_DEBUG, "Could not remove station " MACSTR
-                          " from kernel driver.", MAC2STR(sta->addr));
+               wpa_printf(MSG_DEBUG, "%s: Could not remove station " MACSTR
+                          " from kernel driver",
+                          hapd->conf->iface, MAC2STR(sta->addr));
                return -1;
        }
+       sta->added_unassoc = 0;
        return 0;
 }
 
@@ -683,6 +717,10 @@ static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
                if (!sta2)
                        continue;
 
+               wpa_printf(MSG_DEBUG, "%s: disconnect old STA " MACSTR
+                          " association from another BSS %s",
+                          hapd->conf->iface, MAC2STR(sta2->addr),
+                          bss->conf->iface);
                ap_sta_disconnect(bss, sta2, sta2->addr,
                                  WLAN_REASON_PREV_AUTH_NOT_VALID);
        }
@@ -694,6 +732,8 @@ static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
        struct hostapd_data *hapd = eloop_ctx;
        struct sta_info *sta = timeout_ctx;
 
+       wpa_printf(MSG_DEBUG, "%s: Disassociation callback for STA " MACSTR,
+                  hapd->conf->iface, MAC2STR(sta->addr));
        ap_sta_remove(hapd, sta);
        mlme_disassociate_indication(hapd, sta, sta->disassoc_reason);
 }
@@ -717,7 +757,7 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
        eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
                               ap_handle_timer, hapd, sta);
        accounting_sta_stop(hapd, sta);
-       ieee802_1x_free_station(sta);
+       ieee802_1x_free_station(hapd, sta);
 
        sta->disassoc_reason = reason;
        sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
@@ -733,6 +773,8 @@ static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
        struct hostapd_data *hapd = eloop_ctx;
        struct sta_info *sta = timeout_ctx;
 
+       wpa_printf(MSG_DEBUG, "%s: Deauthentication callback for STA " MACSTR,
+                  hapd->conf->iface, MAC2STR(sta->addr));
        ap_sta_remove(hapd, sta);
        mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason);
 }
@@ -756,7 +798,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
        eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
                               ap_handle_timer, hapd, sta);
        accounting_sta_stop(hapd, sta);
-       ieee802_1x_free_station(sta);
+       ieee802_1x_free_station(hapd, sta);
 
        sta->deauth_reason = reason;
        sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
@@ -784,6 +826,128 @@ int ap_sta_wps_cancel(struct hostapd_data *hapd,
 #endif /* CONFIG_WPS */
 
 
+static int ap_sta_get_free_vlan_id(struct hostapd_data *hapd)
+{
+       struct hostapd_vlan *vlan;
+       int vlan_id = MAX_VLAN_ID + 2;
+
+retry:
+       for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+               if (vlan->vlan_id == vlan_id) {
+                       vlan_id++;
+                       goto retry;
+               }
+       }
+       return vlan_id;
+}
+
+
+int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
+                   struct vlan_description *vlan_desc)
+{
+       struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL;
+       int old_vlan_id, vlan_id = 0, ret = 0;
+
+       if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+               vlan_desc = NULL;
+
+       /* Check if there is something to do */
+       if (hapd->conf->ssid.per_sta_vif && !sta->vlan_id) {
+               /* This sta is lacking its own vif */
+       } else if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED &&
+                  !hapd->conf->ssid.per_sta_vif && sta->vlan_id) {
+               /* sta->vlan_id needs to be reset */
+       } else if (!vlan_compare(vlan_desc, sta->vlan_desc)) {
+               return 0; /* nothing to change */
+       }
+
+       /* Now the real VLAN changed or the STA just needs its own vif */
+       if (hapd->conf->ssid.per_sta_vif) {
+               /* Assign a new vif, always */
+               /* find a free vlan_id sufficiently big */
+               vlan_id = ap_sta_get_free_vlan_id(hapd);
+               /* Get wildcard VLAN */
+               for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+                       if (vlan->vlan_id == VLAN_ID_WILDCARD)
+                               break;
+               }
+               if (!vlan) {
+                       hostapd_logger(hapd, sta->addr,
+                                      HOSTAPD_MODULE_IEEE80211,
+                                      HOSTAPD_LEVEL_DEBUG,
+                                      "per_sta_vif missing wildcard");
+                       vlan_id = 0;
+                       ret = -1;
+                       goto done;
+               }
+       } else if (vlan_desc && vlan_desc->notempty) {
+               for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+                       if (!vlan_compare(&vlan->vlan_desc, vlan_desc))
+                               break;
+                       if (vlan->vlan_id == VLAN_ID_WILDCARD)
+                               wildcard_vlan = vlan;
+               }
+               if (vlan) {
+                       vlan_id = vlan->vlan_id;
+               } else if (wildcard_vlan) {
+                       vlan = wildcard_vlan;
+                       vlan_id = vlan_desc->untagged;
+                       if (vlan_desc->tagged[0]) {
+                               /* Tagged VLAN configuration */
+                               vlan_id = ap_sta_get_free_vlan_id(hapd);
+                       }
+               } else {
+                       hostapd_logger(hapd, sta->addr,
+                                      HOSTAPD_MODULE_IEEE80211,
+                                      HOSTAPD_LEVEL_DEBUG,
+                                      "missing vlan and wildcard for vlan=%d%s",
+                                      vlan_desc->untagged,
+                                      vlan_desc->tagged[0] ? "+" : "");
+                       vlan_id = 0;
+                       ret = -1;
+                       goto done;
+               }
+       }
+
+       if (vlan && vlan->vlan_id == VLAN_ID_WILDCARD) {
+               vlan = vlan_add_dynamic(hapd, vlan, vlan_id, vlan_desc);
+               if (vlan == NULL) {
+                       hostapd_logger(hapd, sta->addr,
+                                      HOSTAPD_MODULE_IEEE80211,
+                                      HOSTAPD_LEVEL_DEBUG,
+                                      "could not add dynamic VLAN interface for vlan=%d%s",
+                                      vlan_desc ? vlan_desc->untagged : -1,
+                                      (vlan_desc && vlan_desc->tagged[0]) ?
+                                      "+" : "");
+                       vlan_id = 0;
+                       ret = -1;
+                       goto done;
+               }
+
+               hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+                              HOSTAPD_LEVEL_DEBUG,
+                              "added new dynamic VLAN interface '%s'",
+                              vlan->ifname);
+       } else if (vlan && vlan->dynamic_vlan > 0) {
+               vlan->dynamic_vlan++;
+               hostapd_logger(hapd, sta->addr,
+                              HOSTAPD_MODULE_IEEE80211,
+                              HOSTAPD_LEVEL_DEBUG,
+                              "updated existing dynamic VLAN interface '%s'",
+                              vlan->ifname);
+       }
+done:
+       old_vlan_id = sta->vlan_id;
+       sta->vlan_id = vlan_id;
+       sta->vlan_desc = vlan ? &vlan->vlan_desc : NULL;
+
+       if (vlan_id != old_vlan_id && old_vlan_id)
+               vlan_remove_dynamic(hapd, old_vlan_id);
+
+       return ret;
+}
+
+
 int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
 {
 #ifndef CONFIG_NO_VLAN
@@ -796,20 +960,11 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
        if (hapd->conf->ssid.vlan[0])
                iface = hapd->conf->ssid.vlan;
 
-       if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
-               sta->vlan_id = 0;
-       else if (sta->vlan_id > 0) {
-               struct hostapd_vlan *wildcard_vlan = NULL;
-               vlan = hapd->conf->vlan;
-               while (vlan) {
+       if (sta->vlan_id > 0) {
+               for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
                        if (vlan->vlan_id == sta->vlan_id)
                                break;
-                       if (vlan->vlan_id == VLAN_ID_WILDCARD)
-                               wildcard_vlan = vlan;
-                       vlan = vlan->next;
                }
-               if (!vlan)
-                       vlan = wildcard_vlan;
                if (vlan)
                        iface = vlan->ifname;
        }
@@ -829,54 +984,13 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
                               sta->vlan_id);
                ret = -1;
                goto done;
-       } else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) {
-               vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id);
-               if (vlan == NULL) {
-                       hostapd_logger(hapd, sta->addr,
-                                      HOSTAPD_MODULE_IEEE80211,
-                                      HOSTAPD_LEVEL_DEBUG, "could not add "
-                                      "dynamic VLAN interface for vlan_id=%d",
-                                      sta->vlan_id);
-                       ret = -1;
-                       goto done;
-               }
-
-               iface = vlan->ifname;
-               if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
-                       hostapd_logger(hapd, sta->addr,
-                                      HOSTAPD_MODULE_IEEE80211,
-                                      HOSTAPD_LEVEL_DEBUG, "could not "
-                                      "configure encryption for dynamic VLAN "
-                                      "interface for vlan_id=%d",
-                                      sta->vlan_id);
-               }
-
-               hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-                              HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN "
-                              "interface '%s'", iface);
-       } else if (vlan && vlan->vlan_id == sta->vlan_id) {
-               if (vlan->dynamic_vlan > 0) {
-                       vlan->dynamic_vlan++;
-                       hostapd_logger(hapd, sta->addr,
-                                      HOSTAPD_MODULE_IEEE80211,
-                                      HOSTAPD_LEVEL_DEBUG, "updated existing "
-                                      "dynamic VLAN interface '%s'", iface);
-               }
-
-               /*
-                * Update encryption configuration for statically generated
-                * VLAN interface. This is only used for static WEP
-                * configuration for the case where hostapd did not yet know
-                * which keys are to be used when the interface was added.
-                */
-               if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
-                       hostapd_logger(hapd, sta->addr,
-                                      HOSTAPD_MODULE_IEEE80211,
-                                      HOSTAPD_LEVEL_DEBUG, "could not "
-                                      "configure encryption for VLAN "
-                                      "interface for vlan_id=%d",
-                                      sta->vlan_id);
-               }
+       } else if (vlan && vlan->dynamic_vlan > 0) {
+               vlan->dynamic_vlan++;
+               hostapd_logger(hapd, sta->addr,
+                              HOSTAPD_MODULE_IEEE80211,
+                              HOSTAPD_LEVEL_DEBUG,
+                              "updated existing dynamic VLAN interface '%s'",
+                              iface);
        }
 
        /* ref counters have been increased, so mark the station */
@@ -942,6 +1056,10 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
        unsigned int timeout, sec, usec;
        u8 *trans_id, *nbuf;
 
+       wpa_printf(MSG_DEBUG, "%s: SA Query timer for STA " MACSTR
+                  " (count=%d)",
+                  hapd->conf->iface, MAC2STR(sta->addr), sta->sa_query_count);
+
        if (sta->sa_query_count > 0 &&
            ap_check_sa_query_timeout(hapd, sta))
                return;
@@ -1080,6 +1198,14 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
 void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
                       const u8 *addr, u16 reason)
 {
+       if (sta)
+               wpa_printf(MSG_DEBUG, "%s: %s STA " MACSTR " reason=%u",
+                          hapd->conf->iface, __func__, MAC2STR(sta->addr),
+                          reason);
+       else if (addr)
+               wpa_printf(MSG_DEBUG, "%s: %s addr " MACSTR " reason=%u",
+                          hapd->conf->iface, __func__, MAC2STR(addr),
+                          reason);
 
        if (sta == NULL && addr)
                sta = ap_get_sta(hapd, addr);
@@ -1093,10 +1219,10 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *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: reschedule ap_handle_timer timeout "
+       wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout "
                   "for " MACSTR " (%d seconds - "
                   "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
-                  __func__, MAC2STR(sta->addr),
+                  hapd->conf->iface, __func__, MAC2STR(sta->addr),
                   AP_MAX_INACTIVITY_AFTER_DEAUTH);
        eloop_cancel_timeout(ap_handle_timer, hapd, sta);
        eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
@@ -1136,6 +1262,22 @@ void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
 }
 
 
+void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
+                                     struct sta_info *sta)
+{
+       if (eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta) > 0)
+               wpa_printf(MSG_DEBUG,
+                          "%s: Removed ap_sta_deauth_cb_timeout timeout for "
+                          MACSTR,
+                          hapd->conf->iface, MAC2STR(sta->addr));
+       if (eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta) > 0)
+               wpa_printf(MSG_DEBUG,
+                          "%s: Removed ap_sta_disassoc_cb_timeout timeout for "
+                          MACSTR,
+                          hapd->conf->iface, MAC2STR(sta->addr));
+}
+
+
 int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
 {
        int res;
index 420d64e..099de62 100644 (file)
 #ifdef CONFIG_MESH
 /* needed for mesh_plink_state enum */
 #include "common/defs.h"
+#include "common/wpa_common.h"
 #endif /* CONFIG_MESH */
 
 #include "list.h"
+#include "vlan.h"
 
 /* STA flags */
 #define WLAN_STA_AUTH BIT(0)
 #define WLAN_SUPP_RATES_MAX 32
 
 
+struct mbo_non_pref_chan_info {
+       struct mbo_non_pref_chan_info *next;
+       u8 op_class;
+       u8 pref;
+       u8 reason_code;
+       u8 num_channels;
+       u8 channels[];
+};
+
+struct pending_eapol_rx {
+       struct wpabuf *buf;
+       struct os_reltime rx_time;
+};
+
 struct sta_info {
        struct sta_info *next; /* next entry in sta list */
        struct sta_info *hnext; /* next entry in hash table list */
@@ -63,13 +79,22 @@ struct sta_info {
        enum mesh_plink_state plink_state;
        u16 peer_lid;
        u16 my_lid;
+       u16 peer_aid;
        u16 mpm_close_reason;
        int mpm_retries;
-       u8 my_nonce[32];
-       u8 peer_nonce[32];
+       u8 my_nonce[WPA_NONCE_LEN];
+       u8 peer_nonce[WPA_NONCE_LEN];
        u8 aek[32];     /* SHA256 digest length */
-       u8 mtk[16];
-       u8 mgtk[16];
+       u8 mtk[WPA_TK_MAX_LEN];
+       size_t mtk_len;
+       u8 mgtk_rsc[6];
+       u8 mgtk_key_id;
+       u8 mgtk[WPA_TK_MAX_LEN];
+       size_t mgtk_len;
+       u8 igtk_rsc[6];
+       u8 igtk[WPA_TK_MAX_LEN];
+       size_t igtk_len;
+       u16 igtk_key_id;
        u8 sae_auth_retry;
 #endif /* CONFIG_MESH */
 
@@ -86,6 +111,8 @@ struct sta_info {
        unsigned int hs20_deauth_requested:1;
        unsigned int session_timeout_set:1;
        unsigned int radius_das_match:1;
+       unsigned int ecsa_supported:1;
+       unsigned int added_unassoc:1;
 
        u16 auth_alg;
 
@@ -100,17 +127,20 @@ struct sta_info {
        /* IEEE 802.1X related data */
        struct eapol_state_machine *eapol_sm;
 
-       u32 acct_session_id_hi;
-       u32 acct_session_id_lo;
+       struct pending_eapol_rx *pending_eapol_rx;
+
+       u64 acct_session_id;
        struct os_reltime acct_session_start;
        int acct_session_started;
        int acct_terminate_cause; /* Acct-Terminate-Cause */
        int acct_interim_interval; /* Acct-Interim-Interval */
+       unsigned int acct_interim_errors;
 
-       unsigned long last_rx_bytes;
-       unsigned long last_tx_bytes;
-       u32 acct_input_gigawords; /* Acct-Input-Gigawords */
-       u32 acct_output_gigawords; /* Acct-Output-Gigawords */
+       /* For extending 32-bit driver counters to 64-bit counters */
+       u32 last_rx_bytes_hi;
+       u32 last_rx_bytes_lo;
+       u32 last_tx_bytes_hi;
+       u32 last_tx_bytes_lo;
 
        u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */
 
@@ -118,6 +148,7 @@ struct sta_info {
        struct rsn_preauth_interface *preauth_iface;
 
        int vlan_id; /* 0: none, >0: VID */
+       struct vlan_description *vlan_desc;
        int vlan_id_bound; /* updated by ap_sta_bind_vlan() */
         /* PSKs from RADIUS authentication server */
        struct hostapd_sta_wpa_psk_short *psk;
@@ -161,6 +192,7 @@ struct sta_info {
 
 #ifdef CONFIG_SAE
        struct sae_data *sae;
+       unsigned int mesh_sae_pmksa_caching:1;
 #endif /* CONFIG_SAE */
 
        u32 session_timeout; /* valid only if session_timeout_set == 1 */
@@ -170,6 +202,22 @@ struct sta_info {
        u16 last_seq_ctrl;
        /* Last Authentication/(Re)Association Request/Action frame subtype */
        u8 last_subtype;
+
+#ifdef CONFIG_MBO
+       u8 cell_capa; /* 0 = unknown (not an MBO STA); otherwise,
+                      * enum mbo_cellular_capa values */
+       struct mbo_non_pref_chan_info *non_pref_chan;
+#endif /* CONFIG_MBO */
+
+       u8 *supp_op_classes; /* Supported Operating Classes element, if
+                             * received, starting from the Length field */
+
+       u8 rrm_enabled_capa[5];
+
+#ifdef CONFIG_TAXONOMY
+       struct wpabuf *probe_ie_taxonomy;
+       struct wpabuf *assoc_ie_taxonomy;
+#endif /* CONFIG_TAXONOMY */
 };
 
 
@@ -180,7 +228,7 @@ struct sta_info {
  * AP_DISASSOC_DELAY seconds. Similarly, the station will be deauthenticated
  * after AP_DEAUTH_DELAY seconds has passed after disassociation. */
 #define AP_MAX_INACTIVITY (5 * 60)
-#define AP_DISASSOC_DELAY (1)
+#define AP_DISASSOC_DELAY (3)
 #define AP_DEAUTH_DELAY (1)
 /* Number of seconds to keep STA entry with Authenticated flag after it has
  * been disassociated. */
@@ -220,6 +268,8 @@ int ap_sta_wps_cancel(struct hostapd_data *hapd,
                      struct sta_info *sta, void *ctx);
 #endif /* CONFIG_WPS */
 int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta);
+int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
+                   struct vlan_description *vlan_desc);
 void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
 void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
 int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
@@ -235,6 +285,8 @@ static inline int ap_sta_is_authorized(struct sta_info *sta)
 
 void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta);
 void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
+                                     struct sta_info *sta);
 
 int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen);
 
diff --git a/libeap/src/ap/taxonomy.c b/libeap/src/ap/taxonomy.c
new file mode 100644 (file)
index 0000000..cea8b72
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * hostapd / Client taxonomy
+ * Copyright (c) 2015 Google, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * Parse a series of IEs, as in Probe Request or (Re)Association Request frames,
+ * and render them to a descriptive string. The tag number of standard options
+ * is written to the string, while the vendor ID and subtag are written for
+ * vendor options.
+ *
+ * Example strings:
+ * 0,1,50,45,221(00904c,51)
+ * 0,1,33,36,48,45,221(00904c,51),221(0050f2,2)
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/wpa_ctrl.h"
+#include "hostapd.h"
+#include "sta_info.h"
+
+
+/* Copy a string with no funny schtuff allowed; only alphanumerics. */
+static void no_mischief_strncpy(char *dst, const char *src, size_t n)
+{
+       size_t i;
+
+       for (i = 0; i < n; i++) {
+               unsigned char s = src[i];
+               int is_lower = s >= 'a' && s <= 'z';
+               int is_upper = s >= 'A' && s <= 'Z';
+               int is_digit = s >= '0' && s <= '9';
+
+               if (is_lower || is_upper || is_digit) {
+                       /* TODO: if any manufacturer uses Unicode within the
+                        * WPS header, it will get mangled here. */
+                       dst[i] = s;
+               } else {
+                       /* Note that even spaces will be transformed to
+                        * underscores, so 'Nexus 7' will turn into 'Nexus_7'.
+                        * This is deliberate, to make the string easier to
+                        * parse. */
+                       dst[i] = '_';
+               }
+       }
+}
+
+
+static int get_wps_name(char *name, size_t name_len,
+                       const u8 *data, size_t data_len)
+{
+       /* Inside the WPS IE are a series of attributes, using two byte IDs
+        * and two byte lengths. We're looking for the model name, if
+        * present. */
+       while (data_len >= 4) {
+               u16 id, elen;
+
+               id = WPA_GET_BE16(data);
+               elen = WPA_GET_BE16(data + 2);
+               data += 4;
+               data_len -= 4;
+
+               if (elen > data_len)
+                       return 0;
+
+               if (id == 0x1023) {
+                       /* Model name, like 'Nexus 7' */
+                       size_t n = (elen < name_len) ? elen : name_len;
+                       no_mischief_strncpy(name, (const char *) data, n);
+                       return n;
+               }
+
+               data += elen;
+               data_len -= elen;
+       }
+
+       return 0;
+}
+
+
+static void ie_to_string(char *fstr, size_t fstr_len, const struct wpabuf *ies)
+{
+       char *fpos = fstr;
+       char *fend = fstr + fstr_len;
+       char htcap[7 + 4 + 1]; /* ",htcap:" + %04hx + trailing NUL */
+       char htagg[7 + 2 + 1]; /* ",htagg:" + %02hx + trailing NUL */
+       char htmcs[7 + 8 + 1]; /* ",htmcs:" + %08x + trailing NUL */
+       char vhtcap[8 + 8 + 1]; /* ",vhtcap:" + %08x + trailing NUL */
+       char vhtrxmcs[10 + 8 + 1]; /* ",vhtrxmcs:" + %08x + trailing NUL */
+       char vhttxmcs[10 + 8 + 1]; /* ",vhttxmcs:" + %08x + trailing NUL */
+#define MAX_EXTCAP     254
+       char extcap[8 + 2 * MAX_EXTCAP + 1]; /* ",extcap:" + hex + trailing NUL
+                                             */
+       char txpow[7 + 4 + 1]; /* ",txpow:" + %04hx + trailing NUL */
+#define WPS_NAME_LEN           32
+       char wps[WPS_NAME_LEN + 5 + 1]; /* room to prepend ",wps:" + trailing
+                                        * NUL */
+       int num = 0;
+       const u8 *ie;
+       size_t ie_len;
+       int ret;
+
+       os_memset(htcap, 0, sizeof(htcap));
+       os_memset(htagg, 0, sizeof(htagg));
+       os_memset(htmcs, 0, sizeof(htmcs));
+       os_memset(vhtcap, 0, sizeof(vhtcap));
+       os_memset(vhtrxmcs, 0, sizeof(vhtrxmcs));
+       os_memset(vhttxmcs, 0, sizeof(vhttxmcs));
+       os_memset(extcap, 0, sizeof(extcap));
+       os_memset(txpow, 0, sizeof(txpow));
+       os_memset(wps, 0, sizeof(wps));
+       *fpos = '\0';
+
+       if (!ies)
+               return;
+       ie = wpabuf_head(ies);
+       ie_len = wpabuf_len(ies);
+
+       while (ie_len >= 2) {
+               u8 id, elen;
+               char *sep = (num++ == 0) ? "" : ",";
+
+               id = *ie++;
+               elen = *ie++;
+               ie_len -= 2;
+
+               if (elen > ie_len)
+                       break;
+
+               if (id == WLAN_EID_VENDOR_SPECIFIC && elen >= 4) {
+                       /* Vendor specific */
+                       if (WPA_GET_BE32(ie) == WPS_IE_VENDOR_TYPE) {
+                               /* WPS */
+                               char model_name[WPS_NAME_LEN + 1];
+                               const u8 *data = &ie[4];
+                               size_t data_len = elen - 4;
+
+                               os_memset(model_name, 0, sizeof(model_name));
+                               if (get_wps_name(model_name, WPS_NAME_LEN, data,
+                                                data_len)) {
+                                       os_snprintf(wps, sizeof(wps),
+                                                   ",wps:%s", model_name);
+                               }
+                       }
+
+                       ret = os_snprintf(fpos, fend - fpos,
+                                         "%s%d(%02x%02x%02x,%d)",
+                                         sep, id, ie[0], ie[1], ie[2], ie[3]);
+               } else {
+                       if (id == WLAN_EID_HT_CAP && elen >= 2) {
+                               /* HT Capabilities (802.11n) */
+                               os_snprintf(htcap, sizeof(htcap),
+                                           ",htcap:%04hx",
+                                           WPA_GET_LE16(ie));
+                       }
+                       if (id == WLAN_EID_HT_CAP && elen >= 3) {
+                               /* HT Capabilities (802.11n), A-MPDU information
+                                */
+                               os_snprintf(htagg, sizeof(htagg),
+                                           ",htagg:%02hx", (u16) ie[2]);
+                       }
+                       if (id == WLAN_EID_HT_CAP && elen >= 7) {
+                               /* HT Capabilities (802.11n), MCS information */
+                               os_snprintf(htmcs, sizeof(htmcs),
+                                           ",htmcs:%08hx",
+                                           (u16) WPA_GET_LE32(ie + 3));
+                       }
+                       if (id == WLAN_EID_VHT_CAP && elen >= 4) {
+                               /* VHT Capabilities (802.11ac) */
+                               os_snprintf(vhtcap, sizeof(vhtcap),
+                                           ",vhtcap:%08x",
+                                           WPA_GET_LE32(ie));
+                       }
+                       if (id == WLAN_EID_VHT_CAP && elen >= 8) {
+                               /* VHT Capabilities (802.11ac), RX MCS
+                                * information */
+                               os_snprintf(vhtrxmcs, sizeof(vhtrxmcs),
+                                           ",vhtrxmcs:%08x",
+                                           WPA_GET_LE32(ie + 4));
+                       }
+                       if (id == WLAN_EID_VHT_CAP && elen >= 12) {
+                               /* VHT Capabilities (802.11ac), TX MCS
+                                * information */
+                               os_snprintf(vhttxmcs, sizeof(vhttxmcs),
+                                           ",vhttxmcs:%08x",
+                                           WPA_GET_LE32(ie + 8));
+                       }
+                       if (id == WLAN_EID_EXT_CAPAB) {
+                               /* Extended Capabilities */
+                               int i;
+                               int len = (elen < MAX_EXTCAP) ? elen :
+                                       MAX_EXTCAP;
+                               char *p = extcap;
+
+                               p += os_snprintf(extcap, sizeof(extcap),
+                                                ",extcap:");
+                               for (i = 0; i < len; i++) {
+                                       int lim;
+
+                                       lim = sizeof(extcap) -
+                                               os_strlen(extcap);
+                                       if (lim <= 0)
+                                               break;
+                                       p += os_snprintf(p, lim, "%02x",
+                                                        *(ie + i));
+                               }
+                       }
+                       if (id == WLAN_EID_PWR_CAPABILITY && elen == 2) {
+                               /* TX Power */
+                               os_snprintf(txpow, sizeof(txpow),
+                                           ",txpow:%04hx",
+                                           WPA_GET_LE16(ie));
+                       }
+
+                       ret = os_snprintf(fpos, fend - fpos, "%s%d", sep, id);
+               }
+               if (os_snprintf_error(fend - fpos, ret))
+                       goto fail;
+               fpos += ret;
+
+               ie += elen;
+               ie_len -= elen;
+       }
+
+       ret = os_snprintf(fpos, fend - fpos, "%s%s%s%s%s%s%s%s%s",
+                         htcap, htagg, htmcs, vhtcap, vhtrxmcs, vhttxmcs,
+                         txpow, extcap, wps);
+       if (os_snprintf_error(fend - fpos, ret)) {
+       fail:
+               fstr[0] = '\0';
+       }
+}
+
+
+int retrieve_sta_taxonomy(const struct hostapd_data *hapd,
+                         struct sta_info *sta, char *buf, size_t buflen)
+{
+       int ret;
+       char *pos, *end;
+
+       if (!sta->probe_ie_taxonomy || !sta->assoc_ie_taxonomy)
+               return 0;
+
+       ret = os_snprintf(buf, buflen, "wifi4|probe:");
+       if (os_snprintf_error(buflen, ret))
+               return 0;
+       pos = buf + ret;
+       end = buf + buflen;
+
+       ie_to_string(pos, end - pos, sta->probe_ie_taxonomy);
+       pos = os_strchr(pos, '\0');
+       if (pos >= end)
+               return 0;
+       ret = os_snprintf(pos, end - pos, "|assoc:");
+       if (os_snprintf_error(end - pos, ret))
+               return 0;
+       pos += ret;
+       ie_to_string(pos, end - pos, sta->assoc_ie_taxonomy);
+       pos = os_strchr(pos, '\0');
+       return pos - buf;
+}
+
+
+void taxonomy_sta_info_probe_req(const struct hostapd_data *hapd,
+                                struct sta_info *sta,
+                                const u8 *ie, size_t ie_len)
+{
+       wpabuf_free(sta->probe_ie_taxonomy);
+       sta->probe_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
+}
+
+
+void taxonomy_hostapd_sta_info_probe_req(const struct hostapd_data *hapd,
+                                        struct hostapd_sta_info *info,
+                                        const u8 *ie, size_t ie_len)
+{
+       wpabuf_free(info->probe_ie_taxonomy);
+       info->probe_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
+}
+
+
+void taxonomy_sta_info_assoc_req(const struct hostapd_data *hapd,
+                                struct sta_info *sta,
+                                const u8 *ie, size_t ie_len)
+{
+       wpabuf_free(sta->assoc_ie_taxonomy);
+       sta->assoc_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
+}
diff --git a/libeap/src/ap/taxonomy.h b/libeap/src/ap/taxonomy.h
new file mode 100644 (file)
index 0000000..80f245c
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * hostapd / Station client taxonomy
+ * Copyright (c) 2015 Google, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TAXONOMY_H
+#define TAXONOMY_H
+
+void taxonomy_sta_info_probe_req(const struct hostapd_data *hapd,
+                                struct sta_info *sta,
+                                const u8 *ie, size_t ie_len);
+void taxonomy_hostapd_sta_info_probe_req(const struct hostapd_data *hapd,
+                                        struct hostapd_sta_info *sta,
+                                        const u8 *ie, size_t ie_len);
+void taxonomy_sta_info_assoc_req(const struct hostapd_data *hapd,
+                                struct sta_info *sta,
+                                const u8 *ie, size_t ie_len);
+int retrieve_sta_taxonomy(const struct hostapd_data *hapd,
+                         struct sta_info *sta, char *buf, size_t buflen);
+
+#endif /* TAXONOMY_H */
diff --git a/libeap/src/ap/vlan.c b/libeap/src/ap/vlan.c
new file mode 100644 (file)
index 0000000..b6f6bb1
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * hostapd / VLAN definition
+ * 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.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "ap/vlan.h"
+
+/* compare the two arguments, NULL is treated as empty
+ * return zero iff they are equal
+ */
+int vlan_compare(struct vlan_description *a, struct vlan_description *b)
+{
+       int i;
+       const int a_empty = !a || !a->notempty;
+       const int b_empty = !b || !b->notempty;
+
+       if (a_empty && b_empty)
+               return 0;
+       if (a_empty || b_empty)
+               return 1;
+       if (a->untagged != b->untagged)
+               return 1;
+       for (i = 0; i < MAX_NUM_TAGGED_VLAN; i++) {
+               if (a->tagged[i] != b->tagged[i])
+                       return 1;
+       }
+       return 0;
+}
diff --git a/libeap/src/ap/vlan.h b/libeap/src/ap/vlan.h
new file mode 100644 (file)
index 0000000..af84929
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * hostapd / VLAN definition
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef VLAN_H
+#define VLAN_H
+
+#define MAX_NUM_TAGGED_VLAN 32
+
+struct vlan_description {
+       int notempty; /* 0 : no vlan information present, 1: else */
+       int untagged; /* >0 802.1q vid */
+       int tagged[MAX_NUM_TAGGED_VLAN]; /* first k items, ascending order */
+};
+
+#ifndef CONFIG_NO_VLAN
+int vlan_compare(struct vlan_description *a, struct vlan_description *b);
+#else /* CONFIG_NO_VLAN */
+static inline int
+vlan_compare(struct vlan_description *a, struct vlan_description *b)
+{
+       return 0;
+}
+#endif /* CONFIG_NO_VLAN */
+
+#endif /* VLAN_H */
diff --git a/libeap/src/ap/vlan_full.c b/libeap/src/ap/vlan_full.c
new file mode 100644 (file)
index 0000000..aa42335
--- /dev/null
@@ -0,0 +1,752 @@
+/*
+ * hostapd / VLAN initialization - full dynamic VLAN
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, 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 <net/if.h>
+/* Avoid conflicts due to NetBSD net/if.h if_type define with driver.h */
+#undef if_type
+#include <sys/ioctl.h>
+
+#include "utils/common.h"
+#include "drivers/priv_netlink.h"
+#include "common/linux_bridge.h"
+#include "common/linux_vlan.h"
+#include "utils/eloop.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "wpa_auth.h"
+#include "vlan_init.h"
+#include "vlan_util.h"
+
+
+struct full_dynamic_vlan {
+       int s; /* socket on which to listen for new/removed interfaces. */
+};
+
+#define DVLAN_CLEAN_BR         0x1
+#define DVLAN_CLEAN_VLAN       0x2
+#define DVLAN_CLEAN_VLAN_PORT  0x4
+
+struct dynamic_iface {
+       char ifname[IFNAMSIZ + 1];
+       int usage;
+       int clean;
+       struct dynamic_iface *next;
+};
+
+
+/* Increment ref counter for ifname and add clean flag.
+ * If not in list, add it only if some flags are given.
+ */
+static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
+                         int clean)
+{
+       struct dynamic_iface *next, **dynamic_ifaces;
+       struct hapd_interfaces *interfaces;
+
+       interfaces = hapd->iface->interfaces;
+       dynamic_ifaces = &interfaces->vlan_priv;
+
+       for (next = *dynamic_ifaces; next; next = next->next) {
+               if (os_strcmp(ifname, next->ifname) == 0)
+                       break;
+       }
+
+       if (next) {
+               next->usage++;
+               next->clean |= clean;
+               return;
+       }
+
+       if (!clean)
+               return;
+
+       next = os_zalloc(sizeof(*next));
+       if (!next)
+               return;
+       os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
+       next->usage = 1;
+       next->clean = clean;
+       next->next = *dynamic_ifaces;
+       *dynamic_ifaces = next;
+}
+
+
+/* Decrement reference counter for given ifname.
+ * Return clean flag iff reference counter was decreased to zero, else zero
+ */
+static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
+{
+       struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
+       struct hapd_interfaces *interfaces;
+       int clean;
+
+       interfaces = hapd->iface->interfaces;
+       dynamic_ifaces = &interfaces->vlan_priv;
+
+       for (next = *dynamic_ifaces; next; next = next->next) {
+               if (os_strcmp(ifname, next->ifname) == 0)
+                       break;
+               prev = next;
+       }
+
+       if (!next)
+               return 0;
+
+       next->usage--;
+       if (next->usage)
+               return 0;
+
+       if (prev)
+               prev->next = next->next;
+       else
+               *dynamic_ifaces = next->next;
+       clean = next->clean;
+       os_free(next);
+
+       return clean;
+}
+
+
+static int ifconfig_down(const char *if_name)
+{
+       wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
+       return ifconfig_helper(if_name, 0);
+}
+
+
+/* This value should be 256 ONLY. If it is something else, then hostapd
+ * might crash!, as this value has been hard-coded in 2.4.x kernel
+ * bridging code.
+ */
+#define MAX_BR_PORTS                   256
+
+static int br_delif(const char *br_name, const char *if_name)
+{
+       int fd;
+       struct ifreq ifr;
+       unsigned long args[2];
+       int if_index;
+
+       wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
+       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+               wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+                          "failed: %s", __func__, strerror(errno));
+               return -1;
+       }
+
+       if_index = if_nametoindex(if_name);
+
+       if (if_index == 0) {
+               wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
+                          "interface index for '%s'",
+                          __func__, if_name);
+               close(fd);
+               return -1;
+       }
+
+       args[0] = BRCTL_DEL_IF;
+       args[1] = if_index;
+
+       os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+       ifr.ifr_data = (void *) args;
+
+       if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
+               /* No error if interface already removed. */
+               wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
+                          "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
+                          "%s", __func__, br_name, if_name, strerror(errno));
+               close(fd);
+               return -1;
+       }
+
+       close(fd);
+       return 0;
+}
+
+
+/*
+       Add interface 'if_name' to the bridge 'br_name'
+
+       returns -1 on error
+       returns 1 if the interface is already part of the bridge
+       returns 0 otherwise
+*/
+static int br_addif(const char *br_name, const char *if_name)
+{
+       int fd;
+       struct ifreq ifr;
+       unsigned long args[2];
+       int if_index;
+
+       wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
+       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+               wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+                          "failed: %s", __func__, strerror(errno));
+               return -1;
+       }
+
+       if_index = if_nametoindex(if_name);
+
+       if (if_index == 0) {
+               wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
+                          "interface index for '%s'",
+                          __func__, if_name);
+               close(fd);
+               return -1;
+       }
+
+       args[0] = BRCTL_ADD_IF;
+       args[1] = if_index;
+
+       os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+       ifr.ifr_data = (void *) args;
+
+       if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
+               if (errno == EBUSY) {
+                       /* The interface is already added. */
+                       close(fd);
+                       return 1;
+               }
+
+               wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
+                          "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
+                          "%s", __func__, br_name, if_name, strerror(errno));
+               close(fd);
+               return -1;
+       }
+
+       close(fd);
+       return 0;
+}
+
+
+static int br_delbr(const char *br_name)
+{
+       int fd;
+       unsigned long arg[2];
+
+       wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
+       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+               wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+                          "failed: %s", __func__, strerror(errno));
+               return -1;
+       }
+
+       arg[0] = BRCTL_DEL_BRIDGE;
+       arg[1] = (unsigned long) br_name;
+
+       if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
+               /* No error if bridge already removed. */
+               wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
+                          "%s: %s", __func__, br_name, strerror(errno));
+               close(fd);
+               return -1;
+       }
+
+       close(fd);
+       return 0;
+}
+
+
+/*
+       Add a bridge with the name 'br_name'.
+
+       returns -1 on error
+       returns 1 if the bridge already exists
+       returns 0 otherwise
+*/
+static int br_addbr(const char *br_name)
+{
+       int fd;
+       unsigned long arg[4];
+       struct ifreq ifr;
+
+       wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
+       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+               wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+                          "failed: %s", __func__, strerror(errno));
+               return -1;
+       }
+
+       arg[0] = BRCTL_ADD_BRIDGE;
+       arg[1] = (unsigned long) br_name;
+
+       if (ioctl(fd, SIOCGIFBR, arg) < 0) {
+               if (errno == EEXIST) {
+                       /* The bridge is already added. */
+                       close(fd);
+                       return 1;
+               } else {
+                       wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
+                                  "failed for %s: %s",
+                                  __func__, br_name, strerror(errno));
+                       close(fd);
+                       return -1;
+               }
+       }
+
+       /* Decrease forwarding delay to avoid EAPOL timeouts. */
+       os_memset(&ifr, 0, sizeof(ifr));
+       os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
+       arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
+       arg[1] = 1;
+       arg[2] = 0;
+       arg[3] = 0;
+       ifr.ifr_data = (char *) &arg;
+       if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
+               wpa_printf(MSG_ERROR, "VLAN: %s: "
+                          "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
+                          "%s: %s", __func__, br_name, strerror(errno));
+               /* Continue anyway */
+       }
+
+       close(fd);
+       return 0;
+}
+
+
+static int br_getnumports(const char *br_name)
+{
+       int fd;
+       int i;
+       int port_cnt = 0;
+       unsigned long arg[4];
+       int ifindices[MAX_BR_PORTS];
+       struct ifreq ifr;
+
+       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+               wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+                          "failed: %s", __func__, strerror(errno));
+               return -1;
+       }
+
+       arg[0] = BRCTL_GET_PORT_LIST;
+       arg[1] = (unsigned long) ifindices;
+       arg[2] = MAX_BR_PORTS;
+       arg[3] = 0;
+
+       os_memset(ifindices, 0, sizeof(ifindices));
+       os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+       ifr.ifr_data = (void *) arg;
+
+       if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
+               wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
+                          "failed for %s: %s",
+                          __func__, br_name, strerror(errno));
+               close(fd);
+               return -1;
+       }
+
+       for (i = 1; i < MAX_BR_PORTS; i++) {
+               if (ifindices[i] > 0) {
+                       port_cnt++;
+               }
+       }
+
+       close(fd);
+       return port_cnt;
+}
+
+
+static void vlan_newlink_tagged(int vlan_naming, const char *tagged_interface,
+                               const char *br_name, int vid,
+                               struct hostapd_data *hapd)
+{
+       char vlan_ifname[IFNAMSIZ];
+       int clean;
+
+       if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+               os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
+                           tagged_interface, vid);
+       else
+               os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
+
+       clean = 0;
+       ifconfig_up(tagged_interface);
+       if (!vlan_add(tagged_interface, vid, vlan_ifname))
+               clean |= DVLAN_CLEAN_VLAN;
+
+       if (!br_addif(br_name, vlan_ifname))
+               clean |= DVLAN_CLEAN_VLAN_PORT;
+
+       dyn_iface_get(hapd, vlan_ifname, clean);
+
+       ifconfig_up(vlan_ifname);
+}
+
+
+static void vlan_bridge_name(char *br_name, struct hostapd_data *hapd, int vid)
+{
+       char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+
+       if (hapd->conf->vlan_bridge[0]) {
+               os_snprintf(br_name, IFNAMSIZ, "%s%d",
+                           hapd->conf->vlan_bridge, vid);
+       } else if (tagged_interface) {
+               os_snprintf(br_name, IFNAMSIZ, "br%s.%d",
+                           tagged_interface, vid);
+       } else {
+               os_snprintf(br_name, IFNAMSIZ, "brvlan%d", vid);
+       }
+}
+
+
+static void vlan_get_bridge(const char *br_name, struct hostapd_data *hapd,
+                           int vid)
+{
+       char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+       int vlan_naming = hapd->conf->ssid.vlan_naming;
+
+       dyn_iface_get(hapd, br_name, br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
+
+       ifconfig_up(br_name);
+
+       if (tagged_interface)
+               vlan_newlink_tagged(vlan_naming, tagged_interface, br_name,
+                                   vid, hapd);
+}
+
+
+void vlan_newlink(const char *ifname, struct hostapd_data *hapd)
+{
+       char br_name[IFNAMSIZ];
+       struct hostapd_vlan *vlan;
+       int untagged, *tagged, i, notempty;
+
+       wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
+
+       for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+               if (vlan->configured ||
+                   os_strcmp(ifname, vlan->ifname) != 0)
+                       continue;
+               break;
+       }
+       if (!vlan)
+               return;
+
+       vlan->configured = 1;
+
+       notempty = vlan->vlan_desc.notempty;
+       untagged = vlan->vlan_desc.untagged;
+       tagged = vlan->vlan_desc.tagged;
+
+       if (!notempty) {
+               /* Non-VLAN STA */
+               if (hapd->conf->bridge[0] &&
+                   !br_addif(hapd->conf->bridge, ifname))
+                       vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
+       } else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
+               vlan_bridge_name(br_name, hapd, untagged);
+
+               vlan_get_bridge(br_name, hapd, untagged);
+
+               if (!br_addif(br_name, ifname))
+                       vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
+       }
+
+       for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
+               if (tagged[i] == untagged ||
+                   tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
+                   (i > 0 && tagged[i] == tagged[i - 1]))
+                       continue;
+               vlan_bridge_name(br_name, hapd, tagged[i]);
+               vlan_get_bridge(br_name, hapd, tagged[i]);
+               vlan_newlink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
+                                   ifname, br_name, tagged[i], hapd);
+       }
+
+       ifconfig_up(ifname);
+}
+
+
+static void vlan_dellink_tagged(int vlan_naming, const char *tagged_interface,
+                               const char *br_name, int vid,
+                               struct hostapd_data *hapd)
+{
+       char vlan_ifname[IFNAMSIZ];
+       int clean;
+
+       if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+               os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
+                           tagged_interface, vid);
+       else
+               os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
+
+       clean = dyn_iface_put(hapd, vlan_ifname);
+
+       if (clean & DVLAN_CLEAN_VLAN_PORT)
+               br_delif(br_name, vlan_ifname);
+
+       if (clean & DVLAN_CLEAN_VLAN) {
+               ifconfig_down(vlan_ifname);
+               vlan_rem(vlan_ifname);
+       }
+}
+
+
+static void vlan_put_bridge(const char *br_name, struct hostapd_data *hapd,
+                           int vid)
+{
+       int clean;
+       char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+       int vlan_naming = hapd->conf->ssid.vlan_naming;
+
+       if (tagged_interface)
+               vlan_dellink_tagged(vlan_naming, tagged_interface, br_name,
+                                   vid, hapd);
+
+       clean = dyn_iface_put(hapd, br_name);
+       if ((clean & DVLAN_CLEAN_BR) && br_getnumports(br_name) == 0) {
+               ifconfig_down(br_name);
+               br_delbr(br_name);
+       }
+}
+
+
+void vlan_dellink(const char *ifname, struct hostapd_data *hapd)
+{
+       struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
+
+       wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
+
+       first = prev = vlan;
+
+       while (vlan) {
+               if (os_strcmp(ifname, vlan->ifname) != 0) {
+                       prev = vlan;
+                       vlan = vlan->next;
+                       continue;
+               }
+               break;
+       }
+       if (!vlan)
+               return;
+
+       if (vlan->configured) {
+               int notempty = vlan->vlan_desc.notempty;
+               int untagged = vlan->vlan_desc.untagged;
+               int *tagged = vlan->vlan_desc.tagged;
+               char br_name[IFNAMSIZ];
+               int i;
+
+               for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
+                       if (tagged[i] == untagged ||
+                           tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
+                           (i > 0 && tagged[i] == tagged[i - 1]))
+                               continue;
+                       vlan_bridge_name(br_name, hapd, tagged[i]);
+                       vlan_dellink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
+                                           ifname, br_name, tagged[i], hapd);
+                       vlan_put_bridge(br_name, hapd, tagged[i]);
+               }
+
+               if (!notempty) {
+                       /* Non-VLAN STA */
+                       if (hapd->conf->bridge[0] &&
+                           (vlan->clean & DVLAN_CLEAN_WLAN_PORT))
+                               br_delif(hapd->conf->bridge, ifname);
+               } else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
+                       vlan_bridge_name(br_name, hapd, untagged);
+
+                       if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
+                               br_delif(br_name, vlan->ifname);
+
+                       vlan_put_bridge(br_name, hapd, untagged);
+               }
+       }
+
+       /*
+        * Ensure this VLAN interface is actually removed even if
+        * NEWLINK message is only received later.
+        */
+       if (if_nametoindex(vlan->ifname) && vlan_if_remove(hapd, vlan))
+               wpa_printf(MSG_ERROR,
+                          "VLAN: Could not remove VLAN iface: %s: %s",
+                          vlan->ifname, strerror(errno));
+
+       if (vlan == first)
+               hapd->conf->vlan = vlan->next;
+       else
+               prev->next = vlan->next;
+
+       os_free(vlan);
+}
+
+
+static void
+vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
+                 struct hostapd_data *hapd)
+{
+       struct ifinfomsg *ifi;
+       int attrlen, nlmsg_len, rta_len;
+       struct rtattr *attr;
+       char ifname[IFNAMSIZ + 1];
+
+       if (len < sizeof(*ifi))
+               return;
+
+       ifi = NLMSG_DATA(h);
+
+       nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+       attrlen = h->nlmsg_len - nlmsg_len;
+       if (attrlen < 0)
+               return;
+
+       attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+       os_memset(ifname, 0, sizeof(ifname));
+       rta_len = RTA_ALIGN(sizeof(struct rtattr));
+       while (RTA_OK(attr, attrlen)) {
+               if (attr->rta_type == IFLA_IFNAME) {
+                       int n = attr->rta_len - rta_len;
+                       if (n < 0)
+                               break;
+
+                       if ((size_t) n >= sizeof(ifname))
+                               n = sizeof(ifname) - 1;
+                       os_memcpy(ifname, ((char *) attr) + rta_len, n);
+
+               }
+
+               attr = RTA_NEXT(attr, attrlen);
+       }
+
+       if (!ifname[0])
+               return;
+       if (del && if_nametoindex(ifname)) {
+                /* interface still exists, race condition ->
+                 * iface has just been recreated */
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG,
+                  "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
+                  del ? "DEL" : "NEW",
+                  ifi->ifi_index, ifname, 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]" : "");
+
+       if (del)
+               vlan_dellink(ifname, hapd);
+       else
+               vlan_newlink(ifname, hapd);
+}
+
+
+static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+       char buf[8192];
+       int left;
+       struct sockaddr_nl from;
+       socklen_t fromlen;
+       struct nlmsghdr *h;
+       struct hostapd_data *hapd = eloop_ctx;
+
+       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_ERROR, "VLAN: %s: recvfrom failed: %s",
+                                  __func__, strerror(errno));
+               return;
+       }
+
+       h = (struct nlmsghdr *) buf;
+       while (NLMSG_OK(h, left)) {
+               int len, plen;
+
+               len = h->nlmsg_len;
+               plen = len - sizeof(*h);
+               if (len > left || plen < 0) {
+                       wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
+                                  "message: len=%d left=%d plen=%d",
+                                  len, left, plen);
+                       break;
+               }
+
+               switch (h->nlmsg_type) {
+               case RTM_NEWLINK:
+                       vlan_read_ifnames(h, plen, 0, hapd);
+                       break;
+               case RTM_DELLINK:
+                       vlan_read_ifnames(h, plen, 1, hapd);
+                       break;
+               }
+
+               h = NLMSG_NEXT(h, left);
+       }
+
+       if (left > 0) {
+               wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
+                          "netlink message", __func__, left);
+       }
+}
+
+
+struct full_dynamic_vlan *
+full_dynamic_vlan_init(struct hostapd_data *hapd)
+{
+       struct sockaddr_nl local;
+       struct full_dynamic_vlan *priv;
+
+       priv = os_zalloc(sizeof(*priv));
+       if (priv == NULL)
+               return NULL;
+
+       vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
+                          DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
+                          VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
+                          VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
+
+       priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+       if (priv->s < 0) {
+               wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
+                          "NETLINK_ROUTE) failed: %s",
+                          __func__, strerror(errno));
+               os_free(priv);
+               return NULL;
+       }
+
+       os_memset(&local, 0, sizeof(local));
+       local.nl_family = AF_NETLINK;
+       local.nl_groups = RTMGRP_LINK;
+       if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+               wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
+                          __func__, strerror(errno));
+               close(priv->s);
+               os_free(priv);
+               return NULL;
+       }
+
+       if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
+       {
+               close(priv->s);
+               os_free(priv);
+               return NULL;
+       }
+
+       return priv;
+}
+
+
+void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
+{
+       if (priv == NULL)
+               return;
+       eloop_unregister_read_sock(priv->s);
+       close(priv->s);
+       os_free(priv);
+}
diff --git a/libeap/src/ap/vlan_ifconfig.c b/libeap/src/ap/vlan_ifconfig.c
new file mode 100644 (file)
index 0000000..ef953a5
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * hostapd / VLAN ifconfig helpers
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, 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 <net/if.h>
+#include <sys/ioctl.h>
+
+#include "utils/common.h"
+#include "vlan_util.h"
+
+
+int ifconfig_helper(const char *if_name, int up)
+{
+       int fd;
+       struct ifreq ifr;
+
+       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+               wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+                          "failed: %s", __func__, strerror(errno));
+               return -1;
+       }
+
+       os_memset(&ifr, 0, sizeof(ifr));
+       os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
+
+       if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
+               wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
+                          "for interface %s: %s",
+                          __func__, if_name, strerror(errno));
+               close(fd);
+               return -1;
+       }
+
+       if (up)
+               ifr.ifr_flags |= IFF_UP;
+       else
+               ifr.ifr_flags &= ~IFF_UP;
+
+       if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
+               wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
+                          "for interface %s (up=%d): %s",
+                          __func__, if_name, up, strerror(errno));
+               close(fd);
+               return -1;
+       }
+
+       close(fd);
+       return 0;
+}
+
+
+int ifconfig_up(const char *if_name)
+{
+       wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
+       return ifconfig_helper(if_name, 1);
+}
+
+
+int iface_exists(const char *ifname)
+{
+       return if_nametoindex(ifname);
+}
index fd1c8dd..31e4fc6 100644 (file)
  */
 
 #include "utils/includes.h"
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-#include <net/if.h>
-#include <sys/ioctl.h>
-#include <linux/sockios.h>
-#include <linux/if_vlan.h>
-#include <linux/if_bridge.h>
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
 
 #include "utils/common.h"
 #include "hostapd.h"
 #include "ap_config.h"
 #include "ap_drv_ops.h"
+#include "wpa_auth.h"
 #include "vlan_init.h"
 #include "vlan_util.h"
 
 
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-
-#include "drivers/priv_netlink.h"
-#include "utils/eloop.h"
-
-
-struct full_dynamic_vlan {
-       int s; /* socket on which to listen for new/removed interfaces. */
-};
-
-#define DVLAN_CLEAN_BR         0x1
-#define DVLAN_CLEAN_VLAN       0x2
-#define DVLAN_CLEAN_VLAN_PORT  0x4
-
-struct dynamic_iface {
-       char ifname[IFNAMSIZ + 1];
-       int usage;
-       int clean;
-       struct dynamic_iface *next;
-};
-
-
-/* Increment ref counter for ifname and add clean flag.
- * If not in list, add it only if some flags are given.
- */
-static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
-                         int clean)
-{
-       struct dynamic_iface *next, **dynamic_ifaces;
-       struct hapd_interfaces *interfaces;
-
-       interfaces = hapd->iface->interfaces;
-       dynamic_ifaces = &interfaces->vlan_priv;
-
-       for (next = *dynamic_ifaces; next; next = next->next) {
-               if (os_strcmp(ifname, next->ifname) == 0)
-                       break;
-       }
-
-       if (next) {
-               next->usage++;
-               next->clean |= clean;
-               return;
-       }
-
-       if (!clean)
-               return;
-
-       next = os_zalloc(sizeof(*next));
-       if (!next)
-               return;
-       os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
-       next->usage = 1;
-       next->clean = clean;
-       next->next = *dynamic_ifaces;
-       *dynamic_ifaces = next;
-}
-
-
-/* Decrement reference counter for given ifname.
- * Return clean flag iff reference counter was decreased to zero, else zero
- */
-static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
-{
-       struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
-       struct hapd_interfaces *interfaces;
-       int clean;
-
-       interfaces = hapd->iface->interfaces;
-       dynamic_ifaces = &interfaces->vlan_priv;
-
-       for (next = *dynamic_ifaces; next; next = next->next) {
-               if (os_strcmp(ifname, next->ifname) == 0)
-                       break;
-               prev = next;
-       }
-
-       if (!next)
-               return 0;
-
-       next->usage--;
-       if (next->usage)
-               return 0;
-
-       if (prev)
-               prev->next = next->next;
-       else
-               *dynamic_ifaces = next->next;
-       clean = next->clean;
-       os_free(next);
-
-       return clean;
-}
-
-
-static int ifconfig_helper(const char *if_name, int up)
-{
-       int fd;
-       struct ifreq ifr;
-
-       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
-                          "failed: %s", __func__, strerror(errno));
-               return -1;
-       }
-
-       os_memset(&ifr, 0, sizeof(ifr));
-       os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
-
-       if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
-                          "for interface %s: %s",
-                          __func__, if_name, strerror(errno));
-               close(fd);
-               return -1;
-       }
-
-       if (up)
-               ifr.ifr_flags |= IFF_UP;
-       else
-               ifr.ifr_flags &= ~IFF_UP;
-
-       if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
-                          "for interface %s (up=%d): %s",
-                          __func__, if_name, up, strerror(errno));
-               close(fd);
-               return -1;
-       }
-
-       close(fd);
-       return 0;
-}
-
-
-static int ifconfig_up(const char *if_name)
-{
-       wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
-       return ifconfig_helper(if_name, 1);
-}
-
-
-static int ifconfig_down(const char *if_name)
-{
-       wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
-       return ifconfig_helper(if_name, 0);
-}
-
-
-/*
- * These are only available in recent linux headers (without the leading
- * underscore).
- */
-#define _GET_VLAN_REALDEV_NAME_CMD     8
-#define _GET_VLAN_VID_CMD              9
-
-/* This value should be 256 ONLY. If it is something else, then hostapd
- * might crash!, as this value has been hard-coded in 2.4.x kernel
- * bridging code.
- */
-#define MAX_BR_PORTS                   256
-
-static int br_delif(const char *br_name, const char *if_name)
-{
-       int fd;
-       struct ifreq ifr;
-       unsigned long args[2];
-       int if_index;
-
-       wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
-       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
-                          "failed: %s", __func__, strerror(errno));
-               return -1;
-       }
-
-       if_index = if_nametoindex(if_name);
-
-       if (if_index == 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
-                          "interface index for '%s'",
-                          __func__, if_name);
-               close(fd);
-               return -1;
-       }
-
-       args[0] = BRCTL_DEL_IF;
-       args[1] = if_index;
-
-       os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
-       ifr.ifr_data = (__caddr_t) args;
-
-       if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
-               /* No error if interface already removed. */
-               wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
-                          "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
-                          "%s", __func__, br_name, if_name, strerror(errno));
-               close(fd);
-               return -1;
-       }
-
-       close(fd);
-       return 0;
-}
-
-
-/*
-       Add interface 'if_name' to the bridge 'br_name'
-
-       returns -1 on error
-       returns 1 if the interface is already part of the bridge
-       returns 0 otherwise
-*/
-static int br_addif(const char *br_name, const char *if_name)
-{
-       int fd;
-       struct ifreq ifr;
-       unsigned long args[2];
-       int if_index;
-
-       wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
-       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
-                          "failed: %s", __func__, strerror(errno));
-               return -1;
-       }
-
-       if_index = if_nametoindex(if_name);
-
-       if (if_index == 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
-                          "interface index for '%s'",
-                          __func__, if_name);
-               close(fd);
-               return -1;
-       }
-
-       args[0] = BRCTL_ADD_IF;
-       args[1] = if_index;
-
-       os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
-       ifr.ifr_data = (__caddr_t) args;
-
-       if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
-               if (errno == EBUSY) {
-                       /* The interface is already added. */
-                       close(fd);
-                       return 1;
-               }
-
-               wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
-                          "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
-                          "%s", __func__, br_name, if_name, strerror(errno));
-               close(fd);
-               return -1;
-       }
-
-       close(fd);
-       return 0;
-}
-
-
-static int br_delbr(const char *br_name)
-{
-       int fd;
-       unsigned long arg[2];
-
-       wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
-       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
-                          "failed: %s", __func__, strerror(errno));
-               return -1;
-       }
-
-       arg[0] = BRCTL_DEL_BRIDGE;
-       arg[1] = (unsigned long) br_name;
-
-       if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
-               /* No error if bridge already removed. */
-               wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
-                          "%s: %s", __func__, br_name, strerror(errno));
-               close(fd);
-               return -1;
-       }
-
-       close(fd);
-       return 0;
-}
-
-
-/*
-       Add a bridge with the name 'br_name'.
-
-       returns -1 on error
-       returns 1 if the bridge already exists
-       returns 0 otherwise
-*/
-static int br_addbr(const char *br_name)
-{
-       int fd;
-       unsigned long arg[4];
-       struct ifreq ifr;
-
-       wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
-       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
-                          "failed: %s", __func__, strerror(errno));
-               return -1;
-       }
-
-       arg[0] = BRCTL_ADD_BRIDGE;
-       arg[1] = (unsigned long) br_name;
-
-       if (ioctl(fd, SIOCGIFBR, arg) < 0) {
-               if (errno == EEXIST) {
-                       /* The bridge is already added. */
-                       close(fd);
-                       return 1;
-               } else {
-                       wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
-                                  "failed for %s: %s",
-                                  __func__, br_name, strerror(errno));
-                       close(fd);
-                       return -1;
-               }
-       }
-
-       /* Decrease forwarding delay to avoid EAPOL timeouts. */
-       os_memset(&ifr, 0, sizeof(ifr));
-       os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
-       arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
-       arg[1] = 1;
-       arg[2] = 0;
-       arg[3] = 0;
-       ifr.ifr_data = (char *) &arg;
-       if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: "
-                          "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
-                          "%s: %s", __func__, br_name, strerror(errno));
-               /* Continue anyway */
-       }
-
-       close(fd);
-       return 0;
-}
-
-
-static int br_getnumports(const char *br_name)
-{
-       int fd;
-       int i;
-       int port_cnt = 0;
-       unsigned long arg[4];
-       int ifindices[MAX_BR_PORTS];
-       struct ifreq ifr;
-
-       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
-                          "failed: %s", __func__, strerror(errno));
-               return -1;
-       }
-
-       arg[0] = BRCTL_GET_PORT_LIST;
-       arg[1] = (unsigned long) ifindices;
-       arg[2] = MAX_BR_PORTS;
-       arg[3] = 0;
-
-       os_memset(ifindices, 0, sizeof(ifindices));
-       os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
-       ifr.ifr_data = (__caddr_t) arg;
-
-       if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
-                          "failed for %s: %s",
-                          __func__, br_name, strerror(errno));
-               close(fd);
-               return -1;
-       }
-
-       for (i = 1; i < MAX_BR_PORTS; i++) {
-               if (ifindices[i] > 0) {
-                       port_cnt++;
-               }
-       }
-
-       close(fd);
-       return port_cnt;
-}
-
-
-#ifndef CONFIG_VLAN_NETLINK
-
-int vlan_rem(const char *if_name)
-{
-       int fd;
-       struct vlan_ioctl_args if_request;
-
-       wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
-       if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
-               wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
-                          if_name);
-               return -1;
-       }
-
-       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
-                          "failed: %s", __func__, strerror(errno));
-               return -1;
-       }
-
-       os_memset(&if_request, 0, sizeof(if_request));
-
-       os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
-       if_request.cmd = DEL_VLAN_CMD;
-
-       if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
-                          "%s", __func__, if_name, strerror(errno));
-               close(fd);
-               return -1;
-       }
-
-       close(fd);
-       return 0;
-}
-
-
-/*
-       Add a vlan interface with VLAN ID 'vid' and tagged interface
-       'if_name'.
-
-       returns -1 on error
-       returns 1 if the interface already exists
-       returns 0 otherwise
-*/
-int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
-{
-       int fd;
-       struct vlan_ioctl_args if_request;
-
-       wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
-                  if_name, vid);
-       ifconfig_up(if_name);
-
-       if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
-               wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
-                          if_name);
-               return -1;
-       }
-
-       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
-                          "failed: %s", __func__, strerror(errno));
-               return -1;
-       }
-
-       os_memset(&if_request, 0, sizeof(if_request));
-
-       /* Determine if a suitable vlan device already exists. */
-
-       os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
-                   vid);
-
-       if_request.cmd = _GET_VLAN_VID_CMD;
-
-       if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
-
-               if (if_request.u.VID == vid) {
-                       if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
-
-                       if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
-                           os_strncmp(if_request.u.device2, if_name,
-                                      sizeof(if_request.u.device2)) == 0) {
-                               close(fd);
-                               wpa_printf(MSG_DEBUG, "VLAN: vlan_add: "
-                                          "if_name %s exists already",
-                                          if_request.device1);
-                               return 1;
-                       }
-               }
-       }
-
-       /* A suitable vlan device does not already exist, add one. */
-
-       os_memset(&if_request, 0, sizeof(if_request));
-       os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
-       if_request.u.VID = vid;
-       if_request.cmd = ADD_VLAN_CMD;
-
-       if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: "
-                          "%s",
-                          __func__, if_request.device1, strerror(errno));
-               close(fd);
-               return -1;
-       }
-
-       close(fd);
-       return 0;
-}
-
-
-static int vlan_set_name_type(unsigned int name_type)
+static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
+                      int existsok)
 {
-       int fd;
-       struct vlan_ioctl_args if_request;
+       int ret, i;
 
-       wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
-                  name_type);
-       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
-                          "failed: %s", __func__, strerror(errno));
+       for (i = 0; i < NUM_WEP_KEYS; i++) {
+               if (!hapd->conf->ssid.wep.key[i])
+                       continue;
+               wpa_printf(MSG_ERROR,
+                          "VLAN: Refusing to set up VLAN iface %s with WEP",
+                          vlan->ifname);
                return -1;
        }
 
-       os_memset(&if_request, 0, sizeof(if_request));
-
-       if_request.u.name_type = name_type;
-       if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
-       if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD "
-                          "name_type=%u failed: %s",
-                          __func__, name_type, strerror(errno));
-               close(fd);
+       if (!iface_exists(vlan->ifname))
+               ret = hostapd_vlan_if_add(hapd, vlan->ifname);
+       else if (!existsok)
                return -1;
-       }
-
-       close(fd);
-       return 0;
-}
-
-#endif /* CONFIG_VLAN_NETLINK */
-
-
-static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
-{
-       char vlan_ifname[IFNAMSIZ];
-       char br_name[IFNAMSIZ];
-       struct hostapd_vlan *vlan = hapd->conf->vlan;
-       char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
-       int vlan_naming = hapd->conf->ssid.vlan_naming;
-       int clean;
-
-       wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
-
-       while (vlan) {
-               if (os_strcmp(ifname, vlan->ifname) == 0 && !vlan->configured) {
-                       vlan->configured = 1;
-
-                       if (hapd->conf->vlan_bridge[0]) {
-                               os_snprintf(br_name, sizeof(br_name), "%s%d",
-                                           hapd->conf->vlan_bridge,
-                                           vlan->vlan_id);
-                       } else if (tagged_interface) {
-                               os_snprintf(br_name, sizeof(br_name),
-                                           "br%s.%d", tagged_interface,
-                                           vlan->vlan_id);
-                       } else {
-                               os_snprintf(br_name, sizeof(br_name),
-                                           "brvlan%d", vlan->vlan_id);
-                       }
-
-                       dyn_iface_get(hapd, br_name,
-                                     br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
-
-                       ifconfig_up(br_name);
-
-                       if (tagged_interface) {
-                               if (vlan_naming ==
-                                   DYNAMIC_VLAN_NAMING_WITH_DEVICE)
-                                       os_snprintf(vlan_ifname,
-                                                   sizeof(vlan_ifname),
-                                                   "%s.%d", tagged_interface,
-                                                   vlan->vlan_id);
-                               else
-                                       os_snprintf(vlan_ifname,
-                                                   sizeof(vlan_ifname),
-                                                   "vlan%d", vlan->vlan_id);
-
-                               clean = 0;
-                               ifconfig_up(tagged_interface);
-                               if (!vlan_add(tagged_interface, vlan->vlan_id,
-                                             vlan_ifname))
-                                       clean |= DVLAN_CLEAN_VLAN;
-
-                               if (!br_addif(br_name, vlan_ifname))
-                                       clean |= DVLAN_CLEAN_VLAN_PORT;
-
-                               dyn_iface_get(hapd, vlan_ifname, clean);
-
-                               ifconfig_up(vlan_ifname);
-                       }
-
-                       if (!br_addif(br_name, ifname))
-                               vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
-
-                       ifconfig_up(ifname);
-
-                       break;
-               }
-               vlan = vlan->next;
-       }
-}
-
-
-static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
-{
-       char vlan_ifname[IFNAMSIZ];
-       char br_name[IFNAMSIZ];
-       struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
-       char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
-       int vlan_naming = hapd->conf->ssid.vlan_naming;
-       int clean;
-
-       wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
-
-       first = prev = vlan;
-
-       while (vlan) {
-               if (os_strcmp(ifname, vlan->ifname) == 0 &&
-                   vlan->configured) {
-                       if (hapd->conf->vlan_bridge[0]) {
-                               os_snprintf(br_name, sizeof(br_name), "%s%d",
-                                           hapd->conf->vlan_bridge,
-                                           vlan->vlan_id);
-                       } else if (tagged_interface) {
-                               os_snprintf(br_name, sizeof(br_name),
-                                           "br%s.%d", tagged_interface,
-                                           vlan->vlan_id);
-                       } else {
-                               os_snprintf(br_name, sizeof(br_name),
-                                           "brvlan%d", vlan->vlan_id);
-                       }
-
-                       if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
-                               br_delif(br_name, vlan->ifname);
-
-                       if (tagged_interface) {
-                               if (vlan_naming ==
-                                   DYNAMIC_VLAN_NAMING_WITH_DEVICE)
-                                       os_snprintf(vlan_ifname,
-                                                   sizeof(vlan_ifname),
-                                                   "%s.%d", tagged_interface,
-                                                   vlan->vlan_id);
-                               else
-                                       os_snprintf(vlan_ifname,
-                                                   sizeof(vlan_ifname),
-                                                   "vlan%d", vlan->vlan_id);
-
-                               clean = dyn_iface_put(hapd, vlan_ifname);
-
-                               if (clean & DVLAN_CLEAN_VLAN_PORT)
-                                       br_delif(br_name, vlan_ifname);
-
-                               if (clean & DVLAN_CLEAN_VLAN) {
-                                       ifconfig_down(vlan_ifname);
-                                       vlan_rem(vlan_ifname);
-                               }
-                       }
-
-                       clean = dyn_iface_put(hapd, br_name);
-                       if ((clean & DVLAN_CLEAN_BR) &&
-                           br_getnumports(br_name) == 0) {
-                               ifconfig_down(br_name);
-                               br_delbr(br_name);
-                       }
-               }
-
-               if (os_strcmp(ifname, vlan->ifname) == 0) {
-                       if (vlan == first) {
-                               hapd->conf->vlan = vlan->next;
-                       } else {
-                               prev->next = vlan->next;
-                       }
-                       os_free(vlan);
-
-                       break;
-               }
-               prev = vlan;
-               vlan = vlan->next;
-       }
-}
-
-
-static void
-vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
-                 struct hostapd_data *hapd)
-{
-       struct ifinfomsg *ifi;
-       int attrlen, nlmsg_len, rta_len;
-       struct rtattr *attr;
-       char ifname[IFNAMSIZ + 1];
-
-       if (len < sizeof(*ifi))
-               return;
-
-       ifi = NLMSG_DATA(h);
-
-       nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
-
-       attrlen = h->nlmsg_len - nlmsg_len;
-       if (attrlen < 0)
-               return;
-
-       attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
-
-       os_memset(ifname, 0, sizeof(ifname));
-       rta_len = RTA_ALIGN(sizeof(struct rtattr));
-       while (RTA_OK(attr, attrlen)) {
-               if (attr->rta_type == IFLA_IFNAME) {
-                       int n = attr->rta_len - rta_len;
-                       if (n < 0)
-                               break;
-
-                       if ((size_t) n >= sizeof(ifname))
-                               n = sizeof(ifname) - 1;
-                       os_memcpy(ifname, ((char *) attr) + rta_len, n);
-
-               }
-
-               attr = RTA_NEXT(attr, attrlen);
-       }
-
-       if (!ifname[0])
-               return;
-       if (del && if_nametoindex(ifname)) {
-                /* interface still exists, race condition ->
-                 * iface has just been recreated */
-               return;
-       }
-
-       wpa_printf(MSG_DEBUG,
-                  "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
-                  del ? "DEL" : "NEW",
-                  ifi->ifi_index, ifname, 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]" : "");
-
-       if (del)
-               vlan_dellink(ifname, hapd);
        else
-               vlan_newlink(ifname, hapd);
-}
-
-
-static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
-{
-       char buf[8192];
-       int left;
-       struct sockaddr_nl from;
-       socklen_t fromlen;
-       struct nlmsghdr *h;
-       struct hostapd_data *hapd = eloop_ctx;
-
-       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_ERROR, "VLAN: %s: recvfrom failed: %s",
-                                  __func__, strerror(errno));
-               return;
-       }
-
-       h = (struct nlmsghdr *) buf;
-       while (NLMSG_OK(h, left)) {
-               int len, plen;
-
-               len = h->nlmsg_len;
-               plen = len - sizeof(*h);
-               if (len > left || plen < 0) {
-                       wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
-                                  "message: len=%d left=%d plen=%d",
-                                  len, left, plen);
-                       break;
-               }
-
-               switch (h->nlmsg_type) {
-               case RTM_NEWLINK:
-                       vlan_read_ifnames(h, plen, 0, hapd);
-                       break;
-               case RTM_DELLINK:
-                       vlan_read_ifnames(h, plen, 1, hapd);
-                       break;
-               }
+               ret = 0;
 
-               h = NLMSG_NEXT(h, left);
-       }
+       if (ret)
+               return ret;
 
-       if (left > 0) {
-               wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
-                          "netlink message", __func__, left);
-       }
-}
+       ifconfig_up(vlan->ifname); /* else wpa group will fail fatal */
 
+       if (hapd->wpa_auth)
+               ret = wpa_auth_ensure_group(hapd->wpa_auth, vlan->vlan_id);
 
-static struct full_dynamic_vlan *
-full_dynamic_vlan_init(struct hostapd_data *hapd)
-{
-       struct sockaddr_nl local;
-       struct full_dynamic_vlan *priv;
+       if (ret == 0)
+               return ret;
 
-       priv = os_zalloc(sizeof(*priv));
-       if (priv == NULL)
-               return NULL;
+       wpa_printf(MSG_ERROR, "WPA initialization for VLAN %d failed (%d)",
+                  vlan->vlan_id, ret);
+       if (wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id))
+               wpa_printf(MSG_ERROR, "WPA deinit of %s failed", vlan->ifname);
 
-#ifndef CONFIG_VLAN_NETLINK
-       vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
-                          DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
-                          VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
-                          VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
-#endif /* CONFIG_VLAN_NETLINK */
+       /* group state machine setup failed */
+       if (hostapd_vlan_if_remove(hapd, vlan->ifname))
+               wpa_printf(MSG_ERROR, "Removal of %s failed", vlan->ifname);
 
-       priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
-       if (priv->s < 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
-                          "NETLINK_ROUTE) failed: %s",
-                          __func__, strerror(errno));
-               os_free(priv);
-               return NULL;
-       }
-
-       os_memset(&local, 0, sizeof(local));
-       local.nl_family = AF_NETLINK;
-       local.nl_groups = RTMGRP_LINK;
-       if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
-               wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
-                          __func__, strerror(errno));
-               close(priv->s);
-               os_free(priv);
-               return NULL;
-       }
-
-       if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
-       {
-               close(priv->s);
-               os_free(priv);
-               return NULL;
-       }
-
-       return priv;
-}
-
-
-static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
-{
-       if (priv == NULL)
-               return;
-       eloop_unregister_read_sock(priv->s);
-       close(priv->s);
-       os_free(priv);
+       return ret;
 }
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
 
 
-int vlan_setup_encryption_dyn(struct hostapd_data *hapd, const char *dyn_vlan)
+int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
 {
-        int i;
+       int ret;
 
-        if (dyn_vlan == NULL)
-               return 0;
+       ret = wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id);
+       if (ret)
+               wpa_printf(MSG_ERROR,
+                          "WPA deinitialization for VLAN %d failed (%d)",
+                          vlan->vlan_id, ret);
 
-       /* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
-        * functions for setting up dynamic broadcast keys. */
-       for (i = 0; i < 4; i++) {
-               if (hapd->conf->ssid.wep.key[i] &&
-                   hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
-                                       i == hapd->conf->ssid.wep.idx, NULL, 0,
-                                       hapd->conf->ssid.wep.key[i],
-                                       hapd->conf->ssid.wep.len[i]))
-               {
-                       wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
-                                  "encryption for dynamic VLAN");
-                       return -1;
-               }
-       }
-
-       return 0;
+       return hostapd_vlan_if_remove(hapd, vlan->ifname);
 }
 
 
@@ -913,17 +83,14 @@ static int vlan_dynamic_add(struct hostapd_data *hapd,
 {
        while (vlan) {
                if (vlan->vlan_id != VLAN_ID_WILDCARD) {
-                       if (hostapd_vlan_if_add(hapd, vlan->ifname)) {
-                               if (errno != EEXIST) {
-                                       wpa_printf(MSG_ERROR, "VLAN: Could "
-                                                  "not add VLAN %s: %s",
-                                                  vlan->ifname,
-                                                  strerror(errno));
-                                       return -1;
-                               }
+                       if (vlan_if_add(hapd, vlan, 1)) {
+                               wpa_printf(MSG_ERROR,
+                                          "VLAN: Could not add VLAN %s: %s",
+                                          vlan->ifname, strerror(errno));
+                               return -1;
                        }
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
-                       ifconfig_up(vlan->ifname);
+                       vlan_newlink(vlan->ifname, hapd);
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
                }
 
@@ -942,15 +109,17 @@ static void vlan_dynamic_remove(struct hostapd_data *hapd,
        while (vlan) {
                next = vlan->next;
 
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+               /* vlan_dellink() takes care of cleanup and interface removal */
+               if (vlan->vlan_id != VLAN_ID_WILDCARD)
+                       vlan_dellink(vlan->ifname, hapd);
+#else /* CONFIG_FULL_DYNAMIC_VLAN */
                if (vlan->vlan_id != VLAN_ID_WILDCARD &&
-                   hostapd_vlan_if_remove(hapd, vlan->ifname)) {
+                   vlan_if_remove(hapd, vlan)) {
                        wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
                                   "iface: %s: %s",
                                   vlan->ifname, strerror(errno));
                }
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-               if (vlan->clean)
-                       vlan_dellink(vlan->ifname, hapd);
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
 
                vlan = next;
@@ -964,7 +133,8 @@ int vlan_init(struct hostapd_data *hapd)
        hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
 
-       if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
+       if ((hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED ||
+            hapd->conf->ssid.per_sta_vif) &&
            !hapd->conf->vlan) {
                /* dynamic vlans enabled but no (or empty) vlan_file given */
                struct hostapd_vlan *vlan;
@@ -1002,50 +172,45 @@ void vlan_deinit(struct hostapd_data *hapd)
 
 struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
                                       struct hostapd_vlan *vlan,
-                                      int vlan_id)
+                                      int vlan_id,
+                                      struct vlan_description *vlan_desc)
 {
-       struct hostapd_vlan *n = NULL;
-       char *ifname, *pos;
+       struct hostapd_vlan *n;
+       char ifname[IFNAMSIZ + 1], *pos;
 
-       if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
-           vlan->vlan_id != VLAN_ID_WILDCARD)
+       if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD)
                return NULL;
 
        wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
                   __func__, vlan_id, vlan->ifname);
-       ifname = os_strdup(vlan->ifname);
-       if (ifname == NULL)
-               return NULL;
+       os_strlcpy(ifname, vlan->ifname, sizeof(ifname));
        pos = os_strchr(ifname, '#');
        if (pos == NULL)
-               goto free_ifname;
+               return NULL;
        *pos++ = '\0';
 
        n = os_zalloc(sizeof(*n));
        if (n == NULL)
-               goto free_ifname;
+               return NULL;
 
        n->vlan_id = vlan_id;
+       if (vlan_desc)
+               n->vlan_desc = *vlan_desc;
        n->dynamic_vlan = 1;
 
        os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
                    pos);
 
-       if (hostapd_vlan_if_add(hapd, n->ifname)) {
-               os_free(n);
-               n = NULL;
-               goto free_ifname;
-       }
-
        n->next = hapd->conf->vlan;
        hapd->conf->vlan = n;
 
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-       ifconfig_up(n->ifname);
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+       /* hapd->conf->vlan needs this new VLAN here for WPA setup */
+       if (vlan_if_add(hapd, n, 0)) {
+               hapd->conf->vlan = n->next;
+               os_free(n);
+               n = NULL;
+       }
 
-free_ifname:
-       os_free(ifname);
        return n;
 }
 
@@ -1054,7 +219,7 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
 {
        struct hostapd_vlan *vlan;
 
-       if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
+       if (vlan_id <= 0)
                return 1;
 
        wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
@@ -1073,7 +238,7 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
                return 1;
 
        if (vlan->dynamic_vlan == 0) {
-               hostapd_vlan_if_remove(hapd, vlan->ifname);
+               vlan_if_remove(hapd, vlan);
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
                vlan_dellink(vlan->ifname, hapd);
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
index fc39443..d17c82c 100644 (file)
@@ -15,10 +15,9 @@ int vlan_init(struct hostapd_data *hapd);
 void vlan_deinit(struct hostapd_data *hapd);
 struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
                                       struct hostapd_vlan *vlan,
-                                      int vlan_id);
+                                      int vlan_id,
+                                      struct vlan_description *vlan_desc);
 int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id);
-int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
-                             const char *dyn_vlan);
 #else /* CONFIG_NO_VLAN */
 static inline int vlan_init(struct hostapd_data *hapd)
 {
@@ -29,9 +28,9 @@ static inline void vlan_deinit(struct hostapd_data *hapd)
 {
 }
 
-static inline struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
-                                                    struct hostapd_vlan *vlan,
-                                                    int vlan_id)
+static inline struct hostapd_vlan *
+vlan_add_dynamic(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
+                int vlan_id, struct vlan_description *vlan_desc)
 {
        return NULL;
 }
@@ -40,12 +39,6 @@ static inline int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
 {
        return -1;
 }
-
-static inline int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
-                                           const char *dyn_vlan)
-{
-       return -1;
-}
 #endif /* CONFIG_NO_VLAN */
 
 #endif /* VLAN_INIT_H */
diff --git a/libeap/src/ap/vlan_ioctl.c b/libeap/src/ap/vlan_ioctl.c
new file mode 100644 (file)
index 0000000..987b612
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * hostapd / VLAN ioctl API
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, 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 "utils/common.h"
+#include "common/linux_vlan.h"
+#include "vlan_util.h"
+
+
+int vlan_rem(const char *if_name)
+{
+       int fd;
+       struct vlan_ioctl_args if_request;
+
+       wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
+       if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
+               wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+                          if_name);
+               return -1;
+       }
+
+       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+               wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+                          "failed: %s", __func__, strerror(errno));
+               return -1;
+       }
+
+       os_memset(&if_request, 0, sizeof(if_request));
+
+       os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
+       if_request.cmd = DEL_VLAN_CMD;
+
+       if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+               wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
+                          "%s", __func__, if_name, strerror(errno));
+               close(fd);
+               return -1;
+       }
+
+       close(fd);
+       return 0;
+}
+
+
+/*
+       Add a vlan interface with VLAN ID 'vid' and tagged interface
+       'if_name'.
+
+       returns -1 on error
+       returns 1 if the interface already exists
+       returns 0 otherwise
+*/
+int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
+{
+       int fd;
+       struct vlan_ioctl_args if_request;
+
+       wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
+                  if_name, vid);
+       ifconfig_up(if_name);
+
+       if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
+               wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+                          if_name);
+               return -1;
+       }
+
+       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+               wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+                          "failed: %s", __func__, strerror(errno));
+               return -1;
+       }
+
+       os_memset(&if_request, 0, sizeof(if_request));
+
+       /* Determine if a suitable vlan device already exists. */
+
+       os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
+                   vid);
+
+       if_request.cmd = GET_VLAN_VID_CMD;
+
+       if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
+           if_request.u.VID == vid) {
+               if_request.cmd = GET_VLAN_REALDEV_NAME_CMD;
+
+               if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
+                   os_strncmp(if_request.u.device2, if_name,
+                              sizeof(if_request.u.device2)) == 0) {
+                       close(fd);
+                       wpa_printf(MSG_DEBUG,
+                                  "VLAN: vlan_add: if_name %s exists already",
+                                  if_request.device1);
+                       return 1;
+               }
+       }
+
+       /* A suitable vlan device does not already exist, add one. */
+
+       os_memset(&if_request, 0, sizeof(if_request));
+       os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
+       if_request.u.VID = vid;
+       if_request.cmd = ADD_VLAN_CMD;
+
+       if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+               wpa_printf(MSG_ERROR,
+                          "VLAN: %s: ADD_VLAN_CMD failed for %s: %s",
+                          __func__, if_request.device1, strerror(errno));
+               close(fd);
+               return -1;
+       }
+
+       close(fd);
+       return 0;
+}
+
+
+int vlan_set_name_type(unsigned int name_type)
+{
+       int fd;
+       struct vlan_ioctl_args if_request;
+
+       wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
+                  name_type);
+       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+               wpa_printf(MSG_ERROR,
+                          "VLAN: %s: socket(AF_INET,SOCK_STREAM) failed: %s",
+                          __func__, strerror(errno));
+               return -1;
+       }
+
+       os_memset(&if_request, 0, sizeof(if_request));
+
+       if_request.u.name_type = name_type;
+       if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
+       if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+               wpa_printf(MSG_ERROR,
+                          "VLAN: %s: SET_VLAN_NAME_TYPE_CMD name_type=%u failed: %s",
+                          __func__, name_type, strerror(errno));
+               close(fd);
+               return -1;
+       }
+
+       close(fd);
+       return 0;
+}
index d4e0efb..56d1d3d 100644 (file)
@@ -7,18 +7,10 @@
  */
 
 #include "utils/includes.h"
-#include <sys/ioctl.h>
-#include <linux/sockios.h>
-#include <linux/if_vlan.h>
-#include <netlink/genl/genl.h>
-#include <netlink/genl/family.h>
-#include <netlink/genl/ctrl.h>
 #include <netlink/route/link.h>
 #include <netlink/route/link/vlan.h>
 
 #include "utils/common.h"
-#include "utils/eloop.h"
-#include "hostapd.h"
 #include "vlan_util.h"
 
 /*
@@ -33,7 +25,6 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
 {
        int err, ret = -1;
        struct nl_sock *handle = NULL;
-       struct nl_cache *cache = NULL;
        struct rtnl_link *rlink = NULL;
        int if_idx = 0;
 
@@ -65,22 +56,19 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
                goto vlan_add_error;
        }
 
-       err = rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache);
+       err = rtnl_link_get_kernel(handle, 0, if_name, &rlink);
        if (err < 0) {
-               cache = NULL;
-               wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache: %s",
-                          nl_geterror(err));
-               goto vlan_add_error;
-       }
-
-       if (!(if_idx = rtnl_link_name2i(cache, if_name))) {
                /* link does not exist */
                wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist",
                           if_name);
                goto vlan_add_error;
        }
+       if_idx = rtnl_link_get_ifindex(rlink);
+       rtnl_link_put(rlink);
+       rlink = NULL;
 
-       if ((rlink = rtnl_link_get_by_name(cache, vlan_if_name))) {
+       err = rtnl_link_get_kernel(handle, 0, vlan_if_name, &rlink);
+       if (err >= 0) {
                /* link does exist */
                rtnl_link_put(rlink);
                rlink = NULL;
@@ -127,8 +115,6 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
 vlan_add_error:
        if (rlink)
                rtnl_link_put(rlink);
-       if (cache)
-               nl_cache_free(cache);
        if (handle)
                nl_socket_free(handle);
        return ret;
@@ -139,7 +125,6 @@ int vlan_rem(const char *if_name)
 {
        int err, ret = -1;
        struct nl_sock *handle = NULL;
-       struct nl_cache *cache = NULL;
        struct rtnl_link *rlink = NULL;
 
        wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name);
@@ -157,15 +142,8 @@ int vlan_rem(const char *if_name)
                goto vlan_rem_error;
        }
 
-       err = rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache);
+       err = rtnl_link_get_kernel(handle, 0, if_name, &rlink);
        if (err < 0) {
-               cache = NULL;
-               wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache: %s",
-                          nl_geterror(err));
-               goto vlan_rem_error;
-       }
-
-       if (!(rlink = rtnl_link_get_by_name(cache, if_name))) {
                /* link does not exist */
                wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists",
                           if_name);
@@ -184,9 +162,13 @@ int vlan_rem(const char *if_name)
 vlan_rem_error:
        if (rlink)
                rtnl_link_put(rlink);
-       if (cache)
-               nl_cache_free(cache);
        if (handle)
                nl_socket_free(handle);
        return ret;
 }
+
+
+int vlan_set_name_type(unsigned int name_type)
+{
+       return 0;
+}
index bef5a16..2446859 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * hostapd / VLAN netlink api
+ * hostapd / VLAN netlink/ioctl api
  * Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de>
  *
  * This software may be distributed under the terms of the BSD license.
@@ -9,7 +9,23 @@
 #ifndef VLAN_UTIL_H
 #define VLAN_UTIL_H
 
+struct hostapd_data;
+struct hostapd_vlan;
+struct full_dynamic_vlan;
+
 int vlan_add(const char *if_name, int vid, const char *vlan_if_name);
 int vlan_rem(const char *if_name);
+int vlan_set_name_type(unsigned int name_type);
+
+int ifconfig_helper(const char *if_name, int up);
+int ifconfig_up(const char *if_name);
+int iface_exists(const char *ifname);
+int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan);
+
+struct full_dynamic_vlan *
+full_dynamic_vlan_init(struct hostapd_data *hapd);
+void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv);
+void vlan_newlink(const char *ifname, struct hostapd_data *hapd);
+void vlan_dellink(const char *ifname, struct hostapd_data *hapd);
 
 #endif /* VLAN_UTIL_H */
index 4c8bc10..41d50ce 100644 (file)
@@ -17,6 +17,7 @@
 #include "ap/ap_config.h"
 #include "ap/ap_drv_ops.h"
 #include "ap/wpa_auth.h"
+#include "mbo_ap.h"
 #include "wnm_ap.h"
 
 #define MAX_TFS_IE_LEN  1024
@@ -94,6 +95,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
        if (mgmt == NULL) {
                wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
                           "WNM-Sleep Response action frame");
+               os_free(wnmtfs_ie);
                return -1;
        }
        os_memcpy(mgmt->da, addr, ETH_ALEN);
@@ -376,6 +378,29 @@ static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
 }
 
 
+static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
+                                              const u8 *addr, const u8 *buf,
+                                              size_t len)
+{
+       u8 dialog_token, type;
+
+       if (len < 2)
+               return;
+       dialog_token = *buf++;
+       type = *buf++;
+       len -= 2;
+
+       wpa_printf(MSG_DEBUG,
+                  "WNM: Received WNM Notification Request frame from "
+                  MACSTR " (dialog_token=%u type=%u)",
+                  MAC2STR(addr), dialog_token, type);
+       wpa_hexdump(MSG_MSGDUMP, "WNM: Notification Request subelements",
+                   buf, len);
+       if (type == WLAN_EID_VENDOR_SPECIFIC)
+               mbo_ap_wnm_notification_req(hapd, addr, buf, len);
+}
+
+
 int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
                                const struct ieee80211_mgmt *mgmt, size_t len)
 {
@@ -402,6 +427,10 @@ int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
        case WNM_SLEEP_MODE_REQ:
                ieee802_11_rx_wnmsleep_req(hapd, mgmt->sa, payload, plen);
                return 0;
+       case WNM_NOTIFICATION_REQ:
+               ieee802_11_rx_wnm_notification_req(hapd, mgmt->sa, payload,
+                                                  plen);
+               return 0;
        }
 
        wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR,
@@ -527,7 +556,8 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
 int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
                        u8 req_mode, int disassoc_timer, u8 valid_int,
                        const u8 *bss_term_dur, const char *url,
-                       const u8 *nei_rep, size_t nei_rep_len)
+                       const u8 *nei_rep, size_t nei_rep_len,
+                       const u8 *mbo_attrs, size_t mbo_len)
 {
        u8 *buf, *pos;
        struct ieee80211_mgmt *mgmt;
@@ -536,7 +566,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
        wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
                   MACSTR " req_mode=0x%x disassoc_timer=%d valid_int=0x%x",
                   MAC2STR(sta->addr), req_mode, disassoc_timer, valid_int);
-       buf = os_zalloc(1000 + nei_rep_len);
+       buf = os_zalloc(1000 + nei_rep_len + mbo_len);
        if (buf == NULL)
                return -1;
        mgmt = (struct ieee80211_mgmt *) buf;
@@ -579,6 +609,11 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
                pos += nei_rep_len;
        }
 
+       if (mbo_len > 0) {
+               pos += mbo_add_ie(pos, buf + sizeof(buf) - pos, mbo_attrs,
+                                 mbo_len);
+       }
+
        if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
                wpa_printf(MSG_DEBUG,
                           "Failed to send BSS Transition Management Request frame");
index 7789307..a44eadb 100644 (file)
@@ -21,6 +21,7 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
 int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
                        u8 req_mode, int disassoc_timer, u8 valid_int,
                        const u8 *bss_term_dur, const char *url,
-                       const u8 *nei_rep, size_t nei_rep_len);
+                       const u8 *nei_rep, size_t nei_rep_len,
+                       const u8 *mbo_attrs, size_t mbo_len);
 
 #endif /* WNM_AP_H */
index 2760a3f..3587086 100644 (file)
@@ -44,7 +44,8 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
 static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
                                       struct wpa_group *group);
 static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
-                         const u8 *pmk, struct wpa_ptk *ptk);
+                         const u8 *pmk, unsigned int pmk_len,
+                         struct wpa_ptk *ptk);
 static void wpa_group_free(struct wpa_authenticator *wpa_auth,
                           struct wpa_group *group);
 static void wpa_group_get(struct wpa_authenticator *wpa_auth,
@@ -827,6 +828,7 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
        struct wpa_ptk PTK;
        int ok = 0;
        const u8 *pmk = NULL;
+       unsigned int pmk_len;
 
        for (;;) {
                if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
@@ -834,10 +836,13 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
                                               sm->p2p_dev_addr, pmk);
                        if (pmk == NULL)
                                break;
-               } else
+                       pmk_len = PMK_LEN;
+               } else {
                        pmk = sm->PMK;
+                       pmk_len = sm->pmk_len;
+               }
 
-               wpa_derive_ptk(sm, sm->alt_SNonce, pmk, &PTK);
+               wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK);
 
                if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK, data, data_len)
                    == 0) {
@@ -1904,11 +1909,27 @@ SM_STATE(WPA_PTK, INITPMK)
 #endif /* CONFIG_IEEE80211R */
        if (sm->pmksa) {
                wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache");
-               os_memcpy(sm->PMK, sm->pmksa->pmk, PMK_LEN);
+               os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len);
+               sm->pmk_len = sm->pmksa->pmk_len;
        } else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) {
+               unsigned int pmk_len;
+
+               if (sm->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+                       pmk_len = PMK_LEN_SUITE_B_192;
+               else
+                       pmk_len = PMK_LEN;
                wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
-                          "(len=%lu)", (unsigned long) len);
-               os_memcpy(sm->PMK, msk, PMK_LEN);
+                          "(MSK len=%lu PMK len=%u)", (unsigned long) 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;
+                       return;
+               }
+               os_memcpy(sm->PMK, msk, pmk_len);
+               sm->pmk_len = pmk_len;
 #ifdef CONFIG_IEEE80211R
                if (len >= 2 * PMK_LEN) {
                        os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
@@ -1943,6 +1964,7 @@ SM_STATE(WPA_PTK, INITPSK)
        psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL);
        if (psk) {
                os_memcpy(sm->PMK, psk, PMK_LEN);
+               sm->pmk_len = PMK_LEN;
 #ifdef CONFIG_IEEE80211R
                os_memcpy(sm->xxkey, psk, PMK_LEN);
                sm->xxkey_len = PMK_LEN;
@@ -1994,7 +2016,7 @@ SM_STATE(WPA_PTK, PTKSTART)
                         * Calculate PMKID since no PMKSA cache entry was
                         * available with pre-calculated PMKID.
                         */
-                       rsn_pmkid(sm->PMK, PMK_LEN, sm->wpa_auth->addr,
+                       rsn_pmkid(sm->PMK, sm->pmk_len, sm->wpa_auth->addr,
                                  sm->addr, &pmkid[2 + RSN_SELECTOR_LEN],
                                  wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
                }
@@ -2006,14 +2028,15 @@ SM_STATE(WPA_PTK, PTKSTART)
 
 
 static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
-                         const u8 *pmk, struct wpa_ptk *ptk)
+                         const u8 *pmk, unsigned int pmk_len,
+                         struct wpa_ptk *ptk)
 {
 #ifdef CONFIG_IEEE80211R
        if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
                return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
 #endif /* CONFIG_IEEE80211R */
 
-       return wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
+       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);
 }
@@ -2024,6 +2047,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
        struct wpa_ptk PTK;
        int ok = 0, psk_found = 0;
        const u8 *pmk = NULL;
+       unsigned int pmk_len;
 
        SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
        sm->EAPOLKeyReceived = FALSE;
@@ -2039,10 +2063,13 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
                        if (pmk == NULL)
                                break;
                        psk_found = 1;
-               } else
+                       pmk_len = PMK_LEN;
+               } else {
                        pmk = sm->PMK;
+                       pmk_len = sm->pmk_len;
+               }
 
-               wpa_derive_ptk(sm, sm->SNonce, pmk, &PTK);
+               wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK);
 
                if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK,
                                       sm->last_rx_eapol_key,
@@ -2092,6 +2119,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
                 * state machine data based on whatever PSK was selected here.
                 */
                os_memcpy(sm->PMK, pmk, PMK_LEN);
+               sm->pmk_len = PMK_LEN;
        }
 
        sm->MICVerified = TRUE;
@@ -2270,14 +2298,19 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
        pos += wpa_ie_len;
 #ifdef CONFIG_IEEE80211R
        if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
-               int res = wpa_insert_pmkid(kde, pos - kde, sm->pmk_r1_name);
+               int res;
+               size_t elen;
+
+               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;
                }
-               pos += res;
+               pos -= wpa_ie_len;
+               pos += elen;
        }
 #endif /* CONFIG_IEEE80211R */
        if (gtk) {
@@ -2295,10 +2328,18 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
                struct wpa_auth_config *conf;
 
                conf = &sm->wpa_auth->conf;
-               res = wpa_write_ftie(conf, conf->r0_key_holder,
-                                    conf->r0_key_holder_len,
-                                    NULL, NULL, pos, kde + kde_len - pos,
-                                    NULL, 0);
+               if (sm->assoc_resp_ftie &&
+                   kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
+                       os_memcpy(pos, sm->assoc_resp_ftie,
+                                 2 + sm->assoc_resp_ftie[1]);
+                       res = 2 + sm->assoc_resp_ftie[1];
+               } else {
+                       res = wpa_write_ftie(conf, conf->r0_key_holder,
+                                            conf->r0_key_holder_len,
+                                            NULL, NULL, pos,
+                                            kde + kde_len - pos,
+                                            NULL, 0);
+               }
                if (res < 0) {
                        wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
                                   "into EAPOL-Key Key Data");
@@ -3243,13 +3284,21 @@ const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len)
 
 
 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 ||
            sm->wpa_auth->conf.disable_pmksa_caching)
                return -1;
 
-       if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
+       if (sm->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+               if (pmk_len > PMK_LEN_SUITE_B_192)
+                       pmk_len = PMK_LEN_SUITE_B_192;
+       } else if (pmk_len > PMK_LEN) {
+               pmk_len = PMK_LEN;
+       }
+
+       if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, pmk_len, NULL,
                                 sm->PTK.kck, sm->PTK.kck_len,
                                 sm->wpa_auth->addr, sm->addr, session_timeout,
                                 eapol, sm->wpa_key_mgmt))
@@ -3267,7 +3316,7 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
        if (wpa_auth == NULL)
                return -1;
 
-       if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len,
+       if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, NULL,
                                 NULL, 0,
                                 wpa_auth->addr,
                                 sta_addr, session_timeout, eapol,
@@ -3279,12 +3328,12 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
 
 
 int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
-                          const u8 *pmk)
+                          const u8 *pmk, const u8 *pmkid)
 {
        if (wpa_auth->conf.disable_pmksa_caching)
                return -1;
 
-       if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN,
+       if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN, pmkid,
                                 NULL, 0,
                                 wpa_auth->addr, addr, 0, NULL,
                                 WPA_KEY_MGMT_SAE))
@@ -3310,6 +3359,46 @@ void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
 }
 
 
+int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
+                       size_t len)
+{
+       if (!wpa_auth || !wpa_auth->pmksa)
+               return 0;
+       return pmksa_cache_auth_list(wpa_auth->pmksa, buf, len);
+}
+
+
+void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth)
+{
+       if (wpa_auth && wpa_auth->pmksa)
+               pmksa_cache_auth_flush(wpa_auth->pmksa);
+}
+
+
+struct rsn_pmksa_cache_entry *
+wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
+{
+       if (!wpa_auth || !wpa_auth->pmksa)
+               return NULL;
+       return pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
+}
+
+
+void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
+                             struct wpa_state_machine *sm,
+                             struct wpa_authenticator *wpa_auth,
+                             u8 *pmkid, u8 *pmk)
+{
+       if (!sm)
+               return;
+
+       sm->pmksa = pmksa;
+       os_memcpy(pmk, pmksa->pmk, PMK_LEN);
+       os_memcpy(pmkid, pmksa->pmkid, PMKID_LEN);
+       os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmksa->pmkid, PMKID_LEN);
+}
+
+
 /*
  * Remove and free the group from wpa_authenticator. This is triggered by a
  * callback to make sure nobody is currently iterating the group list while it
@@ -3388,6 +3477,98 @@ wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
 }
 
 
+/*
+ * Enforce that the group state machine for the VLAN is running, increase
+ * reference counter as interface is up. References might have been increased
+ * even if a negative value is returned.
+ * Returns: -1 on error (group missing, group already failed); otherwise, 0
+ */
+int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id)
+{
+       struct wpa_group *group;
+
+       if (wpa_auth == NULL)
+               return 0;
+
+       group = wpa_auth->group;
+       while (group) {
+               if (group->vlan_id == vlan_id)
+                       break;
+               group = group->next;
+       }
+
+       if (group == NULL) {
+               group = wpa_auth_add_group(wpa_auth, vlan_id);
+               if (group == NULL)
+                       return -1;
+       }
+
+       wpa_printf(MSG_DEBUG,
+                  "WPA: Ensure group state machine running for VLAN ID %d",
+                  vlan_id);
+
+       wpa_group_get(wpa_auth, group);
+       group->num_setup_iface++;
+
+       if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
+               return -1;
+
+       return 0;
+}
+
+
+/*
+ * Decrease reference counter, expected to be zero afterwards.
+ * returns: -1 on error (group not found, group in fail state)
+ *          -2 if wpa_group is still referenced
+ *           0 else
+ */
+int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id)
+{
+       struct wpa_group *group;
+       int ret = 0;
+
+       if (wpa_auth == NULL)
+               return 0;
+
+       group = wpa_auth->group;
+       while (group) {
+               if (group->vlan_id == vlan_id)
+                       break;
+               group = group->next;
+       }
+
+       if (group == NULL)
+               return -1;
+
+       wpa_printf(MSG_DEBUG,
+                  "WPA: Try stopping group state machine for VLAN ID %d",
+                  vlan_id);
+
+       if (group->num_setup_iface <= 0) {
+               wpa_printf(MSG_ERROR,
+                          "WPA: wpa_auth_release_group called more often than wpa_auth_ensure_group for VLAN ID %d, skipping.",
+                          vlan_id);
+               return -1;
+       }
+       group->num_setup_iface--;
+
+       if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
+               ret = -1;
+
+       if (group->references > 1) {
+               wpa_printf(MSG_DEBUG,
+                          "WPA: Cannot stop group state machine for VLAN ID %d as references are still hold",
+                          vlan_id);
+               ret = -2;
+       }
+
+       wpa_group_put(wpa_auth, group);
+
+       return ret;
+}
+
+
 int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
 {
        struct wpa_group *group;
index fd04f16..0de8d97 100644 (file)
@@ -42,10 +42,11 @@ struct ft_rrb_frame {
 #define FT_PACKET_R0KH_R1KH_RESP 201
 #define FT_PACKET_R0KH_R1KH_PUSH 202
 
-#define FT_R0KH_R1KH_PULL_DATA_LEN 44
-#define FT_R0KH_R1KH_RESP_DATA_LEN 76
-#define FT_R0KH_R1KH_PUSH_DATA_LEN 88
 #define FT_R0KH_R1KH_PULL_NONCE_LEN 16
+#define FT_R0KH_R1KH_PULL_DATA_LEN (FT_R0KH_R1KH_PULL_NONCE_LEN + \
+                                   WPA_PMK_NAME_LEN + FT_R1KH_ID_LEN + \
+                                   ETH_ALEN)
+#define FT_R0KH_R1KH_PULL_PAD_LEN ((8 - FT_R0KH_R1KH_PULL_DATA_LEN % 8) % 8)
 
 struct ft_r0kh_r1kh_pull_frame {
        u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
@@ -57,14 +58,18 @@ struct ft_r0kh_r1kh_pull_frame {
        u8 pmk_r0_name[WPA_PMK_NAME_LEN];
        u8 r1kh_id[FT_R1KH_ID_LEN];
        u8 s1kh_id[ETH_ALEN];
-       u8 pad[4]; /* 8-octet boundary for AES key wrap */
+       u8 pad[FT_R0KH_R1KH_PULL_PAD_LEN]; /* 8-octet boundary for AES block */
        u8 key_wrap_extra[8];
 } STRUCT_PACKED;
 
+#define FT_R0KH_R1KH_RESP_DATA_LEN (FT_R0KH_R1KH_PULL_NONCE_LEN + \
+                                   FT_R1KH_ID_LEN + ETH_ALEN + PMK_LEN + \
+                                   WPA_PMK_NAME_LEN + 2)
+#define FT_R0KH_R1KH_RESP_PAD_LEN ((8 - FT_R0KH_R1KH_RESP_DATA_LEN % 8) % 8)
 struct ft_r0kh_r1kh_resp_frame {
        u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
        u8 packet_type; /* FT_PACKET_R0KH_R1KH_RESP */
-       le16 data_length; /* little endian length of data (76) */
+       le16 data_length; /* little endian length of data (78) */
        u8 ap_address[ETH_ALEN];
 
        u8 nonce[FT_R0KH_R1KH_PULL_NONCE_LEN]; /* copied from pull */
@@ -73,14 +78,18 @@ struct ft_r0kh_r1kh_resp_frame {
        u8 pmk_r1[PMK_LEN];
        u8 pmk_r1_name[WPA_PMK_NAME_LEN];
        le16 pairwise;
-       u8 pad[2]; /* 8-octet boundary for AES key wrap */
+       u8 pad[FT_R0KH_R1KH_RESP_PAD_LEN]; /* 8-octet boundary for AES block */
        u8 key_wrap_extra[8];
 } STRUCT_PACKED;
 
+#define FT_R0KH_R1KH_PUSH_DATA_LEN (4 + FT_R1KH_ID_LEN + ETH_ALEN + \
+                                   WPA_PMK_NAME_LEN + PMK_LEN + \
+                                   WPA_PMK_NAME_LEN + 2)
+#define FT_R0KH_R1KH_PUSH_PAD_LEN ((8 - FT_R0KH_R1KH_PUSH_DATA_LEN % 8) % 8)
 struct ft_r0kh_r1kh_push_frame {
        u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
        u8 packet_type; /* FT_PACKET_R0KH_R1KH_PUSH */
-       le16 data_length; /* little endian length of data (88) */
+       le16 data_length; /* little endian length of data (82) */
        u8 ap_address[ETH_ALEN];
 
        /* Encrypted with AES key-wrap */
@@ -92,7 +101,7 @@ struct ft_r0kh_r1kh_push_frame {
        u8 pmk_r1[PMK_LEN];
        u8 pmk_r1_name[WPA_PMK_NAME_LEN];
        le16 pairwise;
-       u8 pad[6]; /* 8-octet boundary for AES key wrap */
+       u8 pad[FT_R0KH_R1KH_PUSH_PAD_LEN]; /* 8-octet boundary for AES block */
        u8 key_wrap_extra[8];
 } STRUCT_PACKED;
 
@@ -279,15 +288,25 @@ 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);
 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);
 int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
                               const u8 *pmk, size_t len, const u8 *sta_addr,
                               int session_timeout,
                               struct eapol_state_machine *eapol);
 int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
-                          const u8 *pmk);
+                          const u8 *pmk, const u8 *pmkid);
 void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
                           const u8 *sta_addr);
+int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
+                       size_t len);
+void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth);
+struct rsn_pmksa_cache_entry *
+wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr);
+void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
+                             struct wpa_state_machine *sm,
+                             struct wpa_authenticator *wpa_auth,
+                             u8 *pmkid, u8 *pmk);
 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);
@@ -325,4 +344,7 @@ int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
                                         struct radius_das_attrs *attr);
 void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth);
 
+int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id);
+int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id);
+
 #endif /* WPA_AUTH_H */
index eeaffbf..42242a5 100644 (file)
@@ -720,11 +720,6 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
        ftie_len = res;
        pos += res;
 
-       os_free(sm->assoc_resp_ftie);
-       sm->assoc_resp_ftie = os_malloc(ftie_len);
-       if (sm->assoc_resp_ftie)
-               os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
-
        _ftie = (struct rsn_ftie *) (ftie + 2);
        if (auth_alg == WLAN_AUTH_FT)
                _ftie->mic_control[1] = 3; /* Information element count */
@@ -750,6 +745,11 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
                       _ftie->mic) < 0)
                wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
 
+       os_free(sm->assoc_resp_ftie);
+       sm->assoc_resp_ftie = os_malloc(ftie_len);
+       if (sm->assoc_resp_ftie)
+               os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
+
        return pos;
 }
 
index f98cc50..2142414 100644 (file)
@@ -12,6 +12,7 @@
 #include "common/ieee802_11_defs.h"
 #include "common/sae.h"
 #include "common/wpa_ctrl.h"
+#include "crypto/sha1.h"
 #include "eapol_auth/eapol_auth_sm.h"
 #include "eapol_auth/eapol_auth_sm_i.h"
 #include "eap_server/eap.h"
@@ -246,6 +247,13 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
                struct hostapd_sta_wpa_psk_short *pos;
                psk = sta->psk->psk;
                for (pos = sta->psk; pos; pos = pos->next) {
+                       if (pos->is_passphrase) {
+                               pbkdf2_sha1(pos->passphrase,
+                                           hapd->conf->ssid.ssid,
+                                           hapd->conf->ssid.ssid_len, 4096,
+                                           pos->psk, PMK_LEN);
+                               pos->is_passphrase = 0;
+                       }
                        if (pos->psk == prev_psk) {
                                psk = pos->next ? pos->next->psk : NULL;
                                break;
@@ -413,6 +421,8 @@ static int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx)
                hapd = iface->bss[j];
                if (hapd == idata->src_hapd)
                        continue;
+               if (!hapd->wpa_auth)
+                       continue;
                if (os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) == 0) {
                        wpa_printf(MSG_DEBUG, "FT: Send RRB data directly to "
                                   "locally managed BSS " MACSTR "@%s -> "
@@ -563,6 +573,9 @@ static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
        ethhdr = (struct l2_ethhdr *) buf;
        wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> "
                   MACSTR, MAC2STR(ethhdr->h_source), MAC2STR(ethhdr->h_dest));
+       if (!is_multicast_ether_addr(ethhdr->h_dest) &&
+           os_memcmp(hapd->own_addr, ethhdr->h_dest, ETH_ALEN) != 0)
+               return;
        wpa_ft_rrb_rx(hapd->wpa_auth, ethhdr->h_source, buf + sizeof(*ethhdr),
                      len - sizeof(*ethhdr));
 }
@@ -637,7 +650,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
        }
 
 #ifdef CONFIG_IEEE80211R
-       if (!hostapd_drv_none(hapd) && hapd->conf->ft_over_ds &&
+       if (!hostapd_drv_none(hapd) &&
            wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
                hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ?
                                          hapd->conf->bridge :
@@ -674,13 +687,14 @@ void hostapd_deinit_wpa(struct hostapd_data *hapd)
                wpa_deinit(hapd->wpa_auth);
                hapd->wpa_auth = NULL;
 
-               if (hostapd_set_privacy(hapd, 0)) {
+               if (hapd->drv_priv && hostapd_set_privacy(hapd, 0)) {
                        wpa_printf(MSG_DEBUG, "Could not disable "
                                   "PrivacyInvoked for interface %s",
                                   hapd->conf->iface);
                }
 
-               if (hostapd_set_generic_elem(hapd, (u8 *) "", 0)) {
+               if (hapd->drv_priv &&
+                   hostapd_set_generic_elem(hapd, (u8 *) "", 0)) {
                        wpa_printf(MSG_DEBUG, "Could not remove generic "
                                   "information element from interface %s",
                                   hapd->conf->iface);
index 57b098f..72b7eb3 100644 (file)
@@ -60,7 +60,8 @@ struct wpa_state_machine {
        u8 SNonce[WPA_NONCE_LEN];
        u8 alt_SNonce[WPA_NONCE_LEN];
        u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN];
-       u8 PMK[PMK_LEN];
+       u8 PMK[PMK_LEN_MAX];
+       unsigned int pmk_len;
        struct wpa_ptk PTK;
        Boolean PTK_valid;
        Boolean pairwise_set;
@@ -171,6 +172,7 @@ struct wpa_group {
 #endif /* CONFIG_IEEE80211W */
        /* Number of references except those in struct wpa_group->next */
        unsigned int references;
+       unsigned int num_setup_iface;
 };
 
 
index eafb828..f79783b 100644 (file)
@@ -251,7 +251,7 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
        pos += 2;
 
        if (pmkid) {
-               if (pos + 2 + PMKID_LEN > buf + len)
+               if (2 + PMKID_LEN > buf + len - pos)
                        return -1;
                /* PMKID Count */
                WPA_PUT_LE16(pos, 1);
@@ -263,7 +263,7 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
 #ifdef CONFIG_IEEE80211W
        if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
            conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) {
-               if (pos + 2 + 4 > buf + len)
+               if (2 + 4 > buf + len - pos)
                        return -1;
                if (pmkid == NULL) {
                        /* PMKID Count */
@@ -712,11 +712,14 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
                }
        }
        if (sm->pmksa && pmkid) {
+               struct vlan_description *vlan;
+
+               vlan = sm->pmksa->vlan_desc;
                wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
-                                "PMKID found from PMKSA cache "
-                                "eap_type=%d vlan_id=%d",
+                                "PMKID found from PMKSA cache eap_type=%d vlan=%d%s",
                                 sm->pmksa->eap_type_authsrv,
-                                sm->pmksa->vlan_id);
+                                vlan ? vlan->untagged : 0,
+                                (vlan && vlan->tagged[0]) ? "+" : "");
                os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN);
        }
 
@@ -791,7 +794,7 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
                return 0;
        }
 
-       if (pos + 1 + RSN_SELECTOR_LEN < end &&
+       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;
@@ -887,13 +890,13 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
        int ret = 0;
 
        os_memset(ie, 0, sizeof(*ie));
-       for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
+       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 (pos + 2 + pos[1] > end) {
+               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));
index cde31e6..95b40da 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / WPS integration
- * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2016, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -269,12 +269,6 @@ static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr,
 }
 
 
-static int str_starts(const char *str, const char *start)
-{
-       return os_strncmp(str, start, os_strlen(start)) == 0;
-}
-
-
 static void wps_reload_config(void *eloop_data, void *user_ctx)
 {
        struct hostapd_iface *iface = eloop_data;
@@ -445,6 +439,8 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
        os_memcpy(hapd->wps->ssid, cred->ssid, cred->ssid_len);
        hapd->wps->ssid_len = cred->ssid_len;
        hapd->wps->encr_types = cred->encr_type;
+       hapd->wps->encr_types_rsn = cred->encr_type;
+       hapd->wps->encr_types_wpa = cred->encr_type;
        hapd->wps->auth_types = cred->auth_type;
        hapd->wps->ap_encr_type = cred->encr_type;
        hapd->wps->ap_auth_type = cred->auth_type;
@@ -872,7 +868,8 @@ static void hostapd_wps_clear_ies(struct hostapd_data *hapd, int deinit_only)
        hapd->wps_probe_resp_ie = NULL;
 
        if (deinit_only) {
-               hostapd_reset_ap_wps_ie(hapd);
+               if (hapd->drv_priv)
+                       hostapd_reset_ap_wps_ie(hapd);
                return;
        }
 
@@ -1067,10 +1064,14 @@ int hostapd_init_wps(struct hostapd_data *hapd,
                if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
                        wps->auth_types |= WPS_AUTH_WPA2;
 
-               if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))
+               if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) {
                        wps->encr_types |= WPS_ENCR_AES;
-               if (conf->rsn_pairwise & WPA_CIPHER_TKIP)
+                       wps->encr_types_rsn |= WPS_ENCR_AES;
+               }
+               if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
                        wps->encr_types |= WPS_ENCR_TKIP;
+                       wps->encr_types_rsn |= WPS_ENCR_TKIP;
+               }
        }
 
        if (conf->wpa & WPA_PROTO_WPA) {
@@ -1079,10 +1080,14 @@ int hostapd_init_wps(struct hostapd_data *hapd,
                if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
                        wps->auth_types |= WPS_AUTH_WPA;
 
-               if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
+               if (conf->wpa_pairwise & WPA_CIPHER_CCMP) {
                        wps->encr_types |= WPS_ENCR_AES;
-               if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
+                       wps->encr_types_wpa |= WPS_ENCR_AES;
+               }
+               if (conf->wpa_pairwise & WPA_CIPHER_TKIP) {
                        wps->encr_types |= WPS_ENCR_TKIP;
+                       wps->encr_types_wpa |= WPS_ENCR_TKIP;
+               }
        }
 
        if (conf->ssid.security_policy == SECURITY_PLAINTEXT) {
@@ -1122,6 +1127,8 @@ int hostapd_init_wps(struct hostapd_data *hapd,
                /* Override parameters to enable security by default */
                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;
        }
 
        wps->ap_settings = conf->ap_settings;
@@ -1614,7 +1621,8 @@ const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout)
        unsigned int pin;
        struct wps_ap_pin_data data;
 
-       pin = wps_generate_pin();
+       if (wps_generate_pin(&pin) < 0)
+               return NULL;
        os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%08u", pin);
        data.timeout = timeout;
        hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
diff --git a/libeap/src/common/cli.c b/libeap/src/common/cli.c
new file mode 100644 (file)
index 0000000..b583d1c
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * Common hostapd/wpa_supplicant command line interface functions
+ * Copyright (c) 2004-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 "common/cli.h"
+
+
+const char *const cli_license =
+"This software may be distributed under the terms of the BSD license.\n"
+"See README for more details.\n";
+
+const char *const cli_full_license =
+"This software may be distributed under the terms of the BSD license.\n"
+"\n"
+"Redistribution and use in source and binary forms, with or without\n"
+"modification, are permitted provided that the following conditions are\n"
+"met:\n"
+"\n"
+"1. Redistributions of source code must retain the above copyright\n"
+"   notice, this list of conditions and the following disclaimer.\n"
+"\n"
+"2. Redistributions in binary form must reproduce the above copyright\n"
+"   notice, this list of conditions and the following disclaimer in the\n"
+"   documentation and/or other materials provided with the distribution.\n"
+"\n"
+"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
+"   names of its contributors may be used to endorse or promote products\n"
+"   derived from this software without specific prior written permission.\n"
+"\n"
+"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
+"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
+"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
+"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
+"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
+"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
+"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
+"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
+"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
+"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
+"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
+"\n";
+
+
+void cli_txt_list_free(struct cli_txt_entry *e)
+{
+       dl_list_del(&e->list);
+       os_free(e->txt);
+       os_free(e);
+}
+
+
+void cli_txt_list_flush(struct dl_list *list)
+{
+       struct cli_txt_entry *e;
+
+       while ((e = dl_list_first(list, struct cli_txt_entry, list)))
+               cli_txt_list_free(e);
+}
+
+
+struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list,
+                                       const char *txt)
+{
+       struct cli_txt_entry *e;
+
+       dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
+               if (os_strcmp(e->txt, txt) == 0)
+                       return e;
+       }
+       return NULL;
+}
+
+
+void cli_txt_list_del(struct dl_list *txt_list, const char *txt)
+{
+       struct cli_txt_entry *e;
+
+       e = cli_txt_list_get(txt_list, txt);
+       if (e)
+               cli_txt_list_free(e);
+}
+
+
+void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt)
+{
+       u8 addr[ETH_ALEN];
+       char buf[18];
+
+       if (hwaddr_aton(txt, addr) < 0)
+               return;
+       os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+       cli_txt_list_del(txt_list, buf);
+}
+
+
+void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt,
+                          int separator)
+{
+       const char *end;
+       char *buf;
+
+       end = os_strchr(txt, separator);
+       if (end == NULL)
+               end = txt + os_strlen(txt);
+       buf = dup_binstr(txt, end - txt);
+       if (buf == NULL)
+               return;
+       cli_txt_list_del(txt_list, buf);
+       os_free(buf);
+}
+
+
+int cli_txt_list_add(struct dl_list *txt_list, const char *txt)
+{
+       struct cli_txt_entry *e;
+
+       e = cli_txt_list_get(txt_list, txt);
+       if (e)
+               return 0;
+       e = os_zalloc(sizeof(*e));
+       if (e == NULL)
+               return -1;
+       e->txt = os_strdup(txt);
+       if (e->txt == NULL) {
+               os_free(e);
+               return -1;
+       }
+       dl_list_add(txt_list, &e->list);
+       return 0;
+}
+
+
+int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt)
+{
+       u8 addr[ETH_ALEN];
+       char buf[18];
+
+       if (hwaddr_aton(txt, addr) < 0)
+               return -1;
+       os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+       return cli_txt_list_add(txt_list, buf);
+}
+
+
+int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt,
+                         int separator)
+{
+       const char *end;
+       char *buf;
+       int ret;
+
+       end = os_strchr(txt, separator);
+       if (end == NULL)
+               end = txt + os_strlen(txt);
+       buf = dup_binstr(txt, end - txt);
+       if (buf == NULL)
+               return -1;
+       ret = cli_txt_list_add(txt_list, buf);
+       os_free(buf);
+       return ret;
+}
+
+
+char ** cli_txt_list_array(struct dl_list *txt_list)
+{
+       unsigned int i, count = dl_list_len(txt_list);
+       char **res;
+       struct cli_txt_entry *e;
+
+       res = os_calloc(count + 1, sizeof(char *));
+       if (res == NULL)
+               return NULL;
+
+       i = 0;
+       dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
+               res[i] = os_strdup(e->txt);
+               if (res[i] == NULL)
+                       break;
+               i++;
+       }
+
+       return res;
+}
+
+
+int get_cmd_arg_num(const char *str, int pos)
+{
+       int arg = 0, i;
+
+       for (i = 0; i <= pos; i++) {
+               if (str[i] != ' ') {
+                       arg++;
+                       while (i <= pos && str[i] != ' ')
+                               i++;
+               }
+       }
+
+       if (arg > 0)
+               arg--;
+       return arg;
+}
+
+
+int write_cmd(char *buf, size_t buflen, const char *cmd, int argc, char *argv[])
+{
+       int i, res;
+       char *pos, *end;
+
+       pos = buf;
+       end = buf + buflen;
+
+       res = os_snprintf(pos, end - pos, "%s", cmd);
+       if (os_snprintf_error(end - pos, res))
+               goto fail;
+       pos += res;
+
+       for (i = 0; i < argc; i++) {
+               res = os_snprintf(pos, end - pos, " %s", argv[i]);
+               if (os_snprintf_error(end - pos, res))
+                       goto fail;
+               pos += res;
+       }
+
+       buf[buflen - 1] = '\0';
+       return 0;
+
+fail:
+       printf("Too long command\n");
+       return -1;
+}
+
+
+int tokenize_cmd(char *cmd, char *argv[])
+{
+       char *pos;
+       int argc = 0;
+
+       pos = cmd;
+       for (;;) {
+               while (*pos == ' ')
+                       pos++;
+               if (*pos == '\0')
+                       break;
+               argv[argc] = pos;
+               argc++;
+               if (argc == max_args)
+                       break;
+               if (*pos == '"') {
+                       char *pos2 = os_strrchr(pos, '"');
+                       if (pos2)
+                               pos = pos2 + 1;
+               }
+               while (*pos != '\0' && *pos != ' ')
+                       pos++;
+               if (*pos == ' ')
+                       *pos++ = '\0';
+       }
+
+       return argc;
+}
diff --git a/libeap/src/common/cli.h b/libeap/src/common/cli.h
new file mode 100644 (file)
index 0000000..41ef329
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Common hostapd/wpa_supplicant command line interface functionality
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CLI_H
+#define CLI_H
+
+#include "utils/list.h"
+
+extern const char *const cli_license;
+extern const char *const cli_full_license;
+
+struct cli_txt_entry {
+       struct dl_list list;
+       char *txt;
+};
+
+void cli_txt_list_free(struct cli_txt_entry *e);
+void cli_txt_list_flush(struct dl_list *list);
+
+struct cli_txt_entry *
+cli_txt_list_get(struct dl_list *txt_list, const char *txt);
+
+void cli_txt_list_del(struct dl_list *txt_list, const char *txt);
+void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt);
+void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt,
+                          int separator);
+
+int cli_txt_list_add(struct dl_list *txt_list, const char *txt);
+int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt);
+int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt,
+                         int separator);
+
+char ** cli_txt_list_array(struct dl_list *txt_list);
+
+int get_cmd_arg_num(const char *str, int pos);
+int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
+             char *argv[]);
+
+#define max_args 10
+int tokenize_cmd(char *cmd, char *argv[]);
+
+#endif /* CLI_H */
index d69448b..e0769c0 100644 (file)
@@ -9,6 +9,7 @@
 #include "utils/includes.h"
 
 #include "utils/common.h"
+#include "utils/module_tests.h"
 #include "ieee802_11_common.h"
 #include "ieee802_11_defs.h"
 #include "gas.h"
diff --git a/libeap/src/common/ctrl_iface_common.c b/libeap/src/common/ctrl_iface_common.c
new file mode 100644 (file)
index 0000000..ebbe6ff
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Common hostapd/wpa_supplicant ctrl iface code.
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2015, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <netdb.h>
+#include <sys/un.h>
+
+#include "utils/common.h"
+#include "ctrl_iface_common.h"
+
+static int sockaddr_compare(struct sockaddr_storage *a, socklen_t a_len,
+                           struct sockaddr_storage *b, socklen_t b_len)
+{
+       if (a->ss_family != b->ss_family)
+               return 1;
+
+       switch (a->ss_family) {
+#ifdef CONFIG_CTRL_IFACE_UDP
+       case AF_INET:
+       {
+               struct sockaddr_in *in_a, *in_b;
+
+               in_a = (struct sockaddr_in *) a;
+               in_b = (struct sockaddr_in *) b;
+
+               if (in_a->sin_port != in_b->sin_port)
+                       return 1;
+               if (in_a->sin_addr.s_addr != in_b->sin_addr.s_addr)
+                       return 1;
+               break;
+       }
+       case AF_INET6:
+       {
+               struct sockaddr_in6 *in6_a, *in6_b;
+
+               in6_a = (struct sockaddr_in6 *) a;
+               in6_b = (struct sockaddr_in6 *) b;
+
+               if (in6_a->sin6_port != in6_b->sin6_port)
+                       return 1;
+               if (os_memcmp(&in6_a->sin6_addr, &in6_b->sin6_addr,
+                             sizeof(in6_a->sin6_addr)) != 0)
+                       return 1;
+               break;
+       }
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#ifdef CONFIG_CTRL_IFACE_UNIX
+       case AF_UNIX:
+       {
+               struct sockaddr_un *u_a, *u_b;
+
+               u_a = (struct sockaddr_un *) a;
+               u_b = (struct sockaddr_un *) b;
+
+               if (a_len != b_len ||
+                   os_memcmp(u_a->sun_path, u_b->sun_path,
+                             a_len - offsetof(struct sockaddr_un, sun_path))
+                   != 0)
+                       return 1;
+               break;
+       }
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+       default:
+               return 1;
+       }
+
+       return 0;
+}
+
+
+void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
+                   socklen_t socklen)
+{
+       switch (sock->ss_family) {
+#ifdef CONFIG_CTRL_IFACE_UDP
+       case AF_INET:
+       case AF_INET6:
+       {
+               char host[NI_MAXHOST] = { 0 };
+               char service[NI_MAXSERV] = { 0 };
+
+               getnameinfo((struct sockaddr *) sock, socklen,
+                           host, sizeof(host),
+                           service, sizeof(service),
+                           NI_NUMERICHOST);
+
+               wpa_printf(level, "%s %s:%s", msg, host, service);
+               break;
+       }
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#ifdef CONFIG_CTRL_IFACE_UNIX
+       case AF_UNIX:
+       {
+               char addr_txt[200];
+
+               printf_encode(addr_txt, sizeof(addr_txt),
+                             (u8 *) ((struct sockaddr_un *) sock)->sun_path,
+                             socklen - offsetof(struct sockaddr_un, sun_path));
+               wpa_printf(level, "%s %s", msg, addr_txt);
+               break;
+       }
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+       default:
+               wpa_printf(level, "%s", msg);
+               break;
+       }
+}
+
+
+int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+                     socklen_t fromlen)
+{
+       struct wpa_ctrl_dst *dst;
+
+       dst = os_zalloc(sizeof(*dst));
+       if (dst == NULL)
+               return -1;
+       os_memcpy(&dst->addr, from, fromlen);
+       dst->addrlen = fromlen;
+       dst->debug_level = MSG_INFO;
+       dl_list_add(ctrl_dst, &dst->list);
+
+       sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor attached", from, fromlen);
+       return 0;
+}
+
+
+int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+                     socklen_t fromlen)
+{
+       struct wpa_ctrl_dst *dst;
+
+       dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
+               if (!sockaddr_compare(from, fromlen,
+                                     &dst->addr, dst->addrlen)) {
+                       sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor detached",
+                                      from, fromlen);
+                       dl_list_del(&dst->list);
+                       os_free(dst);
+                       return 0;
+               }
+       }
+
+       return -1;
+}
+
+
+int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+                    socklen_t fromlen, const char *level)
+{
+       struct wpa_ctrl_dst *dst;
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
+
+       dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
+               if (!sockaddr_compare(from, fromlen,
+                                     &dst->addr, dst->addrlen)) {
+                       sockaddr_print(MSG_DEBUG,
+                                      "CTRL_IFACE changed monitor level",
+                                      from, fromlen);
+                       dst->debug_level = atoi(level);
+                       return 0;
+               }
+       }
+
+       return -1;
+}
diff --git a/libeap/src/common/ctrl_iface_common.h b/libeap/src/common/ctrl_iface_common.h
new file mode 100644 (file)
index 0000000..0b6e3e7
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Common hostapd/wpa_supplicant ctrl iface code.
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2015, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+#ifndef CONTROL_IFACE_COMMON_H
+#define CONTROL_IFACE_COMMON_H
+
+#include "utils/list.h"
+
+/**
+ * struct wpa_ctrl_dst - Data structure of control interface monitors
+ *
+ * This structure is used to store information about registered control
+ * interface monitors into struct wpa_supplicant.
+ */
+struct wpa_ctrl_dst {
+       struct dl_list list;
+       struct sockaddr_storage addr;
+       socklen_t addrlen;
+       int debug_level;
+       int errors;
+};
+
+void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
+                   socklen_t socklen);
+
+int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+                      socklen_t fromlen);
+int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+                     socklen_t fromlen);
+int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+                    socklen_t fromlen, const char *level);
+
+#endif /* CONTROL_IFACE_COMMON_H */
index 6aea375..4f56794 100644 (file)
@@ -312,6 +312,7 @@ enum wpa_ctrl_req_type {
        WPA_CTRL_REQ_EAP_PASSPHRASE,
        WPA_CTRL_REQ_SIM,
        WPA_CTRL_REQ_PSK_PASSPHRASE,
+       WPA_CTRL_REQ_EXT_CERT_CHECK,
        NUM_WPA_CTRL_REQS
 };
 
@@ -319,13 +320,13 @@ enum wpa_ctrl_req_type {
 #define EAP_MAX_METHODS 8
 
 enum mesh_plink_state {
-       PLINK_LISTEN = 1,
-       PLINK_OPEN_SENT,
-       PLINK_OPEN_RCVD,
+       PLINK_IDLE = 1,
+       PLINK_OPN_SNT,
+       PLINK_OPN_RCVD,
        PLINK_CNF_RCVD,
        PLINK_ESTAB,
        PLINK_HOLDING,
-       PLINK_BLOCKED,
+       PLINK_BLOCKED, /* not defined in the IEEE 802.11 standard */
 };
 
 enum set_band {
@@ -334,4 +335,10 @@ enum set_band {
        WPA_SETBAND_2G
 };
 
+enum wpa_radio_work_band {
+       BAND_2_4_GHZ = BIT(0),
+       BAND_5_GHZ = BIT(1),
+       BAND_60_GHZ = BIT(2),
+};
+
 #endif /* DEFS_H */
index 6958661..d773348 100644 (file)
@@ -25,7 +25,7 @@ struct ieee802_1x_hdr {
 struct ieee8023_hdr {
        u8 dest[ETH_ALEN];
        u8 src[ETH_ALEN];
-       u16 ethertype;
+       be16 ethertype;
 } STRUCT_PACKED;
 
 #ifdef _MSC_VER
index d07a316..b6bc449 100644 (file)
@@ -115,6 +115,11 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
                        elems->osen = pos;
                        elems->osen_len = elen;
                        break;
+               case MBO_OUI_TYPE:
+                       /* MBO-OCE */
+                       elems->mbo = pos;
+                       elems->mbo_len = elen;
+                       break;
                default:
                        wpa_printf(MSG_MSGDUMP, "Unknown WFA "
                                   "information element ignored "
@@ -366,6 +371,14 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
                        elems->mb_ies.ies[elems->mb_ies.nof_ies].ie_len = elen;
                        elems->mb_ies.nof_ies++;
                        break;
+               case WLAN_EID_SUPPORTED_OPERATING_CLASSES:
+                       elems->supp_op_classes = pos;
+                       elems->supp_op_classes_len = elen;
+                       break;
+               case WLAN_EID_RRM_ENABLED_CAPABILITIES:
+                       elems->rrm_enabled = pos;
+                       elems->rrm_enabled_len = elen;
+                       break;
                default:
                        unknown++;
                        if (!show_errors)
@@ -398,8 +411,8 @@ int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
        pos = ies;
        end = ies + ies_len;
 
-       while (pos + 2 <= end) {
-               if (pos + 2 + pos[1] > end)
+       while (end - pos >= 2) {
+               if (2 + pos[1] > end - pos)
                        break;
                count++;
                pos += 2 + pos[1];
@@ -419,8 +432,8 @@ struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
        end = ies + ies_len;
        ie = NULL;
 
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
+       while (end - pos > 1) {
+               if (2 + pos[1] > end - pos)
                        return NULL;
                if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
                    WPA_GET_BE32(&pos[2]) == oui_type) {
@@ -441,8 +454,8 @@ struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
         * There may be multiple vendor IEs in the message, so need to
         * concatenate their data fields.
         */
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
+       while (end - pos > 1) {
+               if (2 + pos[1] > end - pos)
                        break;
                if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
                    WPA_GET_BE32(&pos[2]) == oui_type)
@@ -570,7 +583,8 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
 {
        u8 op_class;
 
-       return ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, channel);
+       return ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
+                                            &op_class, channel);
 }
 
 
@@ -579,7 +593,7 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
  * for HT40 and VHT. DFS channels are not covered.
  * @freq: Frequency (MHz) to convert
  * @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
- * @vht: 0 - non-VHT, 1 - 80 MHz
+ * @vht: VHT channel width (VHT_CHANWIDTH_*)
  * @op_class: Buffer for returning operating class
  * @channel: Buffer for returning channel number
  * Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure
@@ -588,6 +602,8 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
                                                   int sec_channel, int vht,
                                                   u8 *op_class, u8 *channel)
 {
+       u8 vht_opclass;
+
        /* TODO: more operating classes */
 
        if (sec_channel > 1 || sec_channel < -1)
@@ -631,17 +647,32 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
                return HOSTAPD_MODE_IEEE80211A;
        }
 
+       switch (vht) {
+       case VHT_CHANWIDTH_80MHZ:
+               vht_opclass = 128;
+               break;
+       case VHT_CHANWIDTH_160MHZ:
+               vht_opclass = 129;
+               break;
+       case VHT_CHANWIDTH_80P80MHZ:
+               vht_opclass = 130;
+               break;
+       default:
+               vht_opclass = 0;
+               break;
+       }
+
        /* 5 GHz, channels 36..48 */
        if (freq >= 5180 && freq <= 5240) {
                if ((freq - 5000) % 5)
                        return NUM_HOSTAPD_MODES;
 
-               if (sec_channel == 1)
+               if (vht_opclass)
+                       *op_class = vht_opclass;
+               else if (sec_channel == 1)
                        *op_class = 116;
                else if (sec_channel == -1)
                        *op_class = 117;
-               else if (vht)
-                       *op_class = 128;
                else
                        *op_class = 115;
 
@@ -650,31 +681,40 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
                return HOSTAPD_MODE_IEEE80211A;
        }
 
-       /* 5 GHz, channels 149..161 */
-       if (freq >= 5745 && freq <= 5805) {
+       /* 5 GHz, channels 149..169 */
+       if (freq >= 5745 && freq <= 5845) {
                if ((freq - 5000) % 5)
                        return NUM_HOSTAPD_MODES;
 
-               if (sec_channel == 1)
+               if (vht_opclass)
+                       *op_class = vht_opclass;
+               else if (sec_channel == 1)
                        *op_class = 126;
                else if (sec_channel == -1)
                        *op_class = 127;
-               else if (vht)
-                       *op_class = 128;
-               else
+               else if (freq <= 5805)
                        *op_class = 124;
+               else
+                       *op_class = 125;
 
                *channel = (freq - 5000) / 5;
 
                return HOSTAPD_MODE_IEEE80211A;
        }
 
-       /* 5 GHz, channels 149..169 */
-       if (freq >= 5745 && freq <= 5845) {
+       /* 5 GHz, channels 100..140 */
+       if (freq >= 5000 && freq <= 5700) {
                if ((freq - 5000) % 5)
                        return NUM_HOSTAPD_MODES;
 
-               *op_class = 125;
+               if (vht_opclass)
+                       *op_class = vht_opclass;
+               else if (sec_channel == 1)
+                       *op_class = 122;
+               else if (sec_channel == -1)
+                       *op_class = 123;
+               else
+                       *op_class = 121;
 
                *channel = (freq - 5000) / 5;
 
@@ -1145,3 +1185,135 @@ struct wpabuf * mb_ies_by_info(struct mb_ies_info *info)
 
        return mb_ies;
 }
+
+
+const struct oper_class_map global_op_class[] = {
+       { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20, P2P_SUPP },
+       { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20, NO_P2P_SUPP },
+
+       /* Do not enable HT40 on 2.4 GHz for P2P use for now */
+       { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS, NO_P2P_SUPP },
+       { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS, NO_P2P_SUPP },
+
+       { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20, P2P_SUPP },
+       { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS, P2P_SUPP },
+       { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS, P2P_SUPP },
+       { HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, NO_P2P_SUPP },
+       { HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, NO_P2P_SUPP },
+       { HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, NO_P2P_SUPP },
+       { HOSTAPD_MODE_IEEE80211A, 121, 100, 140, 4, BW20, NO_P2P_SUPP },
+       { 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 },
+
+       /*
+        * 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
+        * (these center frequencies are not actual channels, which makes
+        * wpas_p2p_allow_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 },
+       { -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
+};
+
+
+static enum phy_type ieee80211_phy_type_by_freq(int freq)
+{
+       enum hostapd_hw_mode hw_mode;
+       u8 channel;
+
+       hw_mode = ieee80211_freq_to_chan(freq, &channel);
+
+       switch (hw_mode) {
+       case HOSTAPD_MODE_IEEE80211A:
+               return PHY_TYPE_OFDM;
+       case HOSTAPD_MODE_IEEE80211B:
+               return PHY_TYPE_HRDSSS;
+       case HOSTAPD_MODE_IEEE80211G:
+               return PHY_TYPE_ERP;
+       case HOSTAPD_MODE_IEEE80211AD:
+               return PHY_TYPE_DMG;
+       default:
+               return PHY_TYPE_UNSPECIFIED;
+       };
+}
+
+
+/* ieee80211_get_phy_type - Derive the phy type by freq and bandwidth */
+enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht)
+{
+       if (vht)
+               return PHY_TYPE_VHT;
+       if (ht)
+               return PHY_TYPE_HT;
+
+       return ieee80211_phy_type_by_freq(freq);
+}
+
+
+size_t global_op_class_size = ARRAY_SIZE(global_op_class);
+
+
+/**
+ * get_ie - Fetch a specified information element from IEs buffer
+ * @ies: Information elements buffer
+ * @len: Information elements buffer length
+ * @eid: Information element identifier (WLAN_EID_*)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the IEs
+ * buffer or %NULL in case the element is not found.
+ */
+const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
+{
+       const u8 *end;
+
+       if (!ies)
+               return NULL;
+
+       end = ies + len;
+
+       while (end - ies > 1) {
+               if (2 + ies[1] > end - ies)
+                       break;
+
+               if (ies[0] == eid)
+                       return ies;
+
+               ies += 2 + ies[1];
+       }
+
+       return NULL;
+}
+
+
+size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len)
+{
+       /*
+        * MBO IE requires 6 bytes without the attributes: EID (1), length (1),
+        * OUI (3), OUI type (1).
+        */
+       if (len < 6 + attr_len) {
+               wpa_printf(MSG_DEBUG,
+                          "MBO: Not enough room in buffer for MBO IE: buf len = %zu, attr_len = %zu",
+                          len, attr_len);
+               return 0;
+       }
+
+       *buf++ = WLAN_EID_VENDOR_SPECIFIC;
+       *buf++ = attr_len + 4;
+       WPA_PUT_BE24(buf, OUI_WFA);
+       buf += 3;
+       *buf++ = MBO_OUI_TYPE;
+       os_memcpy(buf, attr, attr_len);
+
+       return 6 + attr_len;
+}
index 55ce022..42f3909 100644 (file)
@@ -9,6 +9,8 @@
 #ifndef IEEE802_11_COMMON_H
 #define IEEE802_11_COMMON_H
 
+#include "defs.h"
+
 #define MAX_NOF_MB_IES_SUPPORTED 5
 
 struct mb_ies_info {
@@ -56,9 +58,12 @@ struct ieee802_11_elems {
        const u8 *bss_max_idle_period;
        const u8 *ssid_list;
        const u8 *osen;
+       const u8 *mbo;
        const u8 *ampe;
        const u8 *mic;
        const u8 *pref_freq_list;
+       const u8 *supp_op_classes;
+       const u8 *rrm_enabled;
 
        u8 ssid_len;
        u8 supp_rates_len;
@@ -85,9 +90,13 @@ struct ieee802_11_elems {
        u8 ext_capab_len;
        u8 ssid_list_len;
        u8 osen_len;
+       u8 mbo_len;
        u8 ampe_len;
        u8 mic_len;
        u8 pref_freq_list_len;
+       u8 supp_op_classes_len;
+       u8 rrm_enabled_len;
+
        struct mb_ies_info mb_ies;
 };
 
@@ -118,6 +127,7 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
                                                   int sec_channel, int vht,
                                                   u8 *op_class, u8 *channel);
 int ieee80211_is_dfs(int freq);
+enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht);
 
 int supp_rates_11b_only(struct ieee802_11_elems *elems);
 int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
@@ -125,4 +135,22 @@ int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
 struct wpabuf * mb_ies_by_info(struct mb_ies_info *info);
 
 const char * fc2str(u16 fc);
+
+struct oper_class_map {
+       enum hostapd_hw_mode mode;
+       u8 op_class;
+       u8 min_chan;
+       u8 max_chan;
+       u8 inc;
+       enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160, BW160, BW80P80 } bw;
+       enum { P2P_SUPP, NO_P2P_SUPP } p2p;
+};
+
+extern const struct oper_class_map global_op_class[];
+extern size_t global_op_class_size;
+
+const u8 * get_ie(const u8 *ies, size_t len, u8 eid);
+
+size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len);
+
 #endif /* IEEE802_11_COMMON_H */
index 44530ce..d453aec 100644 (file)
 #define WLAN_CAPABILITY_PBCC BIT(6)
 #define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7)
 #define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8)
+#define WLAN_CAPABILITY_QOS BIT(9)
 #define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10)
+#define WLAN_CAPABILITY_APSD BIT(11)
+#define WLAN_CAPABILITY_RADIO_MEASUREMENT BIT(12)
 #define WLAN_CAPABILITY_DSSS_OFDM BIT(13)
+#define WLAN_CAPABILITY_DELAYED_BLOCK_ACK BIT(14)
+#define WLAN_CAPABILITY_IMM_BLOCK_ACK BIT(15)
 
 /* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */
 #define WLAN_STATUS_SUCCESS 0
 #define WLAN_EID_TIMEOUT_INTERVAL 56
 #define WLAN_EID_RIC_DATA 57
 #define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59
+#define WLAN_EID_EXT_CHANSWITCH_ANN 60
 #define WLAN_EID_HT_OPERATION 61
 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
 #define WLAN_EID_WAPI 68
 /* byte 1 (out of 5) */
 #define WLAN_RRM_CAPS_LINK_MEASUREMENT BIT(0)
 #define WLAN_RRM_CAPS_NEIGHBOR_REPORT BIT(1)
+/* byte 2 (out of 5) */
+#define WLAN_RRM_CAPS_LCI_MEASUREMENT BIT(4)
+/* byte 5 (out of 5) */
+#define WLAN_RRM_CAPS_FTM_RANGE_REPORT BIT(2)
+
+/*
+ * IEEE P802.11-REVmc/D5.0, 9.4.2.21.19 (Fine Timing Measurement Range
+ * request) - Minimum AP count
+ */
+#define WLAN_RRM_RANGE_REQ_MAX_MIN_AP 15
 
 /* Timeout Interval Type */
 #define WLAN_TIMEOUT_REASSOC_DEADLINE 1
@@ -407,7 +423,12 @@ enum anqp_info_id {
        ANQP_AP_LOCATION_PUBLIC_URI = 267,
        ANQP_DOMAIN_NAME = 268,
        ANQP_EMERGENCY_ALERT_URI = 269,
+       ANQP_TDLS_CAPABILITY = 270,
        ANQP_EMERGENCY_NAI = 271,
+       ANQP_NEIGHBOR_REPORT = 272,
+       ANQP_VENUE_URL = 277,
+       ANQP_ADVICE_OF_CHARGE = 278,
+       ANQP_LOCAL_CONTENT = 279,
        ANQP_VENDOR_SPECIFIC = 56797
 };
 
@@ -442,6 +463,48 @@ enum nai_realm_eap_cred_type {
        NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10
 };
 
+/*
+ * IEEE P802.11-REVmc/D5.0 Table 9-81 - Measurement type definitions for
+ * measurement requests
+ */
+enum measure_type {
+       MEASURE_TYPE_BASIC = 0,
+       MEASURE_TYPE_CCA = 1,
+       MEASURE_TYPE_RPI_HIST = 2,
+       MEASURE_TYPE_CHANNEL_LOAD = 3,
+       MEASURE_TYPE_NOISE_HIST = 4,
+       MEASURE_TYPE_BEACON = 5,
+       MEASURE_TYPE_FRAME = 6,
+       MEASURE_TYPE_STA_STATISTICS = 7,
+       MEASURE_TYPE_LCI = 8,
+       MEASURE_TYPE_TRANSMIT_STREAM = 9,
+       MEASURE_TYPE_MULTICAST_DIAG = 10,
+       MEASURE_TYPE_LOCATION_CIVIC = 11,
+       MEASURE_TYPE_LOCATION_ID = 12,
+       MEASURE_TYPE_DIRECTIONAL_CHAN_QUALITY = 13,
+       MEASURE_TYPE_DIRECTIONAL_MEASURE = 14,
+       MEASURE_TYPE_DIRECTIONAL_STATS = 15,
+       MEASURE_TYPE_FTM_RANGE = 16,
+       MEASURE_TYPE_MEASURE_PAUSE = 255,
+};
+
+/* IEEE Std 802.11-2012 Table 8-71 - Location subject definition */
+enum location_subject {
+       LOCATION_SUBJECT_LOCAL = 0,
+       LOCATION_SUBJECT_REMOTE = 1,
+       LOCATION_SUBJECT_3RD_PARTY = 2,
+};
+
+/*
+ * IEEE P802.11-REVmc/D5.0 Table 9-94 - Optional subelement IDs for LCI request
+ */
+enum lci_req_subelem {
+       LCI_REQ_SUBELEM_AZIMUTH_REQ = 1,
+       LCI_REQ_SUBELEM_ORIGINATOR_MAC_ADDR = 2,
+       LCI_REQ_SUBELEM_TARGET_MAC_ADDR = 3,
+       LCI_REQ_SUBELEM_MAX_AGE = 4,
+};
+
 #ifdef _MSC_VER
 #pragma pack(push, 1)
 #endif /* _MSC_VER */
@@ -516,10 +579,7 @@ struct ieee80211_mgmt {
                         * FH Params, DS Params, CF Params, IBSS Params, TIM */
                        u8 variable[];
                } STRUCT_PACKED beacon;
-               struct {
-                       /* only variable items: SSID, Supported rates */
-                       u8 variable[0];
-               } STRUCT_PACKED probe_req;
+               /* probe_req: only variable items: SSID, Supported rates */
                struct {
                        u8 timestamp[8];
                        le16 beacon_int;
@@ -625,12 +685,19 @@ struct ieee80211_mgmt {
                                        u8 action;
                                        u8 variable[];
                                } STRUCT_PACKED fst_action;
+                               struct {
+                                       u8 action;
+                                       u8 dialog_token;
+                                       u8 variable[];
+                               } STRUCT_PACKED rrm;
                        } u;
                } STRUCT_PACKED action;
        } u;
 } STRUCT_PACKED;
 
 
+#define IEEE80211_MAX_MMPDU_SIZE 2304
+
 /* Rx MCS bitmask is in the first 77 bits of supported_mcs_set */
 #define IEEE80211_HT_MCS_MASK_LEN 10
 
@@ -690,9 +757,14 @@ struct ieee80211_ampe_ie {
        u8 selected_pairwise_suite[4];
        u8 local_nonce[32];
        u8 peer_nonce[32];
-       u8 mgtk[16];
-       u8 key_rsc[8];
-       u8 key_expiration[4];
+       /* Followed by
+        * Key Replay Counter[8] (optional)
+        *      (only in Mesh Group Key Inform/Acknowledge frames)
+        * GTKdata[variable] (optional)
+        *      (MGTK[variable] || Key RSC[8] || GTKExpirationTime[4])
+        * IGTKdata[variable] (optional)
+        *      (Key ID[2], IPN[6], IGTK[variable] in IGTK KDE format)
+        */
 } STRUCT_PACKED;
 
 #ifdef _MSC_VER
@@ -879,6 +951,8 @@ struct ieee80211_ampe_ie {
 #define WFD_OUI_TYPE 10
 #define HS20_IE_VENDOR_TYPE 0x506f9a10
 #define OSEN_IE_VENDOR_TYPE 0x506f9a12
+#define MBO_IE_VENDOR_TYPE 0x506f9a16
+#define MBO_OUI_TYPE 22
 
 #define WMM_OUI_TYPE 2
 #define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
@@ -1021,6 +1095,95 @@ enum wmm_ac {
 #define HS20_DEAUTH_REASON_CODE_BSS 0
 #define HS20_DEAUTH_REASON_CODE_ESS 1
 
+/* MBO v0.0_r19, 4.2: MBO Attributes */
+/* Table 4-5: MBO Attributes */
+enum mbo_attr_id {
+       MBO_ATTR_ID_AP_CAPA_IND = 1,
+       MBO_ATTR_ID_NON_PREF_CHAN_REPORT = 2,
+       MBO_ATTR_ID_CELL_DATA_CAPA = 3,
+       MBO_ATTR_ID_ASSOC_DISALLOW = 4,
+       MBO_ATTR_ID_CELL_DATA_PREF = 5,
+       MBO_ATTR_ID_TRANSITION_REASON = 6,
+       MBO_ATTR_ID_TRANSITION_REJECT_REASON = 7,
+       MBO_ATTR_ID_ASSOC_RETRY_DELAY = 8,
+};
+
+/* MBO v0.0_r19, 4.2.1: MBO AP Capability Indication Attribute */
+/* Table 4-7: MBO AP Capability Indication Field Values */
+#define MBO_AP_CAPA_CELL_AWARE BIT(6)
+
+/* MBO v0.0_r19, 4.2.2: Non-preferred Channel Report Attribute */
+/* Table 4-10: Reason Code Field Values */
+enum mbo_non_pref_chan_reason {
+       MBO_NON_PREF_CHAN_REASON_UNSPECIFIED = 0,
+       MBO_NON_PREF_CHAN_REASON_RSSI = 1,
+       MBO_NON_PREF_CHAN_REASON_EXT_INTERFERENCE = 2,
+       MBO_NON_PREF_CHAN_REASON_INT_INTERFERENCE = 3,
+};
+
+/* MBO v0.0_r19, 4.2.3: Cellular Data Capabilities Attribute */
+/* Table 4-13: Cellular Data Connectivity Field */
+enum mbo_cellular_capa {
+       MBO_CELL_CAPA_AVAILABLE = 1,
+       MBO_CELL_CAPA_NOT_AVAILABLE = 2,
+       MBO_CELL_CAPA_NOT_SUPPORTED = 3,
+};
+
+/* MBO v0.0_r19, 4.2.4: Association Disallowed Attribute */
+/* Table 4-15: Reason Code Field Values */
+enum mbo_assoc_disallow_reason {
+       MBO_ASSOC_DISALLOW_REASON_UNSPECIFIED = 1,
+       MBO_ASSOC_DISALLOW_REASON_MAX_STA = 2,
+       MBO_ASSOC_DISALLOW_REASON_AIR_INTERFERENCE = 3,
+       MBO_ASSOC_DISALLOW_REASON_AUTH_SERVER_OVERLOAD = 4,
+       MBO_ASSOC_DISALLOW_REASON_LOW_RSSI = 5,
+};
+
+/* MBO v0.0_r19, 4.2.5: Cellular Data Connection Preference Attribute */
+/* Table 4-17: Cellular Preference Field Values */
+enum mbo_cell_pref {
+       MBO_CELL_PREF_EXCLUDED = 0,
+       MBO_CELL_PREF_NO_USE = 1,
+       MBO_CELL_PREF_USE = 255
+};
+
+/* MBO v0.0_r19, 4.2.6: Transition Reason Code Attribute */
+/* Table 4-19: Transition Reason Code Field Values */
+enum mbo_transition_reason {
+       MBO_TRANSITION_REASON_UNSPECIFIED = 0,
+       MBO_TRANSITION_REASON_FRAME_LOSS = 1,
+       MBO_TRANSITION_REASON_DELAY = 2,
+       MBO_TRANSITION_REASON_BANDWIDTH = 3,
+       MBO_TRANSITION_REASON_LOAD_BALANCE = 4,
+       MBO_TRANSITION_REASON_RSSI = 5,
+       MBO_TRANSITION_REASON_RETRANSMISSIONS = 6,
+       MBO_TRANSITION_REASON_INTERFERENCE = 7,
+       MBO_TRANSITION_REASON_GRAY_ZONE = 8,
+       MBO_TRANSITION_REASON_PREMIUM_AP = 9,
+};
+
+/* MBO v0.0_r19, 4.2.7: Transition Rejection Reason Code Attribute */
+/* Table 4-21: Transition Rejection Reason Code Field Values */
+enum mbo_transition_reject_reason {
+       MBO_TRANSITION_REJECT_REASON_UNSPECIFIED = 0,
+       MBO_TRANSITION_REJECT_REASON_FRAME_LOSS = 1,
+       MBO_TRANSITION_REJECT_REASON_DELAY = 2,
+       MBO_TRANSITION_REJECT_REASON_QOS_CAPACITY = 3,
+       MBO_TRANSITION_REJECT_REASON_RSSI = 4,
+       MBO_TRANSITION_REJECT_REASON_INTERFERENCE = 5,
+       MBO_TRANSITION_REJECT_REASON_SERVICES = 6,
+};
+
+/* MBO v0.0_r19, 4.4: WNM-Notification vendor subelements */
+enum wfa_wnm_notif_subelem_id {
+       WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT = 2,
+       WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA = 3,
+};
+
+/* MBO v0.0_r25, 4.3: MBO ANQP-elements */
+#define MBO_ANQP_OUI_TYPE 0x12
+#define MBO_ANQP_SUBTYPE_CELL_CONN_PREF 1
+
 /* Wi-Fi Direct (P2P) */
 
 #define P2P_OUI_TYPE 9
@@ -1178,6 +1341,14 @@ enum wifi_display_subelem {
 #define MESH_PATH_PROTOCOL_VENDOR      255
 #define MESH_PATH_METRIC_AIRTIME       1
 #define MESH_PATH_METRIC_VENDOR                255
+/* IEEE 802.11s - Mesh Capability */
+#define MESH_CAP_ACCEPT_ADDITIONAL_PEER        BIT(0)
+#define MESH_CAP_MCCA_SUPPORTED                BIT(1)
+#define MESH_CAP_MCCA_ENABLED          BIT(2)
+#define MESH_CAP_FORWARDING            BIT(3)
+#define MESH_CAP_MBCA_ENABLED          BIT(4)
+#define MESH_CAP_TBTT_ADJUSTING                BIT(5)
+#define MESH_CAP_MESH_PS_LEVEL         BIT(6)
 
 enum plink_action_field {
        PLINK_OPEN = 1,
@@ -1280,14 +1451,25 @@ enum bss_trans_mgmt_status_code {
        WNM_BSS_TM_REJECT_LEAVING_ESS = 8
 };
 
+/*
+ * IEEE P802.11-REVmc/D5.0 Table 9-150 - Optional subelement IDs for
+ * neighbor report
+ */
 #define WNM_NEIGHBOR_TSF                         1
 #define WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING    2
 #define WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE    3
 #define WNM_NEIGHBOR_BSS_TERMINATION_DURATION    4
 #define WNM_NEIGHBOR_BEARING                     5
+#define WNM_NEIGHBOR_WIDE_BW_CHAN                6
+#define WNM_NEIGHBOR_MEASUREMENT_REPORT         39
+#define WNM_NEIGHBOR_HT_CAPAB                   45
+#define WNM_NEIGHBOR_HT_OPER                    61
+#define WNM_NEIGHBOR_SEC_CHAN_OFFSET            62
 #define WNM_NEIGHBOR_MEASUREMENT_PILOT          66
 #define WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES   70
 #define WNM_NEIGHBOR_MULTIPLE_BSSID             71
+#define WNM_NEIGHBOR_VHT_CAPAB                 191
+#define WNM_NEIGHBOR_VHT_OPER                  192
 
 /* QoS action */
 enum qos_action {
@@ -1356,6 +1538,8 @@ struct tpc_report {
        u8 link_margin;
 } STRUCT_PACKED;
 
+#define RRM_CAPABILITIES_IE_LEN 5
+
 /* IEEE Std 802.11-2012, 8.5.7.4 - Link Measurement Request frame format */
 struct rrm_link_measurement_request {
        u8 dialog_token;
@@ -1375,8 +1559,6 @@ struct rrm_link_measurement_report {
        u8 variable[0];
 } STRUCT_PACKED;
 
-#define SSID_MAX_LEN 32
-
 /* IEEE Std 802.11ad-2012 - Multi-band element */
 struct multi_band_ie {
        u8 eid; /* WLAN_EID_MULTI_BAND */
@@ -1433,4 +1615,49 @@ enum fst_action {
        FST_ACTION_ON_CHANNEL_TUNNEL = 5,
 };
 
+/* IEEE Std 802.11ac-2013, Annex C - dot11PHYType */
+enum phy_type {
+       PHY_TYPE_UNSPECIFIED = 0,
+       PHY_TYPE_FHSS = 1,
+       PHY_TYPE_DSSS = 2,
+       PHY_TYPE_IRBASEBAND = 3,
+       PHY_TYPE_OFDM = 4,
+       PHY_TYPE_HRDSSS = 5,
+       PHY_TYPE_ERP = 6,
+       PHY_TYPE_HT = 7,
+       PHY_TYPE_DMG = 8,
+       PHY_TYPE_VHT = 9,
+};
+
+/* IEEE P802.11-REVmc/D5.0, 9.4.2.37 - 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)
+#define NEI_REP_BSSID_INFO_AP_REACHABLE (BIT(0) | BIT(1))
+#define NEI_REP_BSSID_INFO_SECURITY BIT(2)
+#define NEI_REP_BSSID_INFO_KEY_SCOPE BIT(3)
+#define NEI_REP_BSSID_INFO_SPECTRUM_MGMT BIT(4)
+#define NEI_REP_BSSID_INFO_QOS BIT(5)
+#define NEI_REP_BSSID_INFO_APSD BIT(6)
+#define NEI_REP_BSSID_INFO_RM BIT(7)
+#define NEI_REP_BSSID_INFO_DELAYED_BA BIT(8)
+#define NEI_REP_BSSID_INFO_IMM_BA BIT(9)
+#define NEI_REP_BSSID_INFO_MOBILITY_DOMAIN BIT(10)
+#define NEI_REP_BSSID_INFO_HT BIT(11)
+#define NEI_REP_BSSID_INFO_VHT BIT(12)
+#define NEI_REP_BSSID_INFO_FTM BIT(13)
+
+/*
+ * IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information
+ * subfields.
+ * Note: These definitions are not the same as other VHT_CHANWIDTH_*.
+ */
+enum nr_chan_width {
+       NR_CHAN_WIDTH_20 = 0,
+       NR_CHAN_WIDTH_40 = 1,
+       NR_CHAN_WIDTH_80 = 2,
+       NR_CHAN_WIDTH_160 = 3,
+       NR_CHAN_WIDTH_80P80 = 4,
+};
+
 #endif /* IEEE802_11_DEFS_H */
index cc88caa..a0c1d1b 100644 (file)
@@ -10,7 +10,7 @@
 #define IEEE802_1X_DEFS_H
 
 #define CS_ID_LEN              8
-#define CS_ID_GCM_AES_128      {0x00, 0x80, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01}
+#define CS_ID_GCM_AES_128      0x0080020001000001ULL
 #define CS_NAME_GCM_AES_128    "GCM-AES-128"
 
 enum macsec_policy {
diff --git a/libeap/src/common/linux_bridge.h b/libeap/src/common/linux_bridge.h
new file mode 100644 (file)
index 0000000..7b76846
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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 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/libeap/src/common/linux_vlan.h b/libeap/src/common/linux_vlan.h
new file mode 100644 (file)
index 0000000..8a1dd6e
--- /dev/null
@@ -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 */
index 28985f5..adaec89 100644 (file)
@@ -89,6 +89,102 @@ enum qca_radiotap_vendor_ids {
  * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED: Event used by driver,
  *     which supports DFS offloading, to indicate a radar pattern has been
  *     detected. The channel is now unusable.
+ *
+ * @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
+ *     information elements to the device driver and firmware.
+ *     Uses the attributes defines in
+ *     enum qca_wlan_vendor_attr_p2p_listen_offload.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP: Command/event used to
+ *     indicate stop request/response of the P2P Listen offload function in
+ *     device. As an event, it indicates either the feature stopped after it
+ *     was already running or feature has actually failed to start. Uses the
+ *     attributes defines in enum qca_wlan_vendor_attr_p2p_listen_offload.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH: After AP starts
+ *     beaconing, this sub command provides the driver, the frequencies on the
+ *     5 GHz band to check for any radar activity. Driver selects one channel
+ *     from this priority list provided through
+ *     @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST and starts
+ *     to check for radar activity on it. If no radar activity is detected
+ *     during the channel availability check period, driver internally switches
+ *     to the selected frequency of operation. If the frequency is zero, driver
+ *     internally selects a channel. The status of this conditional switch is
+ *     indicated through an event using the same sub command through
+ *     @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS. Attributes are
+ *     listed in qca_wlan_vendor_attr_sap_conditional_chan_switch.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GPIO_CONFIG_COMMAND: Set GPIO pins. This uses the
+ *     attributes defined in enum qca_wlan_gpio_attr.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_HW_CAPABILITY: Fetch hardware capabilities.
+ *     This uses @QCA_WLAN_VENDOR_ATTR_GET_HW_CAPABILITY to indicate which
+ *     capabilities are to be fetched and other
+ *     enum qca_wlan_vendor_attr_get_hw_capability attributes to return the
+ *     requested capabilities.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT: Link layer statistics extension.
+ *     enum qca_wlan_vendor_attr_ll_stats_ext attributes are used with this
+ *     command and event.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA: Get capabilities for
+ *     indoor location features. Capabilities are reported in
+ *     QCA_WLAN_VENDOR_ATTR_LOC_CAPA.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION: Start an FTM
+ *     (fine timing measurement) session with one or more peers.
+ *     Specify Session cookie in QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE and
+ *     peer information in QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS.
+ *     On success, 0 or more QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT
+ *     events will be reported, followed by
+ *     QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE event to indicate
+ *     end of session.
+ *     Refer to IEEE P802.11-REVmc/D7.0, 11.24.6
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FTM_ABORT_SESSION: Abort a running session.
+ *     A QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE will be reported with
+ *     status code indicating session was aborted.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT: Event with measurement
+ *     results for one peer. Results are reported in
+ *     QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEER_RESULTS.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE: Event triggered when
+ *     FTM session is finished, either successfully or aborted by
+ *     request.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER: Configure FTM responder
+ *     mode. QCA_WLAN_VENDOR_ATTR_FTM_RESPONDER_ENABLE specifies whether
+ *     to enable or disable the responder. LCI/LCR reports can be
+ *     configured with QCA_WLAN_VENDOR_ATTR_FTM_LCI and
+ *     QCA_WLAN_VENDOR_ATTR_FTM_LCR. Can be called multiple
+ *     times to update the LCI/LCR reports.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS: Perform a standalone AOA (angle of
+ *     arrival) measurement with a single peer. Specify peer MAC address in
+ *     QCA_WLAN_VENDOR_ATTR_MAC_ADDR and measurement type in
+ *     QCA_WLAN_VENDOR_ATTR_AOA_TYPE. Measurement result is reported in
+ *     QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT event.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_AOA_ABORT_MEAS: Abort an AOA measurement. Specify
+ *     peer MAC address in QCA_WLAN_VENDOR_ATTR_MAC_ADDR.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT: Event that reports
+ *     the AOA measurement result.
+ *     Peer MAC address reported in QCA_WLAN_VENDOR_ATTR_MAC_ADDR.
+ *     success/failure status is reported in
+ *     QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS.
+ *     Measurement data is reported in QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT.
+ *     The antenna array(s) used in the measurement are reported in
+ *     QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ENCRYPTION_TEST: Encrypt/decrypt the given
+ *     data as per the given parameters.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI: Get antenna RSSI value for a
+ *     specific chain.
  */
 enum qca_nl80211_vendor_subcmds {
        QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -140,7 +236,11 @@ enum qca_nl80211_vendor_subcmds {
        QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED = 58,
        QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED = 59,
        QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED = 60,
-       /* 61-90 - reserved for QCA */
+       /* 61-73 - reserved for QCA */
+       /* Wi-Fi configuration subcommands */
+       QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION = 74,
+       QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION = 75,
+       /* 76-90 - reserved for QCA */
        QCA_NL80211_VENDOR_SUBCMD_DATA_OFFLOAD = 91,
        QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG = 92,
        QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME = 93,
@@ -156,6 +256,35 @@ enum qca_nl80211_vendor_subcmds {
        QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST = 103,
        QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL = 104,
        QCA_NL80211_VENDOR_SUBCMD_SETBAND = 105,
+       QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN = 106,
+       QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE = 107,
+       QCA_NL80211_VENDOR_SUBCMD_OTA_TEST = 108,
+       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_SET_SAP_CONFIG = 118,
+       QCA_NL80211_VENDOR_SUBCMD_TSF = 119,
+       QCA_NL80211_VENDOR_SUBCMD_WISA = 120,
+       /* 121 - reserved for QCA */
+       QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START = 122,
+       QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP = 123,
+       QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH = 124,
+       QCA_NL80211_VENDOR_SUBCMD_GPIO_CONFIG_COMMAND = 125,
+       QCA_NL80211_VENDOR_SUBCMD_GET_HW_CAPABILITY = 126,
+       QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT = 127,
+       /* FTM/indoor location subcommands */
+       QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA = 128,
+       QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION = 129,
+       QCA_NL80211_VENDOR_SUBCMD_FTM_ABORT_SESSION = 130,
+       QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT = 131,
+       QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE = 132,
+       QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER = 133,
+       QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS = 134,
+       QCA_NL80211_VENDOR_SUBCMD_AOA_ABORT_MEAS = 135,
+       QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT = 136,
+       QCA_NL80211_VENDOR_SUBCMD_ENCRYPTION_TEST = 137,
+       QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI = 138,
 };
 
 
@@ -185,6 +314,84 @@ enum qca_wlan_vendor_attr {
        QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND = 11,
        /* Unsigned 32-bit value from enum qca_set_band. */
        QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE = 12,
+       /* Dummy (NOP) attribute for 64 bit padding */
+       QCA_WLAN_VENDOR_ATTR_PAD = 13,
+       /* Unique FTM session cookie (Unsigned 64 bit). Specified in
+        * QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION. Reported in
+        * the session in QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT and
+        * QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE.
+        */
+       QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE = 14,
+       /* Indoor location capabilities, returned by
+        * QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA.
+        * see enum qca_wlan_vendor_attr_loc_capa.
+        */
+       QCA_WLAN_VENDOR_ATTR_LOC_CAPA = 15,
+       /* Array of nested attributes containing information about each peer
+        * in FTM measurement session. See enum qca_wlan_vendor_attr_peer_info
+        * for supported attributes for each peer.
+        */
+       QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS = 16,
+       /* Array of nested attributes containing measurement results for
+        * one or more peers, reported by the
+        * QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT event.
+        * See enum qca_wlan_vendor_attr_peer_result for list of supported
+        * attributes.
+        */
+       QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEER_RESULTS = 17,
+       /* Flag attribute for enabling or disabling responder functionality. */
+       QCA_WLAN_VENDOR_ATTR_FTM_RESPONDER_ENABLE = 18,
+       /* Used in the QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER
+        * command to specify the LCI report that will be sent by
+        * the responder during a measurement exchange. The format is
+        * defined in IEEE P802.11-REVmc/D7.0, 9.4.2.22.10.
+        */
+       QCA_WLAN_VENDOR_ATTR_FTM_LCI = 19,
+       /* Used in the QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER
+        * command to specify the location civic report that will
+        * be sent by the responder during a measurement exchange.
+        * The format is defined in IEEE P802.11-REVmc/D7.0, 9.4.2.22.13.
+        */
+       QCA_WLAN_VENDOR_ATTR_FTM_LCR = 20,
+       /* Session/measurement completion status code,
+        * reported in QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE and
+        * QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT
+        * see enum qca_vendor_attr_loc_session_status.
+        */
+       QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS = 21,
+       /* Initial dialog token used by responder (0 if not specified),
+        * unsigned 8 bit value.
+        */
+       QCA_WLAN_VENDOR_ATTR_FTM_INITIAL_TOKEN = 22,
+       /* AOA measurement type. Requested in QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS
+        * and optionally in QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION if
+        * AOA measurements are needed as part of an FTM session.
+        * Reported by QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT. See
+        * enum qca_wlan_vendor_attr_aoa_type.
+        */
+       QCA_WLAN_VENDOR_ATTR_AOA_TYPE = 23,
+       /* A bit mask (unsigned 32 bit value) of antenna arrays used
+        * by indoor location measurements. Refers to the antenna
+        * arrays described by QCA_VENDOR_ATTR_LOC_CAPA_ANTENNA_ARRAYS.
+        */
+       QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK = 24,
+       /* AOA measurement data. Its contents depends on the AOA measurement
+        * type and antenna array mask:
+        * QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE: array of U16 values,
+        * phase of the strongest CIR path for each antenna in the measured
+        * array(s).
+        * QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP: array of 2 U16
+        * values, phase and amplitude of the strongest CIR path for each
+        * antenna in the measured array(s).
+        */
+       QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT = 25,
+       /* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command
+        * to specify the chain number (unsigned 32 bit value) to inquire
+        * the corresponding antenna RSSI value */
+       QCA_WLAN_VENDOR_ATTR_CHAIN_INDEX = 26,
+       /* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command
+        * to report the specific antenna RSSI value (unsigned 32 bit value) */
+       QCA_WLAN_VENDOR_ATTR_CHAIN_RSSI = 27,
        /* keep last */
        QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
        QCA_WLAN_VENDOR_ATTR_MAX        = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
@@ -205,12 +412,50 @@ enum qca_wlan_vendor_attr_roam_auth {
        QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR,
        QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK,
        QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK,
+       QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS,
        /* keep last */
        QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST,
        QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX =
        QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST - 1
 };
 
+enum qca_wlan_vendor_attr_p2p_listen_offload {
+       QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INVALID = 0,
+       /* A 32-bit unsigned value; the P2P listen frequency (MHz); must be one
+        * of the social channels.
+        */
+       QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL,
+       /* A 32-bit unsigned value; the P2P listen offload period (ms).
+        */
+       QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD,
+       /* A 32-bit unsigned value; the P2P listen interval duration (ms).
+        */
+       QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL,
+       /* A 32-bit unsigned value; number of interval times the firmware needs
+        * to run the offloaded P2P listen operation before it stops.
+        */
+       QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT,
+       /* An array of arbitrary binary data with one or more 8-byte values.
+        * The device types include both primary and secondary device types.
+        */
+       QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES,
+       /* An array of unsigned 8-bit characters; vendor information elements.
+        */
+       QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE,
+       /* A 32-bit unsigned value; a control flag to indicate whether listen
+        * results need to be flushed to wpa_supplicant.
+        */
+       QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG,
+       /* A 8-bit unsigned value; reason code for P2P listen offload stop
+        * event.
+        */
+       QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON,
+       /* keep last */
+       QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST,
+       QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX =
+       QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST - 1
+};
+
 enum qca_wlan_vendor_attr_acs_offload {
        QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
        QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL,
@@ -247,11 +492,21 @@ enum qca_wlan_vendor_acs_hw_mode {
  *     after roaming, rather than having the user space wpa_supplicant do it.
  * @QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY: Device supports automatic
  *     band selection based on channel selection results.
+ * @QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS: Device supports
+ *     simultaneous off-channel operations.
+ * @QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD: Device supports P2P
+ *     Listen offload; a mechanism where the station's firmware takes care of
+ *     responding to incoming Probe Request frames received from other P2P
+ *     Devices whilst in Listen state, rather than having the user space
+ *     wpa_supplicant do it. Information from received P2P requests are
+ *     forwarded from firmware to host whenever the host processor wakes up.
  * @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
  */
 enum qca_wlan_vendor_features {
        QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD        = 0,
        QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY     = 1,
+       QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS = 2,
+       QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD      = 3,
        NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
 };
 
@@ -324,6 +579,67 @@ enum qca_set_band {
        QCA_SETBAND_2G,
 };
 
+/**
+ * enum qca_access_policy - Access control policy
+ *
+ * Access control policy is applied on the configured IE
+ * (QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE).
+ * To be set with QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY.
+ *
+ * @QCA_ACCESS_POLICY_ACCEPT_UNLESS_LISTED: Deny Wi-Fi connections which match
+ *     the specific configuration (IE) set, i.e., allow all the
+ *     connections which do not match the configuration.
+ * @QCA_ACCESS_POLICY_DENY_UNLESS_LISTED: Accept Wi-Fi connections which match
+ *     the specific configuration (IE) set, i.e., deny all the
+ *     connections which do not match the configuration.
+ */
+enum qca_access_policy {
+       QCA_ACCESS_POLICY_ACCEPT_UNLESS_LISTED,
+       QCA_ACCESS_POLICY_DENY_UNLESS_LISTED,
+};
+
+/**
+ * enum qca_vendor_attr_get_tsf: Vendor attributes for TSF capture
+ * @QCA_WLAN_VENDOR_ATTR_TSF_CMD: enum qca_tsf_operation (u32)
+ * @QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE: Unsigned 64 bit TSF timer value
+ * @QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE: Unsigned 64 bit Synchronized
+ *     SOC timer value at TSF capture
+ */
+enum qca_vendor_attr_tsf_cmd {
+       QCA_WLAN_VENDOR_ATTR_TSF_INVALID = 0,
+       QCA_WLAN_VENDOR_ATTR_TSF_CMD,
+       QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE,
+       QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE,
+       QCA_WLAN_VENDOR_ATTR_TSF_AFTER_LAST,
+       QCA_WLAN_VENDOR_ATTR_TSF_MAX =
+       QCA_WLAN_VENDOR_ATTR_TSF_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_tsf_operation: TSF driver commands
+ * @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
+ */
+enum qca_tsf_cmd {
+       QCA_TSF_CAPTURE,
+       QCA_TSF_GET,
+       QCA_TSF_SYNC_GET,
+};
+
+/**
+ * enum qca_vendor_attr_wisa_cmd
+ * @QCA_WLAN_VENDOR_ATTR_WISA_MODE: WISA mode value (u32)
+ * WISA setup vendor commands
+ */
+enum qca_vendor_attr_wisa_cmd {
+       QCA_WLAN_VENDOR_ATTR_WISA_INVALID = 0,
+       QCA_WLAN_VENDOR_ATTR_WISA_MODE,
+       QCA_WLAN_VENDOR_ATTR_WISA_AFTER_LAST,
+       QCA_WLAN_VENDOR_ATTR_WISA_MAX =
+       QCA_WLAN_VENDOR_ATTR_WISA_AFTER_LAST - 1
+};
+
 /* IEEE 802.11 Vendor Specific elements */
 
 /**
@@ -349,9 +665,926 @@ enum qca_set_band {
  *
  *     This vendor element may be included in GO Negotiation Request, P2P
  *     Invitation Request, and Provision Discovery Request frames.
+ *
+ * @QCA_VENDOR_ELEM_HE_CAPAB: HE Capabilities element.
+ *     This element can be used for pre-standard publication testing of HE
+ *     before P802.11ax draft assigns the element ID. The payload of this
+ *     vendor specific element is defined by the latest P802.11ax draft.
+ *     Please note that the draft is still work in progress and this element
+ *     payload is subject to change.
+ *
+ * @QCA_VENDOR_ELEM_HE_OPER: HE Operation element.
+ *     This element can be used for pre-standard publication testing of HE
+ *     before P802.11ax draft assigns the element ID. The payload of this
+ *     vendor specific element is defined by the latest P802.11ax draft.
+ *     Please note that the draft is still work in progress and this element
+ *     payload is subject to change.
  */
 enum qca_vendor_element_id {
        QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST = 0,
+       QCA_VENDOR_ELEM_HE_CAPAB = 1,
+       QCA_VENDOR_ELEM_HE_OPER = 2,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_scan - Specifies vendor scan attributes
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_IE: IEs that should be included as part of scan
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES: Nested unsigned 32-bit attributes
+ *     with frequencies to be scanned (in MHz)
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS: Nested attribute with SSIDs to be scanned
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES: Nested array attribute of supported
+ *     rates to be included
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE: flag used to send probe requests
+ *     at non CCK rate in 2GHz band
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS: Unsigned 32-bit scan flags
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE: Unsigned 64-bit cookie provided by the
+ *     driver for the specific scan request
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_STATUS: Unsigned 8-bit status of the scan
+ *     request decoded as in enum scan_status
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_MAC: 6-byte MAC address to use when randomisation
+ *     scan flag is set
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK: 6-byte MAC address mask to be used with
+ *     randomisation
+ */
+enum qca_wlan_vendor_attr_scan {
+       QCA_WLAN_VENDOR_ATTR_SCAN_INVALID_PARAM = 0,
+       QCA_WLAN_VENDOR_ATTR_SCAN_IE,
+       QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES,
+       QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS,
+       QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES,
+       QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE,
+       QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS,
+       QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE,
+       QCA_WLAN_VENDOR_ATTR_SCAN_STATUS,
+       QCA_WLAN_VENDOR_ATTR_SCAN_MAC,
+       QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK,
+       QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST,
+       QCA_WLAN_VENDOR_ATTR_SCAN_MAX =
+       QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST - 1
+};
+
+/**
+ * enum scan_status - Specifies the valid values the vendor scan attribute
+ *     QCA_WLAN_VENDOR_ATTR_SCAN_STATUS can take
+ *
+ * @VENDOR_SCAN_STATUS_NEW_RESULTS: implies the vendor scan is successful with
+ *     new scan results
+ * @VENDOR_SCAN_STATUS_ABORTED: implies the vendor scan was aborted in-between
+ */
+enum scan_status {
+       VENDOR_SCAN_STATUS_NEW_RESULTS,
+       VENDOR_SCAN_STATUS_ABORTED,
+       VENDOR_SCAN_STATUS_MAX,
+};
+
+/**
+ * enum qca_vendor_attr_ota_test - Specifies the values for vendor
+ *                       command QCA_NL80211_VENDOR_SUBCMD_OTA_TEST
+ * @QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE: enable ota test
+ */
+enum qca_vendor_attr_ota_test {
+       QCA_WLAN_VENDOR_ATTR_OTA_TEST_INVALID,
+       /* 8-bit unsigned value to indicate if OTA test is enabled */
+       QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE,
+       /* keep last */
+       QCA_WLAN_VENDOR_ATTR_OTA_TEST_AFTER_LAST,
+       QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX =
+       QCA_WLAN_VENDOR_ATTR_OTA_TEST_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_vendor_attr_txpower_scale - vendor sub commands index
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE: scaling value
+ */
+enum qca_vendor_attr_txpower_scale {
+       QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_INVALID,
+       /* 8-bit unsigned value to indicate the scaling of tx power */
+       QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE,
+       /* keep last */
+       QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_AFTER_LAST,
+       QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX =
+       QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_vendor_attr_txpower_decr_db - Attributes for TX power decrease
+ *
+ * These attributes are used with QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_DECR_DB.
+ */
+enum qca_vendor_attr_txpower_decr_db {
+       QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB_INVALID,
+       /* 8-bit unsigned value to indicate the reduction of TX power in dB for
+        * a virtual interface. */
+       QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB,
+       /* keep last */
+       QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB_AFTER_LAST,
+       QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB_MAX =
+       QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB_AFTER_LAST - 1
+};
+
+/* Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION and
+ * QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION subcommands.
+ */
+enum qca_wlan_vendor_attr_config {
+       QCA_WLAN_VENDOR_ATTR_CONFIG_INVALID = 0,
+       /* Unsigned 32-bit value to set the DTIM period.
+        * Whether the wifi chipset wakes at every dtim beacon or a multiple of
+        * the DTIM period. If DTIM is set to 3, the STA shall wake up every 3
+        * DTIM beacons.
+        */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_DYNAMIC_DTIM = 1,
+       /* Unsigned 32-bit value to set the wifi_iface stats averaging factor
+        * used to calculate statistics like average the TSF offset or average
+        * number of frame leaked.
+        * For instance, upon Beacon frame reception:
+        * current_avg = ((beacon_TSF - TBTT) * factor + previous_avg * (0x10000 - factor) ) / 0x10000
+        * For instance, when evaluating leaky APs:
+        * current_avg = ((num frame received within guard time) * factor + previous_avg * (0x10000 - factor)) / 0x10000
+        */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR = 2,
+       /* Unsigned 32-bit value to configure guard time, i.e., when
+        * implementing IEEE power management based on frame control PM bit, how
+        * long the driver waits before shutting down the radio and after
+        * receiving an ACK frame for a Data frame with PM bit set.
+        */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME = 3,
+       /* Unsigned 32-bit value to change the FTM capability dynamically */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_FINE_TIME_MEASUREMENT = 4,
+       /* Unsigned 16-bit value to configure maximum TX rate dynamically */
+       QCA_WLAN_VENDOR_ATTR_CONF_TX_RATE = 5,
+       /* Unsigned 32-bit value to configure the number of continuous
+        * Beacon Miss which shall be used by the firmware to penalize
+        * the RSSI.
+        */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_PENALIZE_AFTER_NCONS_BEACON_MISS = 6,
+       /* Unsigned 8-bit value to configure the channel avoidance indication
+        * behavior. Firmware to send only one indication and ignore duplicate
+        * indications when set to avoid multiple Apps wakeups.
+        */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_AVOIDANCE_IND = 7,
+       /* 8-bit unsigned value to configure the maximum TX MPDU for
+        * aggregation. */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION = 8,
+       /* 8-bit unsigned value to configure the maximum RX MPDU for
+        * aggregation. */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION = 9,
+       /* 8-bit unsigned value to configure the Non aggregrate/11g sw
+        * retry threshold (0 disable, 31 max). */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_NON_AGG_RETRY = 10,
+       /* 8-bit unsigned value to configure the aggregrate sw
+        * retry threshold (0 disable, 31 max). */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_AGG_RETRY = 11,
+       /* 8-bit unsigned value to configure the MGMT frame
+        * retry threshold (0 disable, 31 max). */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_MGMT_RETRY = 12,
+       /* 8-bit unsigned value to configure the CTRL frame
+        * retry threshold (0 disable, 31 max). */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_CTRL_RETRY = 13,
+       /* 8-bit unsigned value to configure the propagation delay for
+        * 2G/5G band (0~63, units in us) */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_DELAY = 14,
+       /* Unsigned 32-bit value to configure the number of unicast TX fail
+        * packet count. The peer is disconnected once this threshold is
+        * reached. */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_TX_FAIL_COUNT = 15,
+       /* Attribute used to set scan default IEs to the driver.
+        *
+        * These IEs can be used by scan operations that will be initiated by
+        * the driver/firmware.
+        *
+        * For further scan requests coming to the driver, these IEs should be
+        * merged with the IEs received along with scan request coming to the
+        * driver. If a particular IE is present in the scan default IEs but not
+        * present in the scan request, then that IE should be added to the IEs
+        * sent in the Probe Request frames for that scan request. */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES = 16,
+       /* Unsigned 32-bit attribute for generic commands */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_COMMAND = 17,
+       /* Unsigned 32-bit value attribute for generic commands */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_VALUE = 18,
+       /* Unsigned 32-bit data attribute for generic command response */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA = 19,
+       /* Unsigned 32-bit length attribute for
+        * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_LENGTH = 20,
+       /* Unsigned 32-bit flags attribute for
+        * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_FLAGS = 21,
+       /* Unsigned 32-bit, defining the access policy.
+        * See enum qca_access_policy. Used with
+        * QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST. */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY = 22,
+       /* Sets the list of full set of IEs for which a specific access policy
+        * has to be applied. Used along with
+        * QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY to control the access.
+        * Zero length payload can be used to clear this access constraint. */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST = 23,
+       /* Unsigned 32-bit, specifies the interface index (netdev) for which the
+        * corresponding configurations are applied. If the interface index is
+        * not specified, the configurations are attributed to the respective
+        * wiphy. */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_IFINDEX = 24,
+       /* 8-bit unsigned value to trigger QPower: 1-Enable, 0-Disable */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER = 25,
+       /* 8-bit unsigned value to configure the driver and below layers to
+        * ignore the assoc disallowed set by APs while connecting
+        * 1-Ignore, 0-Don't ignore */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED = 26,
+       /* 32-bit unsigned value to trigger antenna diversity features:
+        * 1-Enable, 0-Disable */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ENA = 27,
+       /* 32-bit unsigned value to configure specific chain antenna */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_CHAIN = 28,
+       /* 32-bit unsigned value to trigger cycle selftest
+        * 1-Enable, 0-Disable */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST = 29,
+       /* 32-bit unsigned to configure the cycle time of selftest
+        * the unit is micro-second */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST_INTVL = 30,
+
+       /* keep last */
+       QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
+       QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
+       QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_sap_config - Parameters for AP configuration
+ */
+enum qca_wlan_vendor_attr_sap_config {
+       QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_INVALID = 0,
+       /* 1 - reserved for QCA */
+       /* 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
+        * best concurrency sessions (avoid MCC and use DBS/SCC) co-exist in
+        * the system.
+        */
+       QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST = 2,
+
+       QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST,
+       QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX =
+       QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_sap_conditional_chan_switch - Parameters for AP
+ *                                     conditional channel switch
+ */
+enum qca_wlan_vendor_attr_sap_conditional_chan_switch {
+       QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_INVALID = 0,
+       /* Priority based frequency list (an array of u32 values in host byte
+        * order) */
+       QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST = 1,
+       /* Status of the conditional switch (u32).
+        * 0: Success, Non-zero: Failure
+        */
+       QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS = 2,
+
+       QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_AFTER_LAST,
+       QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX =
+       QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_gpio_attr - Parameters for GPIO configuration
+ */
+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,
+       /* Unsigned 32-bit attribute for GPIO PIN number to configure */
+       QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM,
+       /* Unsigned 32-bit attribute for GPIO value to configure */
+       QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE,
+       /* Unsigned 32-bit attribute for GPIO pull type */
+       QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE,
+       /* Unsigned 32-bit attribute for GPIO interrupt mode */
+       QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE,
+
+       /* keep last */
+       QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_LAST,
+       QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MAX =
+       QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_hw_capability - Wi-Fi hardware capability
+ */
+enum qca_wlan_vendor_attr_get_hw_capability {
+       QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_INVALID,
+       /* Antenna isolation
+        * An attribute used in the response.
+        * The content of this attribute is encoded in a byte array. Each byte
+        * value is an antenna isolation value. The array length is the number
+        * of antennas.
+        */
+       QCA_WLAN_VENDOR_ATTR_ANTENNA_ISOLATION,
+       /* Request HW capability
+        * An attribute used in the request.
+        * The content of this attribute is a u32 array for one or more of
+        * hardware capabilities (attribute IDs) that are being requested. Each
+        * u32 value has a value from this
+        * enum qca_wlan_vendor_attr_get_hw_capability
+        * identifying which capabilities are requested.
+        */
+       QCA_WLAN_VENDOR_ATTR_GET_HW_CAPABILITY,
+
+       /* keep last */
+       QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_AFTER_LAST,
+       QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_MAX =
+       QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ll_stats_ext - Attributes for MAC layer monitoring
+ *    offload which is an extension for LL_STATS.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD: Monitoring period. Unit in ms.
+ *    If MAC counters do not exceed the threshold, FW will report monitored
+ *    link layer counters periodically as this setting. The first report is
+ *    always triggered by this timer.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD: It is a percentage (1-99).
+ *    For each MAC layer counter, FW holds two copies. One is the current value.
+ *    The other is the last report. Once a current counter's increment is larger
+ *    than the threshold, FW will indicate that counter to host even if the
+ *    monitoring timer does not expire.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG: Peer STA power state change
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID: TID of MSDU
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU: Count of MSDU with the same
+ *    failure code.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS: TX failure code
+ *    1: TX packet discarded
+ *    2: No ACK
+ *    3: Postpone
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS: peer MAC address
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE: Peer STA current state
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL: Global threshold.
+ *    Threshold for all monitored parameters. If per counter dedicated threshold
+ *    is not enabled, this threshold will take effect.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE: Indicate what triggers this
+ *    event, PERORID_TIMEOUT == 1, THRESH_EXCEED == 0.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID: interface ID
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID: peer ID
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP: bitmap for TX counters
+ *    Bit0: TX counter unit in MSDU
+ *    Bit1: TX counter unit in MPDU
+ *    Bit2: TX counter unit in PPDU
+ *    Bit3: TX counter unit in byte
+ *    Bit4: Dropped MSDUs
+ *    Bit5: Dropped Bytes
+ *    Bit6: MPDU retry counter
+ *    Bit7: MPDU failure counter
+ *    Bit8: PPDU failure counter
+ *    Bit9: MPDU aggregation counter
+ *    Bit10: MCS counter for ACKed MPDUs
+ *    Bit11: MCS counter for Failed MPDUs
+ *    Bit12: TX Delay counter
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP: bitmap for RX counters
+ *    Bit0: MAC RX counter unit in MPDU
+ *    Bit1: MAC RX counter unit in byte
+ *    Bit2: PHY RX counter unit in PPDU
+ *    Bit3: PHY RX counter unit in byte
+ *    Bit4: Disorder counter
+ *    Bit5: Retry counter
+ *    Bit6: Duplication counter
+ *    Bit7: Discard counter
+ *    Bit8: MPDU aggregation size counter
+ *    Bit9: MCS counter
+ *    Bit10: Peer STA power state change (wake to sleep) counter
+ *    Bit11: Peer STA power save counter, total time in PS mode
+ *    Bit12: Probe request counter
+ *    Bit13: Other management frames counter
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP: bitmap for CCA
+ *    Bit0: Idle time
+ *    Bit1: TX time
+ *    Bit2: time RX in current bss
+ *    Bit3: Out of current bss time
+ *    Bit4: Wireless medium busy time
+ *    Bit5: RX in bad condition time
+ *    Bit6: TX in bad condition time
+ *    Bit7: time wlan card not available
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP: bitmap for signal
+ *    Bit0: Per channel SNR counter
+ *    Bit1: Per channel noise floor counter
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM: number of peers
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM: number of channels
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_AC_RX_NUM: number of RX stats
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS: per channel BSS CCA stats
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER: container for per PEER stats
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU: Number of total TX MSDUs
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU: Number of total TX MPDUs
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU: Number of total TX PPDUs
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES: bytes of TX data
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP: Number of dropped TX packets
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES: Bytes dropped
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY: waiting time without an ACK
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK: number of MPDU not-ACKed
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK: number of PPDU not-ACKed
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM:
+ *    aggregation stats buffer length
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM: length of mcs stats
+ *    buffer for ACKed MPDUs.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM: length of mcs stats
+ *    buffer for failed MPDUs.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE:
+ *    length of delay stats array.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR: TX aggregation stats
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS: MCS stats for ACKed MPDUs
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS: MCS stats for failed MPDUs
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY: tx delay stats
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU: MPDUs received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES: bytes received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU: PPDU received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES: PPDU bytes received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST: packets lost
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY: number of RX packets
+ *    flagged as retransmissions
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP: number of RX packets
+ *    flagged as duplicated
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD: number of RX
+ *    packets discarded
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM: length of RX aggregation
+ *    stats buffer.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM: length of RX mcs
+ *    stats buffer.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS: RX mcs stats buffer
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR: aggregation stats buffer
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES: times STAs go to sleep
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION: STAs' total sleep time
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ: number of probe
+ *    requests received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT: number of other mgmt
+ *    frames received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME: Percentage of idle time
+ *    there is no TX, nor RX, nor interference.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME: percentage of time
+ *    transmitting packets.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_TIME: percentage of time
+ *    for receiving.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY: percentage of time
+ *    interference detected.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD: percentage of time
+ *    receiving packets with errors.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD: percentage of time
+ *    TX no-ACK.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL: percentage of time
+ *    the chip is unable to work in normal conditions.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME: percentage of time
+ *    receiving packets in current BSS.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME: percentage of time
+ *    receiving packets not in current BSS.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM: number of antennas
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL:
+ *    This is a container for per antenna signal stats.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR: per antenna SNR value
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF: per antenna NF value
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_RSSI_BEACON: RSSI of beacon
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_SNR_BEACON: SNR of beacon
+ */
+enum qca_wlan_vendor_attr_ll_stats_ext {
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_INVALID = 0,
+
+       /* Attributes for configurations */
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD,
+
+       /* Peer STA power state change */
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG,
+
+       /* TX failure event */
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS,
+
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
+
+       /* MAC counters */
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER,
+
+       /* Sub-attributes for PEER_AC_TX */
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY,
+
+       /* Sub-attributes for PEER_AC_RX */
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT,
+
+       /* Sub-attributes for CCA_BSS */
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_TIME,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL,
+
+       /* sub-attribute for BSS_RX_TIME */
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME,
+
+       /* Sub-attributes for PEER_SIGNAL */
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF,
+
+       /* Sub-attributes for IFACE_BSS */
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_RSSI_BEACON,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_SNR_BEACON,
+
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_LAST,
+       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX =
+               QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_LAST - 1
+};
+
+/* Attributes for FTM commands and events */
+
+/**
+ * enum qca_wlan_vendor_attr_loc_capa - Indoor location capabilities
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAGS: Various flags. See
+ *     enum qca_wlan_vendor_attr_loc_capa_flags.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_SESSIONS: Maximum number
+ *     of measurement sessions that can run concurrently.
+ *     Default is one session (no session concurrency).
+ * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_PEERS: The total number of unique
+ *     peers that are supported in running sessions. For example,
+ *     if the value is 8 and maximum number of sessions is 2, you can
+ *     have one session with 8 unique peers, or 2 sessions with 4 unique
+ *     peers each, and so on.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_BURSTS_EXP: Maximum number
+ *     of bursts per peer, as an exponent (2^value). Default is 0,
+ *     meaning no multi-burst support.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_MEAS_PER_BURST: Maximum number
+ *     of measurement exchanges allowed in a single burst.
+ * @QCA_WLAN_VENDOR_ATTR_AOA_CAPA_SUPPORTED_TYPES: Supported AOA measurement
+ *     types. A bit mask (unsigned 32 bit value), each bit corresponds
+ *     to an AOA type as defined by enum qca_vendor_attr_aoa_type.
+ */
+enum qca_wlan_vendor_attr_loc_capa {
+       QCA_WLAN_VENDOR_ATTR_LOC_CAPA_INVALID,
+       QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAGS,
+       QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_SESSIONS,
+       QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_PEERS,
+       QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_BURSTS_EXP,
+       QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_MEAS_PER_BURST,
+       QCA_WLAN_VENDOR_ATTR_AOA_CAPA_SUPPORTED_TYPES,
+       /* keep last */
+       QCA_WLAN_VENDOR_ATTR_LOC_CAPA_AFTER_LAST,
+       QCA_WLAN_VENDOR_ATTR_LOC_CAPA_MAX =
+       QCA_WLAN_VENDOR_ATTR_LOC_CAPA_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_loc_capa_flags: Indoor location capability flags
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_RESPONDER: Set if driver
+ *     can be configured as an FTM responder (for example, an AP that
+ *     services FTM requests). QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER
+ *     will be supported if set.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_INITIATOR: Set if driver
+ *     can run FTM sessions. QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION
+ *     will be supported if set.
+* @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP: Set if FTM responder
+ *     supports immediate (ASAP) response.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA: Set if driver supports standalone
+ *     AOA measurement using QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA_IN_FTM: Set if driver supports
+ *     requesting AOA measurements as part of an FTM session.
+ */
+enum qca_wlan_vendor_attr_loc_capa_flags {
+       QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_RESPONDER = 1 << 0,
+       QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_INITIATOR = 1 << 1,
+       QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP = 1 << 2,
+       QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA = 1 << 3,
+       QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA_IN_FTM = 1 << 4,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_info: Information about
+ *     a single peer in a measurement session.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR: The MAC address of the peer.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS: Various flags related
+ *     to measurement. See enum qca_wlan_vendor_attr_ftm_peer_meas_flags.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS: Nested attribute of
+ *     FTM measurement parameters, as specified by IEEE P802.11-REVmc/D7.0
+ *     9.4.2.167. See enum qca_wlan_vendor_attr_ftm_meas_param for
+ *     list of supported attributes.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID: Initial token ID for
+ *     secure measurement.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD: Request AOA
+ *     measurement every <value> bursts. If 0 or not specified,
+ *     AOA measurements will be disabled for this peer.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_info {
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_INVALID,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD,
+       /* keep last */
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_AFTER_LAST,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAX =
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_meas_flags: Measurement request flags,
+ *     per-peer
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_ASAP: If set, request
+ *     immediate (ASAP) response from peer.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCI: If set, request
+ *     LCI report from peer. The LCI report includes the absolute
+ *     location of the peer in "official" coordinates (similar to GPS).
+ *     See IEEE P802.11-REVmc/D7.0, 11.24.6.7 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCR: If set, request
+ *     Location civic report from peer. The LCR includes the location
+ *     of the peer in free-form format. See IEEE P802.11-REVmc/D7.0,
+ *     11.24.6.7 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_SECURE: If set,
+ *     request a secure measurement.
+ *     QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID must also be provided.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_meas_flags {
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_ASAP    = 1 << 0,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCI     = 1 << 1,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCR     = 1 << 2,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_SECURE  = 1 << 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_meas_param: Measurement parameters
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST: Number of measurements
+ *     to perform in a single burst.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP: Number of bursts to
+ *     perform, specified as an exponent (2^value).
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION: Duration of burst
+ *     instance, as specified in IEEE P802.11-REVmc/D7.0, 9.4.2.167.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD: Time between bursts,
+ *     as specified in IEEE P802.11-REVmc/D7.0, 9.4.2.167. Must
+ *     be larger than QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION.
+ */
+enum qca_wlan_vendor_attr_ftm_meas_param {
+       QCA_WLAN_VENDOR_ATTR_FTM_PARAM_INVALID,
+       QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST,
+       QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP,
+       QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION,
+       QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD,
+       /* keep last */
+       QCA_WLAN_VENDOR_ATTR_FTM_PARAM_AFTER_LAST,
+       QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MAX =
+       QCA_WLAN_VENDOR_ATTR_FTM_PARAM_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_result: Per-peer results
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAC_ADDR: MAC address of the reported
+ *      peer.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS: Status of measurement
+ *     request for this peer.
+ *     See enum qca_wlan_vendor_attr_ftm_peer_result_status.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAGS: Various flags related
+ *     to measurement results for this peer.
+ *     See enum qca_wlan_vendor_attr_ftm_peer_result_flags.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS: Specified when
+ *     request failed and peer requested not to send an additional request
+ *     for this number of seconds.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCI: LCI report when received
+ *     from peer. In the format specified by IEEE P802.11-REVmc/D7.0,
+ *     9.4.2.22.10.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCR: Location civic report when
+ *     received from peer. In the format specified by IEEE P802.11-REVmc/D7.0,
+ *     9.4.2.22.13.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAMS: Reported when peer
+ *     overridden some measurement request parameters. See
+ *     enum qca_wlan_vendor_attr_ftm_meas_param.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AOA_MEAS: AOA measurement
+ *     for this peer. Same contents as @QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS: Array of measurement
+ *     results. Each entry is a nested attribute defined
+ *     by enum qca_wlan_vendor_attr_ftm_meas.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_result {
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_INVALID,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAC_ADDR,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAGS,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCI,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCR,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAMS,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AOA_MEAS,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS,
+       /* keep last */
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AFTER_LAST,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAX =
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_result_status
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_OK: Request sent ok and results
+ *     will be provided. Peer may have overridden some measurement parameters,
+ *     in which case overridden parameters will be report by
+ *     QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAM attribute.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INCAPABLE: Peer is incapable
+ *     of performing the measurement request. No more results will be sent
+ *     for this peer in this session.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_FAILED: Peer reported request
+ *     failed, and requested not to send an additional request for number
+ *     of seconds specified by QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS
+ *     attribute.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INVALID: Request validation
+ *     failed. Request was not sent over the air.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_result_status {
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_OK,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INCAPABLE,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_FAILED,
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INVALID,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_result_flags: Various flags
+ *  for measurement result, per-peer
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAG_DONE: If set,
+ *     measurement completed for this peer. No more results will be reported
+ *     for this peer in this session.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_result_flags {
+       QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAG_DONE = 1 << 0,
+};
+
+/**
+ * enum qca_vendor_attr_loc_session_status: Session completion status code
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_OK: Session completed
+ *     successfully.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED: Session aborted
+ *     by request.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_INVALID: Session request
+ *     was invalid and was not started.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_FAILED: Session had an error
+ *     and did not complete normally (for example out of resources).
+ */
+enum qca_vendor_attr_loc_session_status {
+       QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_OK,
+       QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED,
+       QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_INVALID,
+       QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_FAILED,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_meas: Single measurement data
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T1: Time of departure (TOD) of FTM packet as
+ *     recorded by responder, in picoseconds.
+ *     See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T2: Time of arrival (TOA) of FTM packet at
+ *     initiator, in picoseconds.
+ *     See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T3: TOD of ACK packet as recorded by
+ *     initiator, in picoseconds.
+ *     See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T4: TOA of ACK packet at
+ *     responder, in picoseconds.
+ *     See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_RSSI: RSSI (signal level) as recorded
+ *     during this measurement exchange. Optional and will be provided if
+ *     the hardware can measure it.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOD_ERR: TOD error reported by
+ *     responder. Not always provided.
+ *     See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOA_ERR: TOA error reported by
+ *     responder. Not always provided.
+ *     See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOD_ERR: TOD error measured by
+ *     initiator. Not always provided.
+ *     See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOA_ERR: TOA error measured by
+ *     initiator. Not always provided.
+ *     See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD: Dummy attribute for padding.
+ */
+enum qca_wlan_vendor_attr_ftm_meas {
+       QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INVALID,
+       QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T1,
+       QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T2,
+       QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T3,
+       QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T4,
+       QCA_WLAN_VENDOR_ATTR_FTM_MEAS_RSSI,
+       QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOD_ERR,
+       QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOA_ERR,
+       QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOD_ERR,
+       QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOA_ERR,
+       QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD,
+       /* keep last */
+       QCA_WLAN_VENDOR_ATTR_FTM_MEAS_AFTER_LAST,
+       QCA_WLAN_VENDOR_ATTR_FTM_MEAS_MAX =
+       QCA_WLAN_VENDOR_ATTR_FTM_MEAS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_aoa_type - AOA measurement type
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE: Phase of the strongest
+ *     CIR (channel impulse response) path for each antenna.
+ * @QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP: Phase and amplitude
+ *     of the strongest CIR path for each antenna.
+ */
+enum qca_wlan_vendor_attr_aoa_type {
+       QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE,
+       QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP,
+       QCA_WLAN_VENDOR_ATTR_AOA_TYPE_MAX
+};
+
+/**
+ * enum qca_wlan_vendor_attr_encryption_test - Attributes to
+ * validate encryption engine
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION: Flag attribute.
+ *     This will be included if the request is for decryption; if not included,
+ *     the request is treated as a request for encryption by default.
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER: Unsigned 32-bit value
+ *     indicating the key cipher suite. Takes same values as
+ *     NL80211_ATTR_KEY_CIPHER.
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID: Unsigned 8-bit value
+ *     Key Id to be used for encryption
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK: Array of 8-bit values.
+ *     Key (TK) to be used for encryption/decryption
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN: Array of 8-bit values.
+ *     Packet number to be specified for encryption/decryption
+ *     6 bytes for TKIP/CCMP/GCMP.
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA: Array of 8-bit values
+ *     representing the 802.11 packet (header + payload + FCS) that
+ *     needs to be encrypted/decrypted.
+ *     Encrypted/decrypted response from the driver will also be sent
+ *     to userspace with the same attribute.
+ */
+enum qca_wlan_vendor_attr_encryption_test {
+       QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_INVALID = 0,
+       QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION,
+       QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER,
+       QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID,
+       QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK,
+       QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN,
+       QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA,
+
+       /* keep last */
+       QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_AFTER_LAST,
+       QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX =
+       QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_AFTER_LAST - 1
 };
 
 #endif /* QCA_VENDOR_H */
index 503fa1d..9f70f03 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Simultaneous authentication of equals
- * Copyright (c) 2012-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2012-2016, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -275,8 +275,9 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
 
        /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
        bits = crypto_ec_prime_len_bits(sae->tmp->ec);
-       sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
-                       prime, sae->tmp->prime_len, pwd_value, bits);
+       if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
+                           prime, sae->tmp->prime_len, pwd_value, bits) < 0)
+               return -1;
        if (bits % 8)
                buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
        wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
@@ -318,11 +319,10 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
        wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
 
        /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
-       sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
-                       sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value,
-                       bits);
-       if (bits % 8)
-               buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
+       if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
+                           sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value,
+                           bits) < 0)
+               return -1;
        wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value,
                        sae->tmp->prime_len);
 
@@ -811,11 +811,13 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
        crypto_bignum_mod(tmp, sae->tmp->order, tmp);
        crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
        wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
-       sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
-                  val, sae->tmp->prime_len, keys, sizeof(keys));
+       if (sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
+                      val, sae->tmp->prime_len, keys, sizeof(keys)) < 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);
+       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);
        wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
@@ -923,7 +925,7 @@ static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
                                   const u8 *end, const u8 **token,
                                   size_t *token_len)
 {
-       if (*pos + (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end) {
+       if ((sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end - *pos) {
                size_t tlen = end - (*pos + (sae->tmp->ec ? 3 : 2) *
                                     sae->tmp->prime_len);
                wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
@@ -946,7 +948,7 @@ static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
 {
        struct crypto_bignum *peer_scalar;
 
-       if (*pos + sae->tmp->prime_len > end) {
+       if (sae->tmp->prime_len > end - *pos) {
                wpa_printf(MSG_DEBUG, "SAE: Not enough data for scalar");
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
        }
@@ -994,7 +996,7 @@ static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
 {
        u8 prime[SAE_MAX_ECC_PRIME_LEN];
 
-       if (pos + 2 * sae->tmp->prime_len > end) {
+       if (2 * sae->tmp->prime_len > end - pos) {
                wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
                           "commit-element");
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -1040,7 +1042,7 @@ static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
        struct crypto_bignum *res, *one;
        const u8 one_bin[1] = { 0x01 };
 
-       if (pos + sae->tmp->prime_len > end) {
+       if (sae->tmp->prime_len > end - pos) {
                wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
                           "commit-element");
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -1098,7 +1100,7 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
        u16 res;
 
        /* Check Finite Cyclic Group */
-       if (pos + 2 > end)
+       if (end - pos < 2)
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
        res = sae_group_allowed(sae, allowed_groups, WPA_GET_LE16(pos));
        if (res != WLAN_STATUS_SUCCESS)
index c07026c..a4270bc 100644 (file)
@@ -45,6 +45,7 @@ struct sae_data {
        enum { SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED } state;
        u16 send_confirm;
        u8 pmk[SAE_PMK_LEN];
+       u8 pmkid[SAE_PMKID_LEN];
        struct crypto_bignum *peer_commit_scalar;
        int group;
        int sync;
index a5cc5b7..75e5c6e 100644 (file)
@@ -5,6 +5,10 @@
 #define VERSION_STR_POSTFIX ""
 #endif /* VERSION_STR_POSTFIX */
 
-#define VERSION_STR "2.5" VERSION_STR_POSTFIX
+#ifndef GIT_VERSION_STR_POSTFIX
+#define GIT_VERSION_STR_POSTFIX ""
+#endif /* GIT_VERSION_STR_POSTFIX */
+
+#define VERSION_STR "2.6" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
 
 #endif /* VERSION_H */
index e9d4248..299b8bb 100644 (file)
@@ -292,38 +292,47 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
        pos = ie + sizeof(struct rsn_ftie);
        end = ie + ie_len;
 
-       while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-               switch (pos[0]) {
+       while (end - pos >= 2) {
+               u8 id, len;
+
+               id = *pos++;
+               len = *pos++;
+               if (len > end - pos)
+                       break;
+
+               switch (id) {
                case FTIE_SUBELEM_R1KH_ID:
-                       if (pos[1] != FT_R1KH_ID_LEN) {
-                               wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
-                                          "length in FTIE: %d", pos[1]);
+                       if (len != FT_R1KH_ID_LEN) {
+                               wpa_printf(MSG_DEBUG,
+                                          "FT: Invalid R1KH-ID length in FTIE: %d",
+                                          len);
                                return -1;
                        }
-                       parse->r1kh_id = pos + 2;
+                       parse->r1kh_id = pos;
                        break;
                case FTIE_SUBELEM_GTK:
-                       parse->gtk = pos + 2;
-                       parse->gtk_len = pos[1];
+                       parse->gtk = pos;
+                       parse->gtk_len = len;
                        break;
                case FTIE_SUBELEM_R0KH_ID:
-                       if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
-                               wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
-                                          "length in FTIE: %d", pos[1]);
+                       if (len < 1 || len > FT_R0KH_ID_MAX_LEN) {
+                               wpa_printf(MSG_DEBUG,
+                                          "FT: Invalid R0KH-ID length in FTIE: %d",
+                                          len);
                                return -1;
                        }
-                       parse->r0kh_id = pos + 2;
-                       parse->r0kh_id_len = pos[1];
+                       parse->r0kh_id = pos;
+                       parse->r0kh_id_len = len;
                        break;
 #ifdef CONFIG_IEEE80211W
                case FTIE_SUBELEM_IGTK:
-                       parse->igtk = pos + 2;
-                       parse->igtk_len = pos[1];
+                       parse->igtk = pos;
+                       parse->igtk_len = len;
                        break;
 #endif /* CONFIG_IEEE80211W */
                }
 
-               pos += 2 + pos[1];
+               pos += len;
        }
 
        return 0;
@@ -345,11 +354,18 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
 
        pos = ies;
        end = ies + ies_len;
-       while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-               switch (pos[0]) {
+       while (end - pos >= 2) {
+               u8 id, len;
+
+               id = *pos++;
+               len = *pos++;
+               if (len > end - pos)
+                       break;
+
+               switch (id) {
                case WLAN_EID_RSN:
-                       parse->rsn = pos + 2;
-                       parse->rsn_len = pos[1];
+                       parse->rsn = pos;
+                       parse->rsn_len = len;
                        ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
                                                   parse->rsn_len + 2,
                                                   &data);
@@ -362,32 +378,32 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
                                parse->rsn_pmkid = data.pmkid;
                        break;
                case WLAN_EID_MOBILITY_DOMAIN:
-                       if (pos[1] < sizeof(struct rsn_mdie))
+                       if (len < sizeof(struct rsn_mdie))
                                return -1;
-                       parse->mdie = pos + 2;
-                       parse->mdie_len = pos[1];
+                       parse->mdie = pos;
+                       parse->mdie_len = len;
                        break;
                case WLAN_EID_FAST_BSS_TRANSITION:
-                       if (pos[1] < sizeof(*ftie))
+                       if (len < sizeof(*ftie))
                                return -1;
-                       ftie = (const struct rsn_ftie *) (pos + 2);
+                       ftie = (const struct rsn_ftie *) pos;
                        prot_ie_count = ftie->mic_control[1];
-                       if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
+                       if (wpa_ft_parse_ftie(pos, len, parse) < 0)
                                return -1;
                        break;
                case WLAN_EID_TIMEOUT_INTERVAL:
-                       if (pos[1] != 5)
+                       if (len != 5)
                                break;
-                       parse->tie = pos + 2;
-                       parse->tie_len = pos[1];
+                       parse->tie = pos;
+                       parse->tie_len = len;
                        break;
                case WLAN_EID_RIC_DATA:
                        if (parse->ric == NULL)
-                               parse->ric = pos;
+                               parse->ric = pos - 2;
                        break;
                }
 
-               pos += 2 + pos[1];
+               pos += len;
        }
 
        if (prot_ie_count == 0)
@@ -416,13 +432,15 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
        }
 
        /* Determine the end of the RIC IE(s) */
-       pos = parse->ric;
-       while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
-              prot_ie_count) {
-               prot_ie_count--;
-               pos += 2 + pos[1];
+       if (parse->ric) {
+               pos = parse->ric;
+               while (end - pos >= 2 && 2 + pos[1] <= end - pos &&
+                      prot_ie_count) {
+                       prot_ie_count--;
+                       pos += 2 + pos[1];
+               }
+               parse->ric_len = pos - parse->ric;
        }
-       parse->ric_len = pos - parse->ric;
        if (prot_ie_count) {
                wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
                           "frame", (int) prot_ie_count);
@@ -582,8 +600,10 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
        if (left >= RSN_SELECTOR_LEN) {
                data->group_cipher = rsn_selector_to_bitfield(pos);
                if (!wpa_cipher_valid_group(data->group_cipher)) {
-                       wpa_printf(MSG_DEBUG, "%s: invalid group cipher 0x%x",
-                                  __func__, data->group_cipher);
+                       wpa_printf(MSG_DEBUG,
+                                  "%s: invalid group cipher 0x%x (%08x)",
+                                  __func__, data->group_cipher,
+                                  WPA_GET_BE32(pos));
                        return -1;
                }
                pos += RSN_SELECTOR_LEN;
@@ -671,9 +691,10 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
        if (left >= 4) {
                data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
                if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) {
-                       wpa_printf(MSG_DEBUG, "%s: Unsupported management "
-                                  "group cipher 0x%x", __func__,
-                                  data->mgmt_group_cipher);
+                       wpa_printf(MSG_DEBUG,
+                                  "%s: Unsupported management group cipher 0x%x (%08x)",
+                                  __func__, data->mgmt_group_cipher,
+                                  WPA_GET_BE32(pos));
                        return -10;
                }
                pos += RSN_SELECTOR_LEN;
@@ -1163,6 +1184,8 @@ const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
                        "WPA2-PSK" : "WPA-PSK";
        case WPA_KEY_MGMT_NONE:
                return "NONE";
+       case WPA_KEY_MGMT_WPA_NONE:
+               return "WPA-NONE";
        case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
                return "IEEE 802.1X (no WPA)";
 #ifdef CONFIG_IEEE80211R
@@ -1261,13 +1284,13 @@ int wpa_compare_rsn_ie(int ft_initial_assoc,
 
 
 #ifdef CONFIG_IEEE80211R
-int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
+int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid)
 {
        u8 *start, *end, *rpos, *rend;
        int added = 0;
 
        start = ies;
-       end = ies + ies_len;
+       end = ies + *ies_len;
 
        while (start < end) {
                if (*start == WLAN_EID_RSN)
@@ -1320,11 +1343,29 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
                added += 2 + PMKID_LEN;
                start[1] += 2 + PMKID_LEN;
        } else {
-               /* PMKID-Count was included; use it */
-               if (WPA_GET_LE16(rpos) != 0) {
-                       wpa_printf(MSG_ERROR, "FT: Unexpected PMKID "
-                                  "in RSN IE in EAPOL-Key data");
+               u16 num_pmkid;
+
+               if (rend - rpos < 2)
                        return -1;
+               num_pmkid = WPA_GET_LE16(rpos);
+               /* PMKID-Count was included; use it */
+               if (num_pmkid != 0) {
+                       u8 *after;
+
+                       if (num_pmkid * PMKID_LEN > rend - rpos - 2)
+                               return -1;
+                       /*
+                        * PMKID may have been included in RSN IE in
+                        * (Re)Association Request frame, so remove the old
+                        * PMKID(s) first before adding the new one.
+                        */
+                       wpa_printf(MSG_DEBUG,
+                                  "FT: Remove %u old PMKID(s) from RSN IE",
+                                  num_pmkid);
+                       after = rpos + 2 + num_pmkid * PMKID_LEN;
+                       os_memmove(rpos + 2, after, rend - after);
+                       start[1] -= num_pmkid * PMKID_LEN;
+                       added -= num_pmkid * PMKID_LEN;
                }
                WPA_PUT_LE16(rpos, 1);
                rpos += 2;
@@ -1337,7 +1378,9 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
        wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
                    "(PMKID inserted)", start, 2 + start[1]);
 
-       return added;
+       *ies_len += added;
+
+       return 0;
 }
 #endif /* CONFIG_IEEE80211R */
 
index c08f651..af1d0f0 100644 (file)
@@ -12,6 +12,8 @@
 /* IEEE 802.11i */
 #define PMKID_LEN 16
 #define PMK_LEN 32
+#define PMK_LEN_SUITE_B_192 48
+#define PMK_LEN_MAX 48
 #define WPA_REPLAY_COUNTER_LEN 8
 #define WPA_NONCE_LEN 32
 #define WPA_KEY_RSC_LEN 8
@@ -407,7 +409,7 @@ u32 wpa_akm_to_suite(int akm);
 int wpa_compare_rsn_ie(int ft_initial_assoc,
                       const u8 *ie1, size_t ie1len,
                       const u8 *ie2, size_t ie2len);
-int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid);
+int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid);
 
 struct wpa_ft_ies {
        const u8 *mdie;
index 5733aa6..623c2a7 100644 (file)
@@ -532,6 +532,8 @@ retry_send:
                FD_ZERO(&rfds);
                FD_SET(ctrl->s, &rfds);
                res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+               if (res < 0 && errno == EINTR)
+                       continue;
                if (res < 0)
                        return res;
                if (FD_ISSET(ctrl->s, &rfds)) {
index 3de4682..4dcba81 100644 (file)
@@ -76,6 +76,21 @@ extern "C" {
 #define WPA_EVENT_SIGNAL_CHANGE "CTRL-EVENT-SIGNAL-CHANGE "
 /** Regulatory domain channel */
 #define WPA_EVENT_REGDOM_CHANGE "CTRL-EVENT-REGDOM-CHANGE "
+/** Channel switch (followed by freq=<MHz> and other channel parameters) */
+#define WPA_EVENT_CHANNEL_SWITCH "CTRL-EVENT-CHANNEL-SWITCH "
+
+/** IP subnet status change notification
+ *
+ * When using an offloaded roaming mechanism where driver/firmware takes care
+ * of roaming and IP subnet validation checks post-roaming, this event can
+ * indicate whether IP subnet has changed.
+ *
+ * The event has a status=<0/1/2> parameter where
+ * 0 = unknown
+ * 1 = IP subnet unchanged (can continue to use the old IP address)
+ * 2 = IP subnet changed (need to get a new IP address)
+ */
+#define WPA_EVENT_SUBNET_STATUS_UPDATE "CTRL-EVENT-SUBNET-STATUS-UPDATE "
 
 /** RSN IBSS 4-way handshakes completed with specified peer */
 #define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED "
@@ -174,6 +189,7 @@ extern "C" {
 #define P2P_EVENT_SERV_ASP_RESP "P2P-SERV-ASP-RESP "
 #define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
 #define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
+#define P2P_EVENT_INVITATION_ACCEPTED "P2P-INVITATION-ACCEPTED "
 #define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED "
 #define P2P_EVENT_PERSISTENT_PSK_FAIL "P2P-PERSISTENT-PSK-FAIL id="
 #define P2P_EVENT_PRESENCE_RESPONSE "P2P-PRESENCE-RESPONSE "
@@ -212,6 +228,11 @@ extern "C" {
 /* parameters: <addr> <result> */
 #define ANQP_QUERY_DONE "ANQP-QUERY-DONE "
 
+#define RX_ANQP "RX-ANQP "
+#define RX_HS20_ANQP "RX-HS20-ANQP "
+#define RX_HS20_ANQP_ICON "RX-HS20-ANQP-ICON "
+#define RX_HS20_ICON "RX-HS20-ICON "
+
 #define HS20_SUBSCRIPTION_REMEDIATION "HS20-SUBSCRIPTION-REMEDIATION "
 #define HS20_DEAUTH_IMMINENT_NOTICE "HS20-DEAUTH-IMMINENT-NOTICE "
 
@@ -232,6 +253,7 @@ extern "C" {
 #define AP_STA_CONNECTED "AP-STA-CONNECTED "
 #define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
 #define AP_STA_POSSIBLE_PSK_MISMATCH "AP-STA-POSSIBLE-PSK-MISMATCH "
+#define AP_STA_POLL_OK "AP-STA-POLL-OK "
 
 #define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
 #define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
@@ -254,9 +276,18 @@ extern "C" {
 
 #define AP_CSA_FINISHED "AP-CSA-FINISHED "
 
+#define P2P_EVENT_LISTEN_OFFLOAD_STOP "P2P-LISTEN-OFFLOAD-STOPPED "
+#define P2P_LISTEN_OFFLOAD_STOP_REASON "P2P-LISTEN-OFFLOAD-STOP-REASON "
+
 /* BSS Transition Management Response frame received */
 #define BSS_TM_RESP "BSS-TM-RESP "
 
+/* MBO IE with cellular data connection preference received */
+#define MBO_CELL_PREFERENCE "MBO-CELL-PREFERENCE "
+
+/* BSS Transition Management Request received with MBO transition reason */
+#define MBO_TRANSITION_REASON "MBO-TRANSITION-REASON "
+
 /* BSS command information masks */
 
 #define WPA_BSS_MASK_ALL               0xFFFDFFFF
@@ -300,6 +331,7 @@ enum wpa_vendor_elem_frame {
        VENDOR_ELEM_P2P_ASSOC_REQ = 11,
        VENDOR_ELEM_P2P_ASSOC_RESP = 12,
        VENDOR_ELEM_ASSOC_REQ = 13,
+       VENDOR_ELEM_PROBE_REQ = 14,
        NUM_VENDOR_ELEM_FRAMES
 };
 
index 28913b9..f159421 100644 (file)
@@ -172,7 +172,8 @@ int get_wpa_status(const char *ifname, const char *field, char *obuf,
        if (ctrl == NULL)
                return -1;
        len = sizeof(buf);
-       if (wpa_ctrl_request(ctrl, "STATUS", 6, buf, &len, NULL) < 0) {
+       if (wpa_ctrl_request(ctrl, "STATUS-NO_EVENTS", 16, buf, &len,
+                            NULL) < 0) {
                wpa_ctrl_close(ctrl);
                return -1;
        }
index 3e90350..d181e72 100644 (file)
@@ -47,7 +47,9 @@ LIB_OBJS= \
        sha256.o \
        sha256-prf.o \
        sha256-tlsprf.o \
-       sha256-internal.o
+       sha256-internal.o \
+       sha384-internal.o \
+       sha512-internal.o
 
 LIB_OBJS += crypto_internal.o
 LIB_OBJS += crypto_internal-cipher.o
index 2833cfc..0835f2c 100644 (file)
@@ -28,6 +28,9 @@ int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
        u8 *pos = data;
        int i, j, blocks;
 
+       if (TEST_FAIL())
+               return -1;
+
        ctx = aes_encrypt_init(key, 16);
        if (ctx == NULL)
                return -1;
@@ -61,6 +64,9 @@ int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
        u8 *pos = data;
        int i, j, blocks;
 
+       if (TEST_FAIL())
+               return -1;
+
        ctx = aes_decrypt_init(key, 16);
        if (ctx == NULL)
                return -1;
index 375db57..8642516 100644 (file)
@@ -48,6 +48,9 @@ int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
        const u8 *pos, *end;
        size_t i, e, left, total_len;
 
+       if (TEST_FAIL())
+               return -1;
+
        ctx = aes_encrypt_init(key, key_len);
        if (ctx == NULL)
                return -1;
index 368bacf..0dc073d 100644 (file)
@@ -85,6 +85,28 @@ int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
                  u8 *mac);
 
 /**
+ * sha384_vector - SHA384 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 on failure
+ */
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+                 u8 *mac);
+
+/**
+ * sha512_vector - SHA512 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 on failure
+ */
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+                 u8 *mac);
+
+/**
  * des_encrypt - Encrypt one block with DES
  * @clear: 8 octets (in)
  * @key: 7 octets (in) (no parity bits included)
@@ -140,7 +162,8 @@ void aes_decrypt_deinit(void *ctx);
 enum crypto_hash_alg {
        CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,
        CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1,
-       CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256
+       CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256,
+       CRYPTO_HASH_ALG_SHA384, CRYPTO_HASH_ALG_SHA512
 };
 
 struct crypto_hash;
index f3602da..d391f48 100644 (file)
@@ -11,6 +11,8 @@
 #include "common.h"
 #include "crypto.h"
 #include "sha256_i.h"
+#include "sha384_i.h"
+#include "sha512_i.h"
 #include "sha1_i.h"
 #include "md5_i.h"
 
@@ -22,6 +24,12 @@ struct crypto_hash {
 #ifdef CONFIG_SHA256
                struct sha256_state sha256;
 #endif /* CONFIG_SHA256 */
+#ifdef CONFIG_INTERNAL_SHA384
+               struct sha384_state sha384;
+#endif /* CONFIG_INTERNAL_SHA384 */
+#ifdef CONFIG_INTERNAL_SHA512
+               struct sha512_state sha512;
+#endif /* CONFIG_INTERNAL_SHA512 */
        } u;
        u8 key[64];
        size_t key_len;
@@ -54,6 +62,16 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
                sha256_init(&ctx->u.sha256);
                break;
 #endif /* CONFIG_SHA256 */
+#ifdef CONFIG_INTERNAL_SHA384
+       case CRYPTO_HASH_ALG_SHA384:
+               sha384_init(&ctx->u.sha384);
+               break;
+#endif /* CONFIG_INTERNAL_SHA384 */
+#ifdef CONFIG_INTERNAL_SHA512
+       case CRYPTO_HASH_ALG_SHA512:
+               sha512_init(&ctx->u.sha512);
+               break;
+#endif /* CONFIG_INTERNAL_SHA512 */
        case CRYPTO_HASH_ALG_HMAC_MD5:
                if (key_len > sizeof(k_pad)) {
                        MD5Init(&ctx->u.md5);
@@ -142,6 +160,16 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
                sha256_process(&ctx->u.sha256, data, len);
                break;
 #endif /* CONFIG_SHA256 */
+#ifdef CONFIG_INTERNAL_SHA384
+       case CRYPTO_HASH_ALG_SHA384:
+               sha384_process(&ctx->u.sha384, data, len);
+               break;
+#endif /* CONFIG_INTERNAL_SHA384 */
+#ifdef CONFIG_INTERNAL_SHA512
+       case CRYPTO_HASH_ALG_SHA512:
+               sha512_process(&ctx->u.sha512, data, len);
+               break;
+#endif /* CONFIG_INTERNAL_SHA512 */
        default:
                break;
        }
@@ -191,6 +219,28 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
                sha256_done(&ctx->u.sha256, mac);
                break;
 #endif /* CONFIG_SHA256 */
+#ifdef CONFIG_INTERNAL_SHA384
+       case CRYPTO_HASH_ALG_SHA384:
+               if (*len < 48) {
+                       *len = 48;
+                       os_free(ctx);
+                       return -1;
+               }
+               *len = 48;
+               sha384_done(&ctx->u.sha384, mac);
+               break;
+#endif /* CONFIG_INTERNAL_SHA384 */
+#ifdef CONFIG_INTERNAL_SHA512
+       case CRYPTO_HASH_ALG_SHA512:
+               if (*len < 64) {
+                       *len = 64;
+                       os_free(ctx);
+                       return -1;
+               }
+               *len = 64;
+               sha512_done(&ctx->u.sha512, mac);
+               break;
+#endif /* CONFIG_INTERNAL_SHA512 */
        case CRYPTO_HASH_ALG_HMAC_MD5:
                if (*len < 16) {
                        *len = 16;
index 581005d..ffd2394 100644 (file)
@@ -9,6 +9,7 @@
 #include "utils/includes.h"
 
 #include "utils/common.h"
+#include "utils/module_tests.h"
 #include "crypto/aes_siv.h"
 #include "crypto/aes_wrap.h"
 #include "crypto/aes.h"
@@ -1266,7 +1267,7 @@ static int test_sha1(void)
 }
 
 
-const struct {
+static const struct {
        char *data;
        u8 hash[32];
 } tests[] = {
@@ -1290,7 +1291,7 @@ const struct {
        }
 };
 
-const struct hmac_test {
+static const struct hmac_test {
        u8 key[80];
        size_t key_len;
        u8 data[128];
@@ -1503,6 +1504,7 @@ static int test_sha256(void)
        const u8 *addr[2];
        size_t len[2];
        int errors = 0;
+       u8 *key;
 
        for (i = 0; i < ARRAY_SIZE(tests); i++) {
                wpa_printf(MSG_INFO, "SHA256 test case %d:", i + 1);
@@ -1573,12 +1575,66 @@ static int test_sha256(void)
                   hash, sizeof(hash));
        /* TODO: add proper test case for this */
 
+       key = os_malloc(8161);
+       if (key) {
+#ifdef CONFIG_HMAC_SHA256_KDF
+               int res;
+
+               res = hmac_sha256_kdf((u8 *) "secret", 6, "label",
+                                     (u8 *) "seed", 4, key, 8160);
+               if (res) {
+                       wpa_printf(MSG_INFO,
+                                  "Unexpected hmac_sha256_kdf(outlen=8160) failure");
+                       errors++;
+               }
+
+               res = hmac_sha256_kdf((u8 *) "secret", 6, "label",
+                                     (u8 *) "seed", 4, key, 8161);
+               if (res == 0) {
+                       wpa_printf(MSG_INFO,
+                                  "Unexpected hmac_sha256_kdf(outlen=8161) success");
+                       errors++;
+               }
+#endif /* CONFIG_HMAC_SHA256_KDF */
+
+               os_free(key);
+       }
+
        if (!errors)
                wpa_printf(MSG_INFO, "SHA256 test cases passed");
        return errors;
 }
 
 
+static int test_fips186_2_prf(void)
+{
+       /* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
+       u8 xkey[] = {
+               0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
+               0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
+               0xeb, 0x5a, 0x38, 0xb6
+       };
+       u8 w[] = {
+               0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
+               0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
+               0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
+               0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
+               0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
+       };
+       u8 buf[40];
+
+       wpa_printf(MSG_INFO,
+                  "Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)");
+       if (fips186_2_prf(xkey, sizeof(xkey), buf, sizeof(buf)) < 0 ||
+           os_memcmp(w, buf, sizeof(w)) != 0) {
+               wpa_printf(MSG_INFO, "fips186_2_prf failed");
+               return 1;
+       }
+
+       return 0;
+}
+
+
 static int test_ms_funcs(void)
 {
 #ifndef CONFIG_FIPS
@@ -1695,6 +1751,7 @@ int crypto_module_tests(void)
            test_md5() ||
            test_sha1() ||
            test_sha256() ||
+           test_fips186_2_prf() ||
            test_ms_funcs())
                ret = -1;
 
index 6cff75c..19e0e2b 100644 (file)
 #include "sha1.h"
 #include "sha256.h"
 #include "sha384.h"
+#include "md5.h"
+#include "aes_wrap.h"
 #include "crypto.h"
 
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+/* Compatibility wrappers for older versions. */
+
+static HMAC_CTX * HMAC_CTX_new(void)
+{
+       HMAC_CTX *ctx;
+
+       ctx = os_zalloc(sizeof(*ctx));
+       if (ctx)
+               HMAC_CTX_init(ctx);
+       return ctx;
+}
+
+
+static void HMAC_CTX_free(HMAC_CTX *ctx)
+{
+       if (!ctx)
+               return;
+       HMAC_CTX_cleanup(ctx);
+       bin_clear_free(ctx, sizeof(*ctx));
+}
+
+
+static EVP_MD_CTX * EVP_MD_CTX_new(void)
+{
+       EVP_MD_CTX *ctx;
+
+       ctx = os_zalloc(sizeof(*ctx));
+       if (ctx)
+               EVP_MD_CTX_init(ctx);
+       return ctx;
+}
+
+
+static void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
+{
+       if (!ctx)
+               return;
+       EVP_MD_CTX_cleanup(ctx);
+       bin_clear_free(ctx, sizeof(*ctx));
+}
+
+#endif /* OpenSSL version < 1.1.0 */
+
 static BIGNUM * get_group5_prime(void)
 {
-#ifdef OPENSSL_IS_BORINGSSL
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+       return BN_get_rfc3526_prime_1536(NULL);
+#elif !defined(OPENSSL_IS_BORINGSSL)
+       return get_rfc3526_prime_1536(NULL);
+#else
        static const unsigned char RFC3526_PRIME_1536[] = {
                0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
                0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
@@ -53,9 +103,7 @@ static BIGNUM * get_group5_prime(void)
                0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        };
         return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), NULL);
-#else /* OPENSSL_IS_BORINGSSL */
-       return get_rfc3526_prime_1536(NULL);
-#endif /* OPENSSL_IS_BORINGSSL */
+#endif
 }
 
 #ifdef OPENSSL_NO_SHA256
@@ -65,29 +113,38 @@ static BIGNUM * get_group5_prime(void)
 static int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
                                 const u8 *addr[], const size_t *len, u8 *mac)
 {
-       EVP_MD_CTX ctx;
+       EVP_MD_CTX *ctx;
        size_t i;
        unsigned int mac_len;
 
-       EVP_MD_CTX_init(&ctx);
-       if (!EVP_DigestInit_ex(&ctx, type, NULL)) {
+       if (TEST_FAIL())
+               return -1;
+
+       ctx = EVP_MD_CTX_new();
+       if (!ctx)
+               return -1;
+       if (!EVP_DigestInit_ex(ctx, type, NULL)) {
                wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s",
                           ERR_error_string(ERR_get_error(), NULL));
+               EVP_MD_CTX_free(ctx);
                return -1;
        }
        for (i = 0; i < num_elem; i++) {
-               if (!EVP_DigestUpdate(&ctx, addr[i], len[i])) {
+               if (!EVP_DigestUpdate(ctx, addr[i], len[i])) {
                        wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestUpdate "
                                   "failed: %s",
                                   ERR_error_string(ERR_get_error(), NULL));
+                       EVP_MD_CTX_free(ctx);
                        return -1;
                }
        }
-       if (!EVP_DigestFinal(&ctx, mac, &mac_len)) {
+       if (!EVP_DigestFinal(ctx, mac, &mac_len)) {
                wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s",
                           ERR_error_string(ERR_get_error(), NULL));
+               EVP_MD_CTX_free(ctx);
                return -1;
        }
+       EVP_MD_CTX_free(ctx);
 
        return 0;
 }
@@ -129,32 +186,34 @@ int rc4_skip(const u8 *key, size_t keylen, size_t skip,
 #ifdef OPENSSL_NO_RC4
        return -1;
 #else /* OPENSSL_NO_RC4 */
-       EVP_CIPHER_CTX ctx;
+       EVP_CIPHER_CTX *ctx;
        int outl;
        int res = -1;
        unsigned char skip_buf[16];
 
-       EVP_CIPHER_CTX_init(&ctx);
-       if (!EVP_CIPHER_CTX_set_padding(&ctx, 0) ||
-           !EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, NULL, NULL, 1) ||
-           !EVP_CIPHER_CTX_set_key_length(&ctx, keylen) ||
-           !EVP_CipherInit_ex(&ctx, NULL, NULL, key, NULL, 1))
+       ctx = EVP_CIPHER_CTX_new();
+       if (!ctx ||
+           !EVP_CIPHER_CTX_set_padding(ctx, 0) ||
+           !EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, NULL, NULL, 1) ||
+           !EVP_CIPHER_CTX_set_key_length(ctx, keylen) ||
+           !EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, 1))
                goto out;
 
        while (skip >= sizeof(skip_buf)) {
                size_t len = skip;
                if (len > sizeof(skip_buf))
                        len = sizeof(skip_buf);
-               if (!EVP_CipherUpdate(&ctx, skip_buf, &outl, skip_buf, len))
+               if (!EVP_CipherUpdate(ctx, skip_buf, &outl, skip_buf, len))
                        goto out;
                skip -= len;
        }
 
-       if (EVP_CipherUpdate(&ctx, data, &outl, data, data_len))
+       if (EVP_CipherUpdate(ctx, data, &outl, data, data_len))
                res = 0;
 
 out:
-       EVP_CIPHER_CTX_cleanup(&ctx);
+       if (ctx)
+               EVP_CIPHER_CTX_free(ctx);
        return res;
 #endif /* OPENSSL_NO_RC4 */
 }
@@ -206,14 +265,16 @@ void * aes_encrypt_init(const u8 *key, size_t len)
        EVP_CIPHER_CTX *ctx;
        const EVP_CIPHER *type;
 
+       if (TEST_FAIL())
+               return NULL;
+
        type = aes_get_evp_cipher(len);
        if (type == NULL)
                return NULL;
 
-       ctx = os_malloc(sizeof(*ctx));
+       ctx = EVP_CIPHER_CTX_new();
        if (ctx == NULL)
                return NULL;
-       EVP_CIPHER_CTX_init(ctx);
        if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
                os_free(ctx);
                return NULL;
@@ -247,8 +308,7 @@ void aes_encrypt_deinit(void *ctx)
                wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
                           "in AES encrypt", len);
        }
-       EVP_CIPHER_CTX_cleanup(c);
-       bin_clear_free(c, sizeof(*c));
+       EVP_CIPHER_CTX_free(c);
 }
 
 
@@ -257,16 +317,18 @@ void * aes_decrypt_init(const u8 *key, size_t len)
        EVP_CIPHER_CTX *ctx;
        const EVP_CIPHER *type;
 
+       if (TEST_FAIL())
+               return NULL;
+
        type = aes_get_evp_cipher(len);
        if (type == NULL)
                return NULL;
 
-       ctx = os_malloc(sizeof(*ctx));
+       ctx = EVP_CIPHER_CTX_new();
        if (ctx == NULL)
                return NULL;
-       EVP_CIPHER_CTX_init(ctx);
        if (EVP_DecryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
-               os_free(ctx);
+               EVP_CIPHER_CTX_free(ctx);
                return NULL;
        }
        EVP_CIPHER_CTX_set_padding(ctx, 0);
@@ -298,8 +360,7 @@ void aes_decrypt_deinit(void *ctx)
                wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
                           "in AES decrypt", len);
        }
-       EVP_CIPHER_CTX_cleanup(c);
-       bin_clear_free(c, sizeof(*c));
+       EVP_CIPHER_CTX_free(c);
 }
 
 
@@ -338,51 +399,56 @@ int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
 
 int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
 {
-       EVP_CIPHER_CTX ctx;
+       EVP_CIPHER_CTX *ctx;
        int clen, len;
        u8 buf[16];
+       int res = -1;
 
-       EVP_CIPHER_CTX_init(&ctx);
-       if (EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
+       if (TEST_FAIL())
                return -1;
-       EVP_CIPHER_CTX_set_padding(&ctx, 0);
 
-       clen = data_len;
-       if (EVP_EncryptUpdate(&ctx, data, &clen, data, data_len) != 1 ||
-           clen != (int) data_len)
+       ctx = EVP_CIPHER_CTX_new();
+       if (!ctx)
                return -1;
-
+       clen = data_len;
        len = sizeof(buf);
-       if (EVP_EncryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
-               return -1;
-       EVP_CIPHER_CTX_cleanup(&ctx);
+       if (EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) == 1 &&
+           EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 &&
+           EVP_EncryptUpdate(ctx, data, &clen, data, data_len) == 1 &&
+           clen == (int) data_len &&
+           EVP_EncryptFinal_ex(ctx, buf, &len) == 1 && len == 0)
+               res = 0;
+       EVP_CIPHER_CTX_free(ctx);
 
-       return 0;
+       return res;
 }
 
 
 int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
 {
-       EVP_CIPHER_CTX ctx;
+       EVP_CIPHER_CTX *ctx;
        int plen, len;
        u8 buf[16];
+       int res = -1;
 
-       EVP_CIPHER_CTX_init(&ctx);
-       if (EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
+       if (TEST_FAIL())
                return -1;
-       EVP_CIPHER_CTX_set_padding(&ctx, 0);
 
-       plen = data_len;
-       if (EVP_DecryptUpdate(&ctx, data, &plen, data, data_len) != 1 ||
-           plen != (int) data_len)
+       ctx = EVP_CIPHER_CTX_new();
+       if (!ctx)
                return -1;
-
+       plen = data_len;
        len = sizeof(buf);
-       if (EVP_DecryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
-               return -1;
-       EVP_CIPHER_CTX_cleanup(&ctx);
+       if (EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) == 1 &&
+           EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 &&
+           EVP_DecryptUpdate(ctx, data, &plen, data, data_len) == 1 &&
+           plen == (int) data_len &&
+           EVP_DecryptFinal_ex(ctx, buf, &len) == 1 && len == 0)
+               res = 0;
+       EVP_CIPHER_CTX_free(ctx);
+
+       return res;
 
-       return 0;
 }
 
 
@@ -425,8 +491,8 @@ error:
 
 
 struct crypto_cipher {
-       EVP_CIPHER_CTX enc;
-       EVP_CIPHER_CTX dec;
+       EVP_CIPHER_CTX *enc;
+       EVP_CIPHER_CTX *dec;
 };
 
 
@@ -487,23 +553,25 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
                return NULL;
        }
 
-       EVP_CIPHER_CTX_init(&ctx->enc);
-       EVP_CIPHER_CTX_set_padding(&ctx->enc, 0);
-       if (!EVP_EncryptInit_ex(&ctx->enc, cipher, NULL, NULL, NULL) ||
-           !EVP_CIPHER_CTX_set_key_length(&ctx->enc, key_len) ||
-           !EVP_EncryptInit_ex(&ctx->enc, NULL, NULL, key, iv)) {
-               EVP_CIPHER_CTX_cleanup(&ctx->enc);
+       if (!(ctx->enc = EVP_CIPHER_CTX_new()) ||
+           !EVP_CIPHER_CTX_set_padding(ctx->enc, 0) ||
+           !EVP_EncryptInit_ex(ctx->enc, cipher, NULL, NULL, NULL) ||
+           !EVP_CIPHER_CTX_set_key_length(ctx->enc, key_len) ||
+           !EVP_EncryptInit_ex(ctx->enc, NULL, NULL, key, iv)) {
+               if (ctx->enc)
+                       EVP_CIPHER_CTX_free(ctx->enc);
                os_free(ctx);
                return NULL;
        }
 
-       EVP_CIPHER_CTX_init(&ctx->dec);
-       EVP_CIPHER_CTX_set_padding(&ctx->dec, 0);
-       if (!EVP_DecryptInit_ex(&ctx->dec, cipher, NULL, NULL, NULL) ||
-           !EVP_CIPHER_CTX_set_key_length(&ctx->dec, key_len) ||
-           !EVP_DecryptInit_ex(&ctx->dec, NULL, NULL, key, iv)) {
-               EVP_CIPHER_CTX_cleanup(&ctx->enc);
-               EVP_CIPHER_CTX_cleanup(&ctx->dec);
+       if (!(ctx->dec = EVP_CIPHER_CTX_new()) ||
+           !EVP_CIPHER_CTX_set_padding(ctx->dec, 0) ||
+           !EVP_DecryptInit_ex(ctx->dec, cipher, NULL, NULL, NULL) ||
+           !EVP_CIPHER_CTX_set_key_length(ctx->dec, key_len) ||
+           !EVP_DecryptInit_ex(ctx->dec, NULL, NULL, key, iv)) {
+               EVP_CIPHER_CTX_free(ctx->enc);
+               if (ctx->dec)
+                       EVP_CIPHER_CTX_free(ctx->dec);
                os_free(ctx);
                return NULL;
        }
@@ -516,7 +584,7 @@ int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
                          u8 *crypt, size_t len)
 {
        int outl;
-       if (!EVP_EncryptUpdate(&ctx->enc, crypt, &outl, plain, len))
+       if (!EVP_EncryptUpdate(ctx->enc, crypt, &outl, plain, len))
                return -1;
        return 0;
 }
@@ -527,7 +595,7 @@ int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
 {
        int outl;
        outl = len;
-       if (!EVP_DecryptUpdate(&ctx->dec, plain, &outl, crypt, len))
+       if (!EVP_DecryptUpdate(ctx->dec, plain, &outl, crypt, len))
                return -1;
        return 0;
 }
@@ -535,19 +603,21 @@ int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
 
 void crypto_cipher_deinit(struct crypto_cipher *ctx)
 {
-       EVP_CIPHER_CTX_cleanup(&ctx->enc);
-       EVP_CIPHER_CTX_cleanup(&ctx->dec);
+       EVP_CIPHER_CTX_free(ctx->enc);
+       EVP_CIPHER_CTX_free(ctx->dec);
        os_free(ctx);
 }
 
 
 void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
 {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
        DH *dh;
        struct wpabuf *pubkey = NULL, *privkey = NULL;
        size_t publen, privlen;
 
        *priv = NULL;
+       wpabuf_free(*publ);
        *publ = NULL;
 
        dh = DH_new();
@@ -586,11 +656,63 @@ err:
        wpabuf_clear_free(privkey);
        DH_free(dh);
        return NULL;
+#else
+       DH *dh;
+       struct wpabuf *pubkey = NULL, *privkey = NULL;
+       size_t publen, privlen;
+       BIGNUM *p = NULL, *g;
+       const BIGNUM *priv_key = NULL, *pub_key = NULL;
+
+       *priv = NULL;
+       wpabuf_free(*publ);
+       *publ = NULL;
+
+       dh = DH_new();
+       if (dh == NULL)
+               return NULL;
+
+       g = BN_new();
+       p = get_group5_prime();
+       if (!g || BN_set_word(g, 2) != 1 || !p ||
+           DH_set0_pqg(dh, p, NULL, g) != 1)
+               goto err;
+       p = NULL;
+       g = NULL;
+
+       if (DH_generate_key(dh) != 1)
+               goto err;
+
+       DH_get0_key(dh, &pub_key, &priv_key);
+       publen = BN_num_bytes(pub_key);
+       pubkey = wpabuf_alloc(publen);
+       if (!pubkey)
+               goto err;
+       privlen = BN_num_bytes(priv_key);
+       privkey = wpabuf_alloc(privlen);
+       if (!privkey)
+               goto err;
+
+       BN_bn2bin(pub_key, wpabuf_put(pubkey, publen));
+       BN_bn2bin(priv_key, wpabuf_put(privkey, privlen));
+
+       *priv = privkey;
+       *publ = pubkey;
+       return dh;
+
+err:
+       BN_free(p);
+       BN_free(g);
+       wpabuf_clear_free(pubkey);
+       wpabuf_clear_free(privkey);
+       DH_free(dh);
+       return NULL;
+#endif
 }
 
 
 void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
 {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
        DH *dh;
 
        dh = DH_new();
@@ -621,6 +743,42 @@ void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
 err:
        DH_free(dh);
        return NULL;
+#else
+       DH *dh;
+       BIGNUM *p = NULL, *g, *priv_key = NULL, *pub_key = NULL;
+
+       dh = DH_new();
+       if (dh == NULL)
+               return NULL;
+
+       g = BN_new();
+       p = get_group5_prime();
+       if (!g || BN_set_word(g, 2) != 1 || !p ||
+           DH_set0_pqg(dh, p, NULL, g) != 1)
+               goto err;
+       p = NULL;
+       g = NULL;
+
+       priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL);
+       pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL);
+       if (!priv_key || !pub_key || DH_set0_key(dh, pub_key, priv_key) != 1)
+               goto err;
+       pub_key = NULL;
+       priv_key = NULL;
+
+       if (DH_generate_key(dh) != 1)
+               goto err;
+
+       return dh;
+
+err:
+       BN_free(p);
+       BN_free(g);
+       BN_free(pub_key);
+       BN_clear_free(priv_key);
+       DH_free(dh);
+       return NULL;
+#endif
 }
 
 
@@ -672,7 +830,7 @@ void dh5_free(void *ctx)
 
 
 struct crypto_hash {
-       HMAC_CTX ctx;
+       HMAC_CTX *ctx;
 };
 
 
@@ -707,16 +865,17 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
        ctx = os_zalloc(sizeof(*ctx));
        if (ctx == NULL)
                return NULL;
-       HMAC_CTX_init(&ctx->ctx);
+       ctx->ctx = HMAC_CTX_new();
+       if (!ctx->ctx) {
+               os_free(ctx);
+               return NULL;
+       }
 
-#if OPENSSL_VERSION_NUMBER < 0x00909000
-       HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL);
-#else /* openssl < 0.9.9 */
-       if (HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL) != 1) {
+       if (HMAC_Init_ex(ctx->ctx, key, key_len, md, NULL) != 1) {
+               HMAC_CTX_free(ctx->ctx);
                bin_clear_free(ctx, sizeof(*ctx));
                return NULL;
        }
-#endif /* openssl < 0.9.9 */
 
        return ctx;
 }
@@ -726,7 +885,7 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
 {
        if (ctx == NULL)
                return;
-       HMAC_Update(&ctx->ctx, data, len);
+       HMAC_Update(ctx->ctx, data, len);
 }
 
 
@@ -739,18 +898,14 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
                return -2;
 
        if (mac == NULL || len == NULL) {
+               HMAC_CTX_free(ctx->ctx);
                bin_clear_free(ctx, sizeof(*ctx));
                return 0;
        }
 
        mdlen = *len;
-#if OPENSSL_VERSION_NUMBER < 0x00909000
-       HMAC_Final(&ctx->ctx, mac, &mdlen);
-       res = 1;
-#else /* openssl < 0.9.9 */
-       res = HMAC_Final(&ctx->ctx, mac, &mdlen);
-#endif /* openssl < 0.9.9 */
-       HMAC_CTX_cleanup(&ctx->ctx);
+       res = HMAC_Final(ctx->ctx, mac, &mdlen);
+       HMAC_CTX_free(ctx->ctx);
        bin_clear_free(ctx, sizeof(*ctx));
 
        if (res == 1) {
@@ -767,28 +922,26 @@ static int openssl_hmac_vector(const EVP_MD *type, const u8 *key,
                               const u8 *addr[], const size_t *len, u8 *mac,
                               unsigned int mdlen)
 {
-       HMAC_CTX ctx;
+       HMAC_CTX *ctx;
        size_t i;
        int res;
 
-       HMAC_CTX_init(&ctx);
-#if OPENSSL_VERSION_NUMBER < 0x00909000
-       HMAC_Init_ex(&ctx, key, key_len, type, NULL);
-#else /* openssl < 0.9.9 */
-       if (HMAC_Init_ex(&ctx, key, key_len, type, NULL) != 1)
+       if (TEST_FAIL())
                return -1;
-#endif /* openssl < 0.9.9 */
+
+       ctx = HMAC_CTX_new();
+       if (!ctx)
+               return -1;
+       res = HMAC_Init_ex(ctx, key, key_len, type, NULL);
+       if (res != 1)
+               goto done;
 
        for (i = 0; i < num_elem; i++)
-               HMAC_Update(&ctx, addr[i], len[i]);
+               HMAC_Update(ctx, addr[i], len[i]);
 
-#if OPENSSL_VERSION_NUMBER < 0x00909000
-       HMAC_Final(&ctx, mac, &mdlen);
-       res = 1;
-#else /* openssl < 0.9.9 */
-       res = HMAC_Final(&ctx, mac, &mdlen);
-#endif /* openssl < 0.9.9 */
-       HMAC_CTX_cleanup(&ctx);
+       res = HMAC_Final(ctx, mac, &mdlen);
+done:
+       HMAC_CTX_free(ctx);
 
        return res == 1 ? 0 : -1;
 }
@@ -892,6 +1045,9 @@ int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
        int ret = -1;
        size_t outlen, i;
 
+       if (TEST_FAIL())
+               return -1;
+
        ctx = CMAC_CTX_new();
        if (ctx == NULL)
                return -1;
@@ -941,13 +1097,20 @@ int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
 
 struct crypto_bignum * crypto_bignum_init(void)
 {
+       if (TEST_FAIL())
+               return NULL;
        return (struct crypto_bignum *) BN_new();
 }
 
 
 struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len)
 {
-       BIGNUM *bn = BN_bin2bn(buf, len, NULL);
+       BIGNUM *bn;
+
+       if (TEST_FAIL())
+               return NULL;
+
+       bn = BN_bin2bn(buf, len, NULL);
        return (struct crypto_bignum *) bn;
 }
 
@@ -966,6 +1129,9 @@ int crypto_bignum_to_bin(const struct crypto_bignum *a,
 {
        int num_bytes, offset;
 
+       if (TEST_FAIL())
+               return -1;
+
        if (padlen > buflen)
                return -1;
 
@@ -1019,6 +1185,9 @@ int crypto_bignum_exptmod(const struct crypto_bignum *a,
        int res;
        BN_CTX *bnctx;
 
+       if (TEST_FAIL())
+               return -1;
+
        bnctx = BN_CTX_new();
        if (bnctx == NULL)
                return -1;
@@ -1037,6 +1206,8 @@ int crypto_bignum_inverse(const struct crypto_bignum *a,
        BIGNUM *res;
        BN_CTX *bnctx;
 
+       if (TEST_FAIL())
+               return -1;
        bnctx = BN_CTX_new();
        if (bnctx == NULL)
                return -1;
@@ -1052,6 +1223,8 @@ int crypto_bignum_sub(const struct crypto_bignum *a,
                      const struct crypto_bignum *b,
                      struct crypto_bignum *c)
 {
+       if (TEST_FAIL())
+               return -1;
        return BN_sub((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b) ?
                0 : -1;
 }
@@ -1065,6 +1238,9 @@ int crypto_bignum_div(const struct crypto_bignum *a,
 
        BN_CTX *bnctx;
 
+       if (TEST_FAIL())
+               return -1;
+
        bnctx = BN_CTX_new();
        if (bnctx == NULL)
                return -1;
@@ -1085,6 +1261,9 @@ int crypto_bignum_mulmod(const struct crypto_bignum *a,
 
        BN_CTX *bnctx;
 
+       if (TEST_FAIL())
+               return -1;
+
        bnctx = BN_CTX_new();
        if (bnctx == NULL)
                return -1;
@@ -1128,6 +1307,9 @@ int crypto_bignum_legendre(const struct crypto_bignum *a,
        BIGNUM *exp = NULL, *tmp = NULL;
        int res = -2;
 
+       if (TEST_FAIL())
+               return -2;
+
        bnctx = BN_CTX_new();
        if (bnctx == NULL)
                return -2;
@@ -1252,6 +1434,8 @@ void crypto_ec_deinit(struct crypto_ec *e)
 
 struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e)
 {
+       if (TEST_FAIL())
+               return NULL;
        if (e == NULL)
                return NULL;
        return (struct crypto_ec_point *) EC_POINT_new(e->group);
@@ -1298,6 +1482,9 @@ int crypto_ec_point_to_bin(struct crypto_ec *e,
        int ret = -1;
        int len = BN_num_bytes(e->prime);
 
+       if (TEST_FAIL())
+               return -1;
+
        x_bn = BN_new();
        y_bn = BN_new();
 
@@ -1328,6 +1515,9 @@ struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
        EC_POINT *elem;
        int len = BN_num_bytes(e->prime);
 
+       if (TEST_FAIL())
+               return NULL;
+
        x = BN_bin2bn(val, len, NULL);
        y = BN_bin2bn(val + len, len, NULL);
        elem = EC_POINT_new(e->group);
@@ -1355,6 +1545,8 @@ int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
                        const struct crypto_ec_point *b,
                        struct crypto_ec_point *c)
 {
+       if (TEST_FAIL())
+               return -1;
        return EC_POINT_add(e->group, (EC_POINT *) c, (const EC_POINT *) a,
                            (const EC_POINT *) b, e->bnctx) ? 0 : -1;
 }
@@ -1364,6 +1556,8 @@ int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
                        const struct crypto_bignum *b,
                        struct crypto_ec_point *res)
 {
+       if (TEST_FAIL())
+               return -1;
        return EC_POINT_mul(e->group, (EC_POINT *) res, NULL,
                            (const EC_POINT *) p, (const BIGNUM *) b, e->bnctx)
                ? 0 : -1;
@@ -1372,6 +1566,8 @@ int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
 
 int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)
 {
+       if (TEST_FAIL())
+               return -1;
        return EC_POINT_invert(e->group, (EC_POINT *) p, e->bnctx) ? 0 : -1;
 }
 
@@ -1380,6 +1576,8 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
                                  struct crypto_ec_point *p,
                                  const struct crypto_bignum *x, int y_bit)
 {
+       if (TEST_FAIL())
+               return -1;
        if (!EC_POINT_set_compressed_coordinates_GFp(e->group, (EC_POINT *) p,
                                                     (const BIGNUM *) x, y_bit,
                                                     e->bnctx) ||
@@ -1395,6 +1593,9 @@ crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
 {
        BIGNUM *tmp, *tmp2, *y_sqr = NULL;
 
+       if (TEST_FAIL())
+               return NULL;
+
        tmp = BN_new();
        tmp2 = BN_new();
 
index ccdbfc8..425c848 100644 (file)
@@ -15,6 +15,7 @@
 
 void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
 {
+       wpabuf_free(*publ);
        *publ = dh_init(dh_groups_get(5), priv);
        if (*publ == NULL)
                return NULL;
index 3aeb2bb..7912361 100644 (file)
@@ -1218,14 +1218,19 @@ struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv)
 
        pv_len = dh->prime_len;
        pv = wpabuf_alloc(pv_len);
-       if (pv == NULL)
+       if (pv == NULL) {
+               wpabuf_clear_free(*priv);
+               *priv = NULL;
                return NULL;
+       }
        if (crypto_mod_exp(dh->generator, dh->generator_len,
                           wpabuf_head(*priv), wpabuf_len(*priv),
                           dh->prime, dh->prime_len, wpabuf_mhead(pv),
                           &pv_len) < 0) {
                wpabuf_clear_free(pv);
                wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
+               wpabuf_clear_free(*priv);
+               *priv = NULL;
                return NULL;
        }
        wpabuf_put(pv, pv_len);
index fb03efc..4697e04 100644 (file)
@@ -17,6 +17,19 @@ static void sha1_transform(u32 *state, const u8 data[64])
 {
        SHA_CTX context;
        os_memset(&context, 0, sizeof(context));
+#if defined(OPENSSL_IS_BORINGSSL) && !defined(ANDROID)
+       context.h[0] = state[0];
+       context.h[1] = state[1];
+       context.h[2] = state[2];
+       context.h[3] = state[3];
+       context.h[4] = state[4];
+       SHA1_Transform(&context, data);
+       state[0] = context.h[0];
+       state[1] = context.h[1];
+       state[2] = context.h[2];
+       state[3] = context.h[3];
+       state[4] = context.h[4];
+#else
        context.h0 = state[0];
        context.h1 = state[1];
        context.h2 = state[2];
@@ -28,6 +41,7 @@ static void sha1_transform(u32 *state, const u8 data[64])
        state[2] = context.h2;
        state[3] = context.h3;
        state[4] = context.h4;
+#endif
 }
 
 
@@ -62,12 +76,11 @@ int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
                        /* w_i = G(t, XVAL) */
                        os_memcpy(_t, t, 20);
                        sha1_transform(_t, xkey);
-                       _t[0] = host_to_be32(_t[0]);
-                       _t[1] = host_to_be32(_t[1]);
-                       _t[2] = host_to_be32(_t[2]);
-                       _t[3] = host_to_be32(_t[3]);
-                       _t[4] = host_to_be32(_t[4]);
-                       os_memcpy(xpos, _t, 20);
+                       WPA_PUT_BE32(xpos, _t[0]);
+                       WPA_PUT_BE32(xpos + 4, _t[1]);
+                       WPA_PUT_BE32(xpos + 8, _t[2]);
+                       WPA_PUT_BE32(xpos + 12, _t[3]);
+                       WPA_PUT_BE32(xpos + 16, _t[4]);
 
                        /* XKEY = (1 + XKEY + w_i) mod 2^b */
                        carry = 1;
index cd5e6ca..d9c737a 100644 (file)
@@ -31,6 +31,9 @@ int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
        MD4_CTX ctx;
        size_t i;
 
+       if (TEST_FAIL())
+               return -1;
+
        MD4Init(&ctx);
        for (i = 0; i < num_elem; i++)
                MD4Update(&ctx, addr[i], len[i]);
index f0a2a5d..944698a 100644 (file)
@@ -33,6 +33,9 @@ int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
        MD5_CTX ctx;
        size_t i;
 
+       if (TEST_FAIL())
+               return -1;
+
        MD5Init(&ctx);
        for (i = 0; i < num_elem; i++)
                MD5Update(&ctx, addr[i], len[i]);
index 053d203..d0d6a96 100644 (file)
@@ -48,7 +48,7 @@ static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
                                WPA_PUT_LE16(ucs2_buffer + j,
                                             ((c & 0x1F) << 6) | (c2 & 0x3F));
                                j += 2;
-                       } else if (i == utf8_string_len ||
+                       } else if (i == utf8_string_len - 1 ||
                                   j >= ucs2_buffer_size - 1) {
                                /* incomplete surrogate */
                                return -1;
index 24bc3ff..ffcba66 100644 (file)
@@ -33,6 +33,9 @@ int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
        SHA1_CTX ctx;
        size_t i;
 
+       if (TEST_FAIL())
+               return -1;
+
        SHA1Init(&ctx);
        for (i = 0; i < num_elem; i++)
                SHA1Update(&ctx, addr[i], len[i]);
@@ -294,7 +297,6 @@ void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
                         255);
        }
        /* Wipe variables */
-       i = 0;
        os_memset(context->buffer, 0, 64);
        os_memset(context->state, 0, 20);
        os_memset(context->count, 0, 8);
index 35299b0..86a548e 100644 (file)
@@ -28,6 +28,9 @@ int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
        struct sha256_state ctx;
        size_t i;
 
+       if (TEST_FAIL())
+               return -1;
+
        sha256_init(&ctx);
        for (i = 0; i < num_elem; i++)
                if (sha256_process(&ctx, addr[i], len[i]))
index 79791c0..722cad6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * SHA256-based PRF (IEEE 802.11r)
- * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
+ * 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.
  * @data_len: Length of the data
  * @buf: Buffer for the generated pseudo-random key
  * @buf_len: 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.
  */
-void sha256_prf(const u8 *key, size_t key_len, const char *label,
+int sha256_prf(const u8 *key, size_t key_len, const char *label,
                const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
 {
-       sha256_prf_bits(key, key_len, label, data, data_len, buf, buf_len * 8);
+       return sha256_prf_bits(key, key_len, label, data, data_len, buf,
+                              buf_len * 8);
 }
 
 
@@ -42,15 +44,16 @@ void sha256_prf(const u8 *key, size_t key_len, const char *label,
  * @data_len: Length of the data
  * @buf: Buffer for the generated pseudo-random key
  * @buf_len: Number of bits 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. If the requested buf_len is not divisible by eight, the least
  * significant 1-7 bits of the last octet in the output are not part of the
  * requested output.
  */
-void sha256_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 sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
+                   const u8 *data, size_t data_len, u8 *buf,
+                   size_t buf_len_bits)
 {
        u16 counter = 1;
        size_t pos, plen;
@@ -75,11 +78,14 @@ void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
                plen = buf_len - pos;
                WPA_PUT_LE16(counter_le, counter);
                if (plen >= SHA256_MAC_LEN) {
-                       hmac_sha256_vector(key, key_len, 4, addr, len,
-                                          &buf[pos]);
+                       if (hmac_sha256_vector(key, key_len, 4, addr, len,
+                                              &buf[pos]) < 0)
+                               return -1;
                        pos += SHA256_MAC_LEN;
                } else {
-                       hmac_sha256_vector(key, key_len, 4, addr, len, hash);
+                       if (hmac_sha256_vector(key, key_len, 4, addr, len,
+                                              hash) < 0)
+                               return -1;
                        os_memcpy(&buf[pos], hash, plen);
                        pos += plen;
                        break;
@@ -97,4 +103,6 @@ void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
        }
 
        os_memset(hash, 0, sizeof(hash));
+
+       return 0;
 }
index b15f511..5219022 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * SHA256 hash implementation and interface functions
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * 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.
@@ -15,11 +15,11 @@ int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
                       const u8 *addr[], const size_t *len, u8 *mac);
 int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
                size_t data_len, u8 *mac);
-void sha256_prf(const u8 *key, size_t key_len, const char *label,
-             const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
-void sha256_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 sha256_prf(const u8 *key, size_t key_len, const char *label,
+              const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+int sha256_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);
 void tls_prf_sha256(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/libeap/src/crypto/sha384-internal.c b/libeap/src/crypto/sha384-internal.c
new file mode 100644 (file)
index 0000000..646f729
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * SHA-384 hash implementation and interface functions
+ * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com>
+ *
+ * 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_i.h"
+#include "crypto.h"
+
+
+/**
+ * sha384_vector - SHA384 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 of failure
+ */
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+                 u8 *mac)
+{
+       struct sha384_state ctx;
+       size_t i;
+
+       sha384_init(&ctx);
+       for (i = 0; i < num_elem; i++)
+               if (sha384_process(&ctx, addr[i], len[i]))
+                       return -1;
+       if (sha384_done(&ctx, mac))
+               return -1;
+       return 0;
+}
+
+
+/* ===== start - public domain SHA384 implementation ===== */
+
+/* This is based on SHA384 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+#define CONST64(n) n ## ULL
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+void sha384_init(struct sha384_state *md)
+{
+       md->curlen = 0;
+       md->length = 0;
+       md->state[0] = CONST64(0xcbbb9d5dc1059ed8);
+       md->state[1] = CONST64(0x629a292a367cd507);
+       md->state[2] = CONST64(0x9159015a3070dd17);
+       md->state[3] = CONST64(0x152fecd8f70e5939);
+       md->state[4] = CONST64(0x67332667ffc00b31);
+       md->state[5] = CONST64(0x8eb44a8768581511);
+       md->state[6] = CONST64(0xdb0c2e0d64f98fa7);
+       md->state[7] = CONST64(0x47b5481dbefa4fa4);
+}
+
+int sha384_process(struct sha384_state *md, const unsigned char *in,
+                  unsigned long inlen)
+{
+       return sha512_process(md, in, inlen);
+}
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (48 bytes)
+   @return CRYPT_OK if successful
+*/
+int sha384_done(struct sha384_state *md, unsigned char *out)
+{
+       unsigned char buf[64];
+
+       if (md->curlen >= sizeof(md->buf))
+               return -1;
+
+       if (sha512_done(md, buf) != 0)
+               return -1;
+
+       os_memcpy(out, buf, 48);
+       return 0;
+}
+
+/* ===== end - public domain SHA384 implementation ===== */
diff --git a/libeap/src/crypto/sha384_i.h b/libeap/src/crypto/sha384_i.h
new file mode 100644 (file)
index 0000000..a00253f
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * SHA-384 internal definitions
+ * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA384_I_H
+#define SHA384_I_H
+
+#include "sha512_i.h"
+
+#define SHA384_BLOCK_SIZE SHA512_BLOCK_SIZE
+
+#define sha384_state sha512_state
+
+void sha384_init(struct sha384_state *md);
+int sha384_process(struct sha384_state *md, const unsigned char *in,
+                  unsigned long inlen);
+int sha384_done(struct sha384_state *md, unsigned char *out);
+
+#endif /* SHA384_I_H */
diff --git a/libeap/src/crypto/sha512-internal.c b/libeap/src/crypto/sha512-internal.c
new file mode 100644 (file)
index 0000000..76c4fe7
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * SHA-512 hash implementation and interface functions
+ * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha512_i.h"
+#include "crypto.h"
+
+
+/**
+ * sha512_vector - SHA512 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 of failure
+ */
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+                 u8 *mac)
+{
+       struct sha512_state ctx;
+       size_t i;
+
+       sha512_init(&ctx);
+       for (i = 0; i < num_elem; i++)
+               if (sha512_process(&ctx, addr[i], len[i]))
+                       return -1;
+       if (sha512_done(&ctx, mac))
+               return -1;
+       return 0;
+}
+
+
+/* ===== start - public domain SHA512 implementation ===== */
+
+/* This is based on SHA512 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+#define CONST64(n) n ## ULL
+
+/* the K array */
+static const u64 K[80] = {
+       CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd),
+       CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc),
+       CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019),
+       CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118),
+       CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe),
+       CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2),
+       CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1),
+       CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694),
+       CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3),
+       CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65),
+       CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483),
+       CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5),
+       CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210),
+       CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4),
+       CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725),
+       CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70),
+       CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926),
+       CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df),
+       CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8),
+       CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b),
+       CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001),
+       CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30),
+       CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910),
+       CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8),
+       CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53),
+       CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8),
+       CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb),
+       CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3),
+       CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60),
+       CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec),
+       CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9),
+       CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b),
+       CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207),
+       CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178),
+       CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6),
+       CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b),
+       CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493),
+       CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c),
+       CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a),
+       CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817)
+};
+
+/* Various logical functions */
+#define Ch(x,y,z)       (z ^ (x & (y ^ z)))
+#define Maj(x,y,z)      (((x | y) & z) | (x & y))
+#define S(x, n)         ROR64c(x, n)
+#define R(x, n)         (((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((u64) n))
+#define Sigma0(x)       (S(x, 28) ^ S(x, 34) ^ S(x, 39))
+#define Sigma1(x)       (S(x, 14) ^ S(x, 18) ^ S(x, 41))
+#define Gamma0(x)       (S(x, 1) ^ S(x, 8) ^ R(x, 7))
+#define Gamma1(x)       (S(x, 19) ^ S(x, 61) ^ R(x, 6))
+#ifndef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
+#define ROR64c(x, y) \
+    ( ((((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((u64) (y) & CONST64(63))) | \
+      ((x) << ((u64) (64 - ((y) & CONST64(63)))))) & \
+      CONST64(0xFFFFFFFFFFFFFFFF))
+
+/* compress 1024-bits */
+static int sha512_compress(struct sha512_state *md, unsigned char *buf)
+{
+       u64 S[8], W[80], t0, t1;
+       int i;
+
+       /* copy state into S */
+       for (i = 0; i < 8; i++) {
+               S[i] = md->state[i];
+       }
+
+       /* copy the state into 1024-bits into W[0..15] */
+       for (i = 0; i < 16; i++)
+               W[i] = WPA_GET_BE64(buf + (8 * i));
+
+       /* fill W[16..79] */
+       for (i = 16; i < 80; i++) {
+               W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
+                       W[i - 16];
+       }
+
+       /* Compress */
+       for (i = 0; i < 80; i++) {
+               t0 = S[7] + Sigma1(S[4]) + Ch(S[4], S[5], S[6]) + K[i] + W[i];
+               t1 = Sigma0(S[0]) + Maj(S[0], S[1], S[2]);
+               S[7] = S[6];
+               S[6] = S[5];
+               S[5] = S[4];
+               S[4] = S[3] + t0;
+               S[3] = S[2];
+               S[2] = S[1];
+               S[1] = S[0];
+               S[0] = t0 + t1;
+       }
+
+       /* feedback */
+       for (i = 0; i < 8; i++) {
+               md->state[i] = md->state[i] + S[i];
+       }
+
+       return 0;
+}
+
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+void sha512_init(struct sha512_state *md)
+{
+       md->curlen = 0;
+       md->length = 0;
+       md->state[0] = CONST64(0x6a09e667f3bcc908);
+       md->state[1] = CONST64(0xbb67ae8584caa73b);
+       md->state[2] = CONST64(0x3c6ef372fe94f82b);
+       md->state[3] = CONST64(0xa54ff53a5f1d36f1);
+       md->state[4] = CONST64(0x510e527fade682d1);
+       md->state[5] = CONST64(0x9b05688c2b3e6c1f);
+       md->state[6] = CONST64(0x1f83d9abfb41bd6b);
+       md->state[7] = CONST64(0x5be0cd19137e2179);
+}
+
+
+/**
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+int sha512_process(struct sha512_state *md, const unsigned char *in,
+                  unsigned long inlen)
+{
+       unsigned long n;
+
+       if (md->curlen >= sizeof(md->buf))
+               return -1;
+
+       while (inlen > 0) {
+               if (md->curlen == 0 && inlen >= SHA512_BLOCK_SIZE) {
+                       if (sha512_compress(md, (unsigned char *) in) < 0)
+                               return -1;
+                       md->length += SHA512_BLOCK_SIZE * 8;
+                       in += SHA512_BLOCK_SIZE;
+                       inlen -= SHA512_BLOCK_SIZE;
+               } else {
+                       n = MIN(inlen, (SHA512_BLOCK_SIZE - md->curlen));
+                       os_memcpy(md->buf + md->curlen, in, n);
+                       md->curlen += n;
+                       in += n;
+                       inlen -= n;
+                       if (md->curlen == SHA512_BLOCK_SIZE) {
+                               if (sha512_compress(md, md->buf) < 0)
+                                       return -1;
+                               md->length += 8 * SHA512_BLOCK_SIZE;
+                               md->curlen = 0;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (64 bytes)
+   @return CRYPT_OK if successful
+*/
+int sha512_done(struct sha512_state *md, unsigned char *out)
+{
+       int i;
+
+       if (md->curlen >= sizeof(md->buf))
+               return -1;
+
+       /* increase the length of the message */
+       md->length += md->curlen * CONST64(8);
+
+       /* append the '1' bit */
+       md->buf[md->curlen++] = (unsigned char) 0x80;
+
+       /* if the length is currently above 112 bytes we append zeros
+        * then compress.  Then we can fall back to padding zeros and length
+        * encoding like normal.
+        */
+       if (md->curlen > 112) {
+               while (md->curlen < 128) {
+                       md->buf[md->curlen++] = (unsigned char) 0;
+               }
+               sha512_compress(md, md->buf);
+               md->curlen = 0;
+       }
+
+       /* pad up to 120 bytes of zeroes
+        * note: that from 112 to 120 is the 64 MSB of the length.  We assume
+        * that you won't hash > 2^64 bits of data... :-)
+        */
+       while (md->curlen < 120) {
+               md->buf[md->curlen++] = (unsigned char) 0;
+       }
+
+       /* store length */
+       WPA_PUT_BE64(md->buf + 120, md->length);
+       sha512_compress(md, md->buf);
+
+       /* copy output */
+       for (i = 0; i < 8; i++)
+               WPA_PUT_BE64(out + (8 * i), md->state[i]);
+
+       return 0;
+}
+
+/* ===== end - public domain SHA512 implementation ===== */
diff --git a/libeap/src/crypto/sha512_i.h b/libeap/src/crypto/sha512_i.h
new file mode 100644 (file)
index 0000000..1089589
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * SHA-512 internal definitions
+ * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA512_I_H
+#define SHA512_I_H
+
+#define SHA512_BLOCK_SIZE 128
+
+struct sha512_state {
+       u64 length, state[8];
+       u32 curlen;
+       u8 buf[SHA512_BLOCK_SIZE];
+};
+
+void sha512_init(struct sha512_state *md);
+int sha512_process(struct sha512_state *md, const unsigned char *in,
+                  unsigned long inlen);
+int sha512_done(struct sha512_state *md, unsigned char *out);
+
+#endif /* SHA512_I_H */
index d02158e..33262da 100644 (file)
@@ -97,6 +97,8 @@ struct tls_config {
 #define TLS_CONN_DISABLE_TLSv1_2 BIT(6)
 #define TLS_CONN_EAP_FAST BIT(7)
 #define TLS_CONN_DISABLE_TLSv1_0 BIT(8)
+#define TLS_CONN_EXT_CERT_CHECK BIT(9)
+#define TLS_CONN_REQUIRE_OCSP_ALL BIT(10)
 
 struct X509; /* from OpenSSL */
 
@@ -143,6 +145,9 @@ struct X509; /* from OpenSSL */
  * @flags: Parameter options (TLS_CONN_*)
  * @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
  *     or %NULL if OCSP is not enabled
+ * @ocsp_stapling_response_multi: DER encoded file with cached OCSP stapling
+ *     response list (OCSPResponseList for ocsp_multi in RFC 6961) or %NULL if
+ *     ocsp_multi is not enabled
  * @server_cert_cb: Optional callback to be used to validate server certificate
  *  when no CA or path was specified. 
  * @server_cert_ctx: Optional context arg for server_cert_cb.
@@ -186,11 +191,7 @@ struct tls_connection_params {
 
        unsigned int flags;
        const char *ocsp_stapling_response;
-
-    /**
-     * If non-null, specifies a callback method that can be used to
-     * confirm the validity of a peer certificate.
-     */
+       const char *ocsp_stapling_response_multi;
     int (*server_cert_cb)(int ok_so_far, X509* cert, void *ca_ctx);
     void *server_cert_ctx;
 };
@@ -344,29 +345,36 @@ int __must_check tls_connection_get_random(void *tls_ctx,
                                         struct tls_random *data);
 
 /**
- * tls_connection_prf - Use TLS-PRF to derive keying material
+ * tls_connection_export_key - Derive keying material from a TLS connection
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
  * @label: Label (e.g., description of the key) for PRF
- * @server_random_first: seed is 0 = client_random|server_random,
- * 1 = server_random|client_random
- * @skip_keyblock: Skip TLS key block from the beginning of PRF output
  * @out: Buffer for output data from TLS-PRF
  * @out_len: Length of the output buffer
  * Returns: 0 on success, -1 on failure
  *
- * tls_connection_prf() is required so that further keying material can be
- * derived from the master secret. Example implementation of this function is in
- * tls_prf_sha1_md5() when it is called with seed set to
- * client_random|server_random (or server_random|client_random). For TLSv1.2 and
- * newer, a different PRF is needed, though.
+ * Exports keying material using the mechanism described in RFC 5705.
+ */
+int __must_check tls_connection_export_key(void *tls_ctx,
+                                          struct tls_connection *conn,
+                                          const char *label,
+                                          u8 *out, size_t out_len);
+
+/**
+ * tls_connection_get_eap_fast_key - Derive key material for EAP-FAST
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @out: Buffer for output data from TLS-PRF
+ * @out_len: Length of the output buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * Exports key material after the normal TLS key block for use with
+ * EAP-FAST. Most callers will want tls_connection_export_key(), but EAP-FAST
+ * uses a different legacy mechanism.
  */
-int __must_check  tls_connection_prf(void *tls_ctx,
-                                    struct tls_connection *conn,
-                                    const char *label,
-                                    int server_random_first,
-                                    int skip_keyblock,
-                                    u8 *out, size_t out_len);
+int __must_check tls_connection_get_eap_fast_key(void *tls_ctx,
+                                                struct tls_connection *conn,
+                                                u8 *out, size_t out_len);
 
 /**
  * tls_connection_handshake - Process TLS handshake (client side)
@@ -469,7 +477,9 @@ enum {
        TLS_CIPHER_RC4_SHA /* 0x0005 */,
        TLS_CIPHER_AES128_SHA /* 0x002f */,
        TLS_CIPHER_RSA_DHE_AES128_SHA /* 0x0031 */,
-       TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */
+       TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */,
+       TLS_CIPHER_RSA_DHE_AES256_SHA /* 0x0039 */,
+       TLS_CIPHER_AES256_SHA /* 0x0035 */,
 };
 
 /**
index f994379..200f0ed 100644 (file)
@@ -37,6 +37,8 @@ struct tls_global {
                         union tls_event_data *data);
        void *cb_ctx;
        int cert_in_cb;
+
+       char *ocsp_stapling_response;
 };
 
 struct tls_connection {
@@ -133,6 +135,7 @@ void tls_deinit(void *ssl_ctx)
                if (global->params_set)
                        gnutls_certificate_free_credentials(global->xcred);
                os_free(global->session_data);
+               os_free(global->ocsp_stapling_response);
                os_free(global);
        }
 
@@ -347,6 +350,18 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
        if (conn == NULL || params == NULL)
                return -1;
 
+       if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+               wpa_printf(MSG_INFO,
+                          "GnuTLS: ocsp=3 not supported");
+               return -1;
+       }
+
+       if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
+               wpa_printf(MSG_INFO,
+                          "GnuTLS: tls_ext_cert_check=1 not supported");
+               return -1;
+       }
+
        if (params->subject_match) {
                wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
                return -1;
@@ -596,6 +611,44 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
 }
 
 
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+static int server_ocsp_status_req(gnutls_session_t session, void *ptr,
+                                 gnutls_datum_t *resp)
+{
+       struct tls_global *global = ptr;
+       char *cached;
+       size_t len;
+
+       if (!global->ocsp_stapling_response) {
+               wpa_printf(MSG_DEBUG, "GnuTLS: OCSP status callback - no response configured");
+               return GNUTLS_E_NO_CERTIFICATE_STATUS;
+       }
+
+       cached = os_readfile(global->ocsp_stapling_response, &len);
+       if (!cached) {
+               wpa_printf(MSG_DEBUG,
+                          "GnuTLS: OCSP status callback - could not read response file (%s)",
+                          global->ocsp_stapling_response);
+               return GNUTLS_E_NO_CERTIFICATE_STATUS;
+       }
+
+       wpa_printf(MSG_DEBUG,
+                  "GnuTLS: OCSP status callback - send cached response");
+       resp->data = gnutls_malloc(len);
+       if (!resp->data) {
+               os_free(resp);
+               return GNUTLS_E_MEMORY_ERROR;
+       }
+
+       os_memcpy(resp->data, cached, len);
+       resp->size = len;
+       os_free(cached);
+
+       return GNUTLS_E_SUCCESS;
+}
+#endif /* 3.1.3 */
+
+
 int tls_global_set_params(void *tls_ctx,
                          const struct tls_connection_params *params)
 {
@@ -690,6 +743,17 @@ int tls_global_set_params(void *tls_ctx,
                }
        }
 
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+       os_free(global->ocsp_stapling_response);
+       if (params->ocsp_stapling_response)
+               global->ocsp_stapling_response =
+                       os_strdup(params->ocsp_stapling_response);
+       else
+               global->ocsp_stapling_response = NULL;
+       gnutls_certificate_set_ocsp_status_request_function(
+               global->xcred, server_ocsp_status_req, global);
+#endif /* 3.1.3 */
+
        global->params_set = 1;
 
        return 0;
@@ -746,15 +810,22 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
 }
 
 
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-                      const char *label, int server_random_first,
-                      int skip_keyblock, u8 *out, size_t out_len)
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+                             const char *label, u8 *out, size_t out_len)
 {
-       if (conn == NULL || conn->session == NULL || skip_keyblock)
+       if (conn == NULL || conn->session == NULL)
                return -1;
 
        return gnutls_prf(conn->session, os_strlen(label), label,
-                         server_random_first, 0, NULL, out_len, (char *) out);
+                         0 /* client_random first */, 0, NULL, out_len,
+                         (char *) out);
+}
+
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+                                   u8 *out, size_t out_len)
+{
+       return -1;
 }
 
 
index 704751d..c7cb5de 100644 (file)
@@ -23,6 +23,11 @@ struct tls_global {
        int server;
        struct tlsv1_credentials *server_cred;
        int check_crl;
+
+       void (*event_cb)(void *ctx, enum tls_event ev,
+                        union tls_event_data *data);
+       void *cb_ctx;
+       int cert_in_cb;
 };
 
 struct tls_connection {
@@ -51,6 +56,11 @@ void * tls_init(const struct tls_config *conf)
        global = os_zalloc(sizeof(*global));
        if (global == NULL)
                return NULL;
+       if (conf) {
+               global->event_cb = conf->event_cb;
+               global->cb_ctx = conf->cb_ctx;
+               global->cert_in_cb = conf->cert_in_cb;
+       }
 
        return global;
 }
@@ -64,10 +74,12 @@ void tls_deinit(void *ssl_ctx)
                tlsv1_client_global_deinit();
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #ifdef CONFIG_TLS_INTERNAL_SERVER
-               tlsv1_cred_free(global->server_cred);
                tlsv1_server_global_deinit();
 #endif /* CONFIG_TLS_INTERNAL_SERVER */
        }
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+       tlsv1_cred_free(global->server_cred);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
        os_free(global);
 }
 
@@ -95,6 +107,8 @@ struct tls_connection * tls_connection_init(void *tls_ctx)
                        os_free(conn);
                        return NULL;
                }
+               tlsv1_client_set_cb(conn->client, global->event_cb,
+                                   global->cb_ctx, global->cert_in_cb);
        }
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #ifdef CONFIG_TLS_INTERNAL_SERVER
@@ -186,6 +200,12 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
        if (conn->client == NULL)
                return -1;
 
+       if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
+               wpa_printf(MSG_INFO,
+                          "TLS: tls_ext_cert_check=1 not supported");
+               return -1;
+       }
+
        cred = tlsv1_cred_alloc();
        if (cred == NULL)
                return -1;
@@ -259,8 +279,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
                return -1;
        }
 
-       tlsv1_client_set_time_checks(
-               conn->client, !(params->flags & TLS_CONN_DISABLE_TIME_CHECKS));
+       tlsv1_client_set_flags(conn->client, params->flags);
 
        return 0;
 #else /* CONFIG_TLS_INTERNAL_CLIENT */
@@ -312,6 +331,13 @@ int tls_global_set_params(void *tls_ctx,
                return -1;
        }
 
+       if (params->ocsp_stapling_response)
+               cred->ocsp_stapling_response =
+                       os_strdup(params->ocsp_stapling_response);
+       if (params->ocsp_stapling_response_multi)
+               cred->ocsp_stapling_response_multi =
+                       os_strdup(params->ocsp_stapling_response_multi);
+
        return 0;
 #else /* CONFIG_TLS_INTERNAL_SERVER */
        return -1;
@@ -368,9 +394,9 @@ static int tls_get_keyblock_size(struct tls_connection *conn)
 }
 
 
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-                      const char *label, int server_random_first,
-                      int skip_keyblock, u8 *out, size_t out_len)
+static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+                             const char *label, int server_random_first,
+                             int skip_keyblock, u8 *out, size_t out_len)
 {
        int ret = -1, skip = 0;
        u8 *tmp_out = NULL;
@@ -390,14 +416,14 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
        if (conn->client) {
                ret = tlsv1_client_prf(conn->client, label,
                                       server_random_first,
-                                      _out, out_len);
+                                      _out, skip + out_len);
        }
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #ifdef CONFIG_TLS_INTERNAL_SERVER
        if (conn->server) {
                ret = tlsv1_server_prf(conn->server, label,
                                       server_random_first,
-                                      _out, out_len);
+                                      _out, skip + out_len);
        }
 #endif /* CONFIG_TLS_INTERNAL_SERVER */
        if (ret == 0 && skip_keyblock)
@@ -408,6 +434,21 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
 }
 
 
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+                             const char *label, u8 *out, size_t out_len)
+{
+       return tls_connection_prf(tls_ctx, conn, label, 0, 0, out, out_len);
+}
+
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+                                   u8 *out, size_t out_len)
+{
+       return tls_connection_prf(tls_ctx, conn, "key expansion", 1, 1, out,
+                                 out_len);
+}
+
+
 struct wpabuf * tls_connection_handshake(void *tls_ctx,
                                         struct tls_connection *conn,
                                         const struct wpabuf *in_data,
@@ -621,7 +662,12 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
 int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
                    char *buf, size_t buflen)
 {
-       /* TODO */
+       if (conn == NULL)
+               return -1;
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+       if (conn->client)
+               return tlsv1_client_get_version(conn->client, buf, buflen);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
        return -1;
 }
 
index ae392ad..dd5681e 100644 (file)
@@ -86,9 +86,15 @@ int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
 }
 
 
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-                      const char *label, int server_random_first,
-                      int skip_keyblock, u8 *out, size_t out_len)
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+                             const char *label, u8 *out, size_t out_len)
+{
+       return -1;
+}
+
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+                                   u8 *out, size_t out_len)
 {
        return -1;
 }
index fab1865..9db8095 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <openssl/ssl.h>
 #include <openssl/err.h>
+#include <openssl/opensslv.h>
 #include <openssl/pkcs12.h>
 #include <openssl/x509v3.h>
 #ifndef OPENSSL_NO_ENGINE
 #include "sha1.h"
 #include "sha256.h"
 #include "tls.h"
+#include "tls_openssl.h"
 
-#if OPENSSL_VERSION_NUMBER < 0x10000000L
-/* ERR_remove_thread_state replaces ERR_remove_state and the latter is
- * deprecated. However, OpenSSL 0.9.8 doesn't include
- * ERR_remove_thread_state. */
-#define ERR_remove_thread_state(tid) ERR_remove_state(0)
+#if !defined(CONFIG_FIPS) &&                             \
+    (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) ||   \
+     defined(EAP_SERVER_FAST))
+#define OPENSSL_NEED_EAP_FAST_PRF
 #endif
 
 #if defined(OPENSSL_IS_BORINGSSL)
@@ -57,6 +58,51 @@ typedef int stack_index_t;
 #endif /* OPENSSL_NO_TLSEXT */
 #endif /* SSL_set_tlsext_status_type */
 
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L || \
+     defined(LIBRESSL_VERSION_NUMBER)) &&    \
+    !defined(BORINGSSL_API_VERSION)
+/*
+ * SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL
+ * 1.1.0 and newer BoringSSL revisions. Provide compatibility wrappers for
+ * older versions.
+ */
+
+static size_t SSL_get_client_random(const SSL *ssl, unsigned char *out,
+                                   size_t outlen)
+{
+       if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
+               return 0;
+       os_memcpy(out, ssl->s3->client_random, SSL3_RANDOM_SIZE);
+       return SSL3_RANDOM_SIZE;
+}
+
+
+static size_t SSL_get_server_random(const SSL *ssl, unsigned char *out,
+                                   size_t outlen)
+{
+       if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
+               return 0;
+       os_memcpy(out, ssl->s3->server_random, SSL3_RANDOM_SIZE);
+       return SSL3_RANDOM_SIZE;
+}
+
+
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
+static size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
+                                        unsigned char *out, size_t outlen)
+{
+       if (!session || session->master_key_length < 0 ||
+           (size_t) session->master_key_length > outlen)
+               return 0;
+       if ((size_t) session->master_key_length < outlen)
+               outlen = session->master_key_length;
+       os_memcpy(out, session->master_key, outlen);
+       return outlen;
+}
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
+
+#endif
+
 #ifdef ANDROID
 #include <openssl/pem.h>
 #include <keystore/keystore_get.h>
@@ -71,6 +117,66 @@ static BIO * BIO_from_keystore(const char *key)
        free(value);
        return bio;
 }
+
+
+static int tls_add_ca_from_keystore(X509_STORE *ctx, const char *key_alias)
+{
+       BIO *bio = BIO_from_keystore(key_alias);
+       STACK_OF(X509_INFO) *stack = NULL;
+       stack_index_t i;
+
+       if (bio) {
+               stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
+               BIO_free(bio);
+       }
+
+       if (!stack) {
+               wpa_printf(MSG_WARNING, "TLS: Failed to parse certificate: %s",
+                          key_alias);
+               return -1;
+       }
+
+       for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
+               X509_INFO *info = sk_X509_INFO_value(stack, i);
+
+               if (info->x509)
+                       X509_STORE_add_cert(ctx, info->x509);
+               if (info->crl)
+                       X509_STORE_add_crl(ctx, info->crl);
+       }
+
+       sk_X509_INFO_pop_free(stack, X509_INFO_free);
+
+       return 0;
+}
+
+
+static int tls_add_ca_from_keystore_encoded(X509_STORE *ctx,
+                                           const char *encoded_key_alias)
+{
+       int rc = -1;
+       int len = os_strlen(encoded_key_alias);
+       unsigned char *decoded_alias;
+
+       if (len & 1) {
+               wpa_printf(MSG_WARNING, "Invalid hex-encoded alias: %s",
+                          encoded_key_alias);
+               return rc;
+       }
+
+       decoded_alias = os_malloc(len / 2 + 1);
+       if (decoded_alias) {
+               if (!hexstr2bin(encoded_key_alias, decoded_alias, len / 2)) {
+                       decoded_alias[len / 2] = '\0';
+                       rc = tls_add_ca_from_keystore(
+                               ctx, (const char *) decoded_alias);
+               }
+               os_free(decoded_alias);
+       }
+
+       return rc;
+}
+
 #endif /* ANDROID */
 
 static int tls_openssl_ref_count = 0;
@@ -97,7 +203,7 @@ struct tls_connection {
        SSL_CTX *ssl_ctx;
        SSL *ssl;
        BIO *ssl_in, *ssl_out;
-#ifndef OPENSSL_NO_ENGINE
+#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
        ENGINE *engine;        /* functional reference to the engine */
        EVP_PKEY *private_key; /* the private key if using engine */
 #endif /* OPENSSL_NO_ENGINE */
@@ -125,10 +231,8 @@ struct tls_connection {
        X509 *peer_issuer;
        X509 *peer_issuer_issuer;
 
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
        unsigned char client_random[SSL3_RANDOM_SIZE];
        unsigned char server_random[SSL3_RANDOM_SIZE];
-#endif
 
     int (*server_cert_cb)(int ok_so_far, X509* cert, void *ca_ctx);
     void *server_cert_ctx;
@@ -528,7 +632,8 @@ static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
                wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for "
                           "system certificate store: subject='%s'", buf);
 
-               if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+               if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
+                                        cert)) {
                        tls_show_errors(MSG_WARNING, __func__,
                                        "Failed to add ca_cert to OpenSSL "
                                        "certificate store");
@@ -626,10 +731,16 @@ static int tls_engine_load_dynamic_generic(const char *pre[],
 
        engine = ENGINE_by_id(id);
        if (engine) {
-               ENGINE_free(engine);
                wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
                           "available", id);
-               return 0;
+               /*
+                * If it was auto-loaded by ENGINE_by_id() we might still
+                * need to tell it which PKCS#11 module to use in legacy
+                * (non-p11-kit) environments. Do so now; even if it was
+                * properly initialised before, setting it again will be
+                * harmless.
+                */
+               goto found;
        }
        ERR_clear_error();
 
@@ -666,7 +777,7 @@ static int tls_engine_load_dynamic_generic(const char *pre[],
                           id, ERR_error_string(ERR_get_error(), NULL));
                return -1;
        }
-
+ found:
        while (post && post[0]) {
                wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]);
                if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) {
@@ -810,6 +921,7 @@ void * tls_init(const struct tls_config *conf)
                }
 #endif /* OPENSSL_FIPS */
 #endif /* CONFIG_FIPS */
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
                SSL_load_error_strings();
                SSL_library_init();
 #ifndef OPENSSL_NO_SHA256
@@ -831,6 +943,7 @@ void * tls_init(const struct tls_config *conf)
 #endif /* OPENSSL_NO_RC2 */
                PKCS12_PBE_add();
 #endif  /* PKCS12_FUNCS */
+#endif /* < 1.1.0 */
        } else {
                context = tls_context_new(conf);
                if (context == NULL)
@@ -851,6 +964,7 @@ void * tls_init(const struct tls_config *conf)
                        os_free(tls_global);
                        tls_global = NULL;
                }
+               os_free(data);
                return NULL;
        }
        data->ssl = ssl;
@@ -931,6 +1045,7 @@ void tls_deinit(void *ssl_ctx)
 
        tls_openssl_ref_count--;
        if (tls_openssl_ref_count == 0) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
 // The next four lines, and two more just below, deal with de-initializing
 // global state in the OpenSSL engine. We (Moonshot) don't want that, since
 // we use OpenSSL elsewhere in our apps (i.e., not only via hostap / libeap.)
@@ -941,6 +1056,7 @@ void tls_deinit(void *ssl_ctx)
                ERR_remove_thread_state(NULL);
 ////           ERR_free_strings();
 ////           EVP_cleanup();
+#endif /* < 1.1.0 */
                os_free(tls_global->ocsp_stapling_response);
                tls_global->ocsp_stapling_response = NULL;
                os_free(tls_global);
@@ -972,10 +1088,32 @@ static int tls_is_pin_error(unsigned int err)
 #endif /* OPENSSL_NO_ENGINE */
 
 
+#ifdef ANDROID
+/* EVP_PKEY_from_keystore comes from system/security/keystore-engine. */
+EVP_PKEY * EVP_PKEY_from_keystore(const char *key_id);
+#endif /* ANDROID */
+
 static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
                           const char *pin, const char *key_id,
                           const char *cert_id, const char *ca_cert_id)
 {
+#if defined(ANDROID) && defined(OPENSSL_IS_BORINGSSL)
+#if !defined(OPENSSL_NO_ENGINE)
+#error "This code depends on OPENSSL_NO_ENGINE being defined by BoringSSL."
+#endif
+       if (!key_id)
+               return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+       conn->engine = NULL;
+       conn->private_key = EVP_PKEY_from_keystore(key_id);
+       if (!conn->private_key) {
+               wpa_printf(MSG_ERROR,
+                          "ENGINE: cannot load private key with id '%s' [%s]",
+                          key_id,
+                          ERR_error_string(ERR_get_error(), NULL));
+               return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+       }
+#endif /* ANDROID && OPENSSL_IS_BORINGSSL */
+
 #ifndef OPENSSL_NO_ENGINE
        int ret = -1;
        if (engine_id == NULL) {
@@ -1073,17 +1211,19 @@ err:
 
 static void tls_engine_deinit(struct tls_connection *conn)
 {
-#ifndef OPENSSL_NO_ENGINE
+#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
        wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
        if (conn->private_key) {
                EVP_PKEY_free(conn->private_key);
                conn->private_key = NULL;
        }
        if (conn->engine) {
+#if !defined(OPENSSL_IS_BORINGSSL)
                ENGINE_finish(conn->engine);
+#endif /* !OPENSSL_IS_BORINGSSL */
                conn->engine = NULL;
        }
-#endif /* OPENSSL_NO_ENGINE */
+#endif /* ANDROID || !OPENSSL_NO_ENGINE */
 }
 
 
@@ -1102,14 +1242,83 @@ int tls_get_errors(void *ssl_ctx)
 }
 
 
+static const char * openssl_content_type(int content_type)
+{
+       switch (content_type) {
+       case 20:
+               return "change cipher spec";
+       case 21:
+               return "alert";
+       case 22:
+               return "handshake";
+       case 23:
+               return "application data";
+       case 24:
+               return "heartbeat";
+       case 256:
+               return "TLS header info"; /* pseudo content type */
+       default:
+               return "?";
+       }
+}
+
+
+static const char * openssl_handshake_type(int content_type, const u8 *buf,
+                                          size_t len)
+{
+       if (content_type != 22 || !buf || len == 0)
+               return "";
+       switch (buf[0]) {
+       case 0:
+               return "hello request";
+       case 1:
+               return "client hello";
+       case 2:
+               return "server hello";
+       case 4:
+               return "new session ticket";
+       case 11:
+               return "certificate";
+       case 12:
+               return "server key exchange";
+       case 13:
+               return "certificate request";
+       case 14:
+               return "server hello done";
+       case 15:
+               return "certificate verify";
+       case 16:
+               return "client key exchange";
+       case 20:
+               return "finished";
+       case 21:
+               return "certificate url";
+       case 22:
+               return "certificate status";
+       default:
+               return "?";
+       }
+}
+
+
 static void tls_msg_cb(int write_p, int version, int content_type,
                       const void *buf, size_t len, SSL *ssl, void *arg)
 {
        struct tls_connection *conn = arg;
        const u8 *pos = buf;
 
-       wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d",
-                  write_p ? "TX" : "RX", version, content_type);
+       if (write_p == 2) {
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: session ver=0x%x content_type=%d",
+                          version, content_type);
+               wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Data", buf, len);
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d (%s/%s)",
+                  write_p ? "TX" : "RX", version, content_type,
+                  openssl_content_type(content_type),
+                  openssl_handshake_type(content_type, buf, len));
        wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Message", buf, len);
        if (content_type == 24 && len >= 3 && pos[0] == 1) {
                size_t payload_len = WPA_GET_BE16(pos + 1);
@@ -1239,6 +1448,8 @@ static int tls_match_altsubject_component(X509 *cert, int type,
                        found++;
        }
 
+       sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
+
        return found;
 }
 
@@ -1351,9 +1562,11 @@ static int tls_match_suffix(X509 *cert, const char *match, int full)
                    1) {
                        wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
                                   full ? "Match" : "Suffix match");
+                       sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
                        return 1;
                }
        }
+       sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
 
        if (dns_name) {
                wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
@@ -1494,7 +1707,8 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
                return;
 
        os_memset(&ev, 0, sizeof(ev));
-       if (conn->cert_probe || context->cert_in_cb) {
+       if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
+           context->cert_in_cb) {
                cert = get_x509_cert(err_cert);
                ev.peer_cert.cert = cert;
        }
@@ -1549,6 +1763,7 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
                pos += gen->d.ia5->length;
                *pos = '\0';
        }
+       sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
 
        for (alt = 0; alt < num_altsubject; alt++)
                ev.peer_cert.altsubject[alt] = altsubject[alt];
@@ -1725,7 +1940,33 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
                                       TLS_FAIL_SERVER_CHAIN_PROBE);
        }
 
-       if (preverify_ok && context->event_cb != NULL)
+#ifdef OPENSSL_IS_BORINGSSL
+       if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
+           preverify_ok) {
+               enum ocsp_result res;
+
+               res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
+                                     conn->peer_issuer,
+                                     conn->peer_issuer_issuer);
+               if (res == OCSP_REVOKED) {
+                       preverify_ok = 0;
+                       openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+                                              "certificate revoked",
+                                              TLS_FAIL_REVOKED);
+                       if (err == X509_V_OK)
+                               X509_STORE_CTX_set_error(
+                                       x509_ctx, X509_V_ERR_CERT_REVOKED);
+               } else if (res != OCSP_GOOD &&
+                          (conn->flags & TLS_CONN_REQUIRE_OCSP)) {
+                       preverify_ok = 0;
+                       openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+                                              "bad certificate status response",
+                                              TLS_FAIL_UNSPECIFIED);
+               }
+       }
+#endif /* OPENSSL_IS_BORINGSSL */
+
+       if (depth == 0 && preverify_ok && context->event_cb != NULL)
                context->event_cb(context->cb_ctx,
                                  TLS_CERT_CHAIN_SUCCESS, NULL);
 
@@ -1865,30 +2106,40 @@ static int tls_connection_ca_cert(struct tls_data *data,
        }
 
 #ifdef ANDROID
+       /* Single alias */
        if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
-               BIO *bio = BIO_from_keystore(&ca_cert[11]);
-               STACK_OF(X509_INFO) *stack = NULL;
-               stack_index_t i;
-
-               if (bio) {
-                       stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
-                       BIO_free(bio);
-               }
-               if (!stack)
+               if (tls_add_ca_from_keystore(SSL_CTX_get_cert_store(ssl_ctx),
+                                            &ca_cert[11]) < 0)
                        return -1;
+               SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+               return 0;
+       }
 
-               for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
-                       X509_INFO *info = sk_X509_INFO_value(stack, i);
-                       if (info->x509) {
-                               X509_STORE_add_cert(ssl_ctx->cert_store,
-                                                   info->x509);
-                       }
-                       if (info->crl) {
-                               X509_STORE_add_crl(ssl_ctx->cert_store,
-                                                  info->crl);
+       /* Multiple aliases separated by space */
+       if (ca_cert && os_strncmp("keystores://", ca_cert, 12) == 0) {
+               char *aliases = os_strdup(&ca_cert[12]);
+               const char *delim = " ";
+               int rc = 0;
+               char *savedptr;
+               char *alias;
+
+               if (!aliases)
+                       return -1;
+               alias = strtok_r(aliases, delim, &savedptr);
+               for (; alias; alias = strtok_r(NULL, delim, &savedptr)) {
+                       if (tls_add_ca_from_keystore_encoded(
+                                   SSL_CTX_get_cert_store(ssl_ctx), alias)) {
+                               wpa_printf(MSG_WARNING,
+                                          "OpenSSL: %s - Failed to add ca_cert %s from keystore",
+                                          __func__, alias);
+                               rc = -1;
+                               break;
                        }
                }
-               sk_X509_INFO_pop_free(stack, X509_INFO_free);
+               os_free(aliases);
+               if (rc)
+                       return rc;
+
                SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
                return 0;
        }
@@ -2112,6 +2363,17 @@ static int tls_connection_client_cert(struct tls_connection *conn,
        if (client_cert == NULL && client_cert_blob == NULL)
                return 0;
 
+#ifdef PKCS12_FUNCS
+#if OPENSSL_VERSION_NUMBER < 0x10002000L
+       /*
+        * Clear previously set extra chain certificates, if any, from PKCS#12
+        * processing in tls_parse_pkcs12() to allow OpenSSL to build a new
+        * chain properly.
+        */
+       SSL_CTX_clear_extra_chain_certs(conn->ssl_ctx);
+#endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */
+#endif /* PKCS12_FUNCS */
+
        if (client_cert_blob &&
            SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob,
                                     client_cert_blob_len) == 1) {
@@ -2259,28 +2521,42 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
        }
 
        if (certs) {
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L
-               SSL_clear_chain_certs(ssl);
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
+               if (ssl)
+                       SSL_clear_chain_certs(ssl);
+               else
+                       SSL_CTX_clear_chain_certs(data->ssl);
                while ((cert = sk_X509_pop(certs)) != NULL) {
                        X509_NAME_oneline(X509_get_subject_name(cert), buf,
                                          sizeof(buf));
                        wpa_printf(MSG_DEBUG, "TLS: additional certificate"
                                   " from PKCS12: subject='%s'", buf);
-                       if (SSL_add1_chain_cert(ssl, cert) != 1) {
+                       if ((ssl && SSL_add1_chain_cert(ssl, cert) != 1) ||
+                           (!ssl && SSL_CTX_add1_chain_cert(data->ssl,
+                                                            cert) != 1)) {
                                tls_show_errors(MSG_DEBUG, __func__,
                                                "Failed to add additional certificate");
                                res = -1;
+                               X509_free(cert);
                                break;
                        }
+                       X509_free(cert);
                }
                if (!res) {
                        /* Try to continue anyway */
                }
-               sk_X509_free(certs);
+               sk_X509_pop_free(certs, X509_free);
 #ifndef OPENSSL_IS_BORINGSSL
-               res = SSL_build_cert_chain(ssl,
-                                          SSL_BUILD_CHAIN_FLAG_CHECK |
-                                          SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
+               if (ssl)
+                       res = SSL_build_cert_chain(
+                               ssl,
+                               SSL_BUILD_CHAIN_FLAG_CHECK |
+                               SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
+               else
+                       res = SSL_CTX_build_cert_chain(
+                               data->ssl,
+                               SSL_BUILD_CHAIN_FLAG_CHECK |
+                               SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
                if (!res) {
                        tls_show_errors(MSG_DEBUG, __func__,
                                        "Failed to build certificate chain");
@@ -2295,9 +2571,7 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
                 */
                res = 0;
 #else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
                SSL_CTX_clear_extra_chain_certs(data->ssl);
-#endif /* OPENSSL_VERSION_NUMBER >= 0x10001000L */
                while ((cert = sk_X509_pop(certs)) != NULL) {
                        X509_NAME_oneline(X509_get_subject_name(cert), buf,
                                          sizeof(buf));
@@ -2309,11 +2583,12 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
                         */
                        if (SSL_CTX_add_extra_chain_cert(data->ssl, cert) != 1)
                        {
+                               X509_free(cert);
                                res = -1;
                                break;
                        }
                }
-               sk_X509_free(certs);
+               sk_X509_pop_free(certs, X509_free);
 #endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
        }
 
@@ -2493,7 +2768,7 @@ static int tls_connection_engine_ca_cert(struct tls_data *data,
 
 static int tls_connection_engine_private_key(struct tls_connection *conn)
 {
-#ifndef OPENSSL_NO_ENGINE
+#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
        if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
                tls_show_errors(MSG_ERROR, __func__,
                                "ENGINE: cannot use private key for TLS");
@@ -2842,16 +3117,6 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
        if (conn == NULL || keys == NULL)
                return -1;
        ssl = conn->ssl;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-       if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL)
-               return -1;
-
-       os_memset(keys, 0, sizeof(*keys));
-       keys->client_random = ssl->s3->client_random;
-       keys->client_random_len = SSL3_RANDOM_SIZE;
-       keys->server_random = ssl->s3->server_random;
-       keys->server_random_len = SSL3_RANDOM_SIZE;
-#else
        if (ssl == NULL)
                return -1;
 
@@ -2862,16 +3127,15 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
        keys->server_random = conn->server_random;
        keys->server_random_len = SSL_get_server_random(
                ssl, conn->server_random, sizeof(conn->server_random));
-#endif
 
        return 0;
 }
 
 
-#ifndef CONFIG_FIPS
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
 static int openssl_get_keyblock_size(SSL *ssl)
 {
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
        const EVP_CIPHER *c;
        const EVP_MD *h;
        int md_size;
@@ -2881,17 +3145,11 @@ static int openssl_get_keyblock_size(SSL *ssl)
                return -1;
 
        c = ssl->enc_read_ctx->cipher;
-#if OPENSSL_VERSION_NUMBER >= 0x00909000L
        h = EVP_MD_CTX_md(ssl->read_hash);
-#else
-       h = ssl->read_hash;
-#endif
        if (h)
                md_size = EVP_MD_size(h);
-#if OPENSSL_VERSION_NUMBER >= 0x10000000L
        else if (ssl->s3)
                md_size = ssl->s3->tmp.new_mac_secret_size;
-#endif
        else
                return -1;
 
@@ -2929,86 +3187,24 @@ static int openssl_get_keyblock_size(SSL *ssl)
                    EVP_CIPHER_iv_length(c));
 #endif
 }
-#endif /* CONFIG_FIPS */
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
 
 
-static int openssl_tls_prf(struct tls_connection *conn,
-                          const char *label, int server_random_first,
-                          int skip_keyblock, u8 *out, size_t out_len)
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+                             const char *label, u8 *out, size_t out_len)
 {
-#ifdef CONFIG_FIPS
-       wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS "
-                  "mode");
-       return -1;
-#else /* CONFIG_FIPS */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-       SSL *ssl;
-       u8 *rnd;
-       int ret = -1;
-       int skip = 0;
-       u8 *tmp_out = NULL;
-       u8 *_out = out;
-       const char *ver;
-
-       /*
-        * TLS library did not support key generation, so get the needed TLS
-        * session parameters and use an internal implementation of TLS PRF to
-        * derive the key.
-        */
-
-       if (conn == NULL)
-               return -1;
-       ssl = conn->ssl;
-       if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL ||
-           ssl->session->master_key_length <= 0)
-               return -1;
-       ver = SSL_get_version(ssl);
-
-       if (skip_keyblock) {
-               skip = openssl_get_keyblock_size(ssl);
-               if (skip < 0)
-                       return -1;
-               tmp_out = os_malloc(skip + out_len);
-               if (!tmp_out)
-                       return -1;
-               _out = tmp_out;
-       }
-
-       rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
-       if (!rnd) {
-               os_free(tmp_out);
+       if (!conn ||
+           SSL_export_keying_material(conn->ssl, out, out_len, label,
+                                      os_strlen(label), NULL, 0, 0) != 1)
                return -1;
-       }
+       return 0;
+}
 
-       if (server_random_first) {
-               os_memcpy(rnd, ssl->s3->server_random, SSL3_RANDOM_SIZE);
-               os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->client_random,
-                       SSL3_RANDOM_SIZE);
-       } else {
-               os_memcpy(rnd, ssl->s3->client_random, SSL3_RANDOM_SIZE);
-               os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->server_random,
-                       SSL3_RANDOM_SIZE);
-       }
 
-       if (os_strcmp(ver, "TLSv1.2") == 0) {
-               tls_prf_sha256(ssl->session->master_key,
-                              ssl->session->master_key_length,
-                              label, rnd, 2 * SSL3_RANDOM_SIZE,
-                              _out, skip + out_len);
-               ret = 0;
-       } else if (tls_prf_sha1_md5(ssl->session->master_key,
-                                   ssl->session->master_key_length,
-                                   label, rnd, 2 * SSL3_RANDOM_SIZE,
-                                   _out, skip + out_len) == 0) {
-               ret = 0;
-       }
-       os_free(rnd);
-       if (ret == 0 && skip_keyblock)
-               os_memcpy(out, _out + skip, out_len);
-       bin_clear_free(tmp_out, skip);
-
-       return ret;
-#else
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+                                   u8 *out, size_t out_len)
+{
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
        SSL *ssl;
        SSL_SESSION *sess;
        u8 *rnd;
@@ -3023,9 +3219,9 @@ static int openssl_tls_prf(struct tls_connection *conn,
        const char *ver;
 
        /*
-        * TLS library did not support key generation, so get the needed TLS
-        * session parameters and use an internal implementation of TLS PRF to
-        * derive the key.
+        * TLS library did not support EAP-FAST key generation, so get the
+        * needed TLS session parameters and use an internal implementation of
+        * TLS PRF to derive the key.
         */
 
        if (conn == NULL)
@@ -3038,15 +3234,13 @@ static int openssl_tls_prf(struct tls_connection *conn,
        if (!ver || !sess)
                return -1;
 
-       if (skip_keyblock) {
-               skip = openssl_get_keyblock_size(ssl);
-               if (skip < 0)
-                       return -1;
-               tmp_out = os_malloc(skip + out_len);
-               if (!tmp_out)
-                       return -1;
-               _out = tmp_out;
-       }
+       skip = openssl_get_keyblock_size(ssl);
+       if (skip < 0)
+               return -1;
+       tmp_out = os_malloc(skip + out_len);
+       if (!tmp_out)
+               return -1;
+       _out = tmp_out;
 
        rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
        if (!rnd) {
@@ -3059,59 +3253,31 @@ static int openssl_tls_prf(struct tls_connection *conn,
        master_key_len = SSL_SESSION_get_master_key(sess, master_key,
                                                    sizeof(master_key));
 
-       if (server_random_first) {
-               os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
-               os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random,
-                         SSL3_RANDOM_SIZE);
-       } else {
-               os_memcpy(rnd, client_random, SSL3_RANDOM_SIZE);
-               os_memcpy(rnd + SSL3_RANDOM_SIZE, server_random,
-                         SSL3_RANDOM_SIZE);
-       }
+       os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
+       os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random, SSL3_RANDOM_SIZE);
 
        if (os_strcmp(ver, "TLSv1.2") == 0) {
                tls_prf_sha256(master_key, master_key_len,
-                              label, rnd, 2 * SSL3_RANDOM_SIZE,
+                              "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
                               _out, skip + out_len);
                ret = 0;
        } else if (tls_prf_sha1_md5(master_key, master_key_len,
-                                   label, rnd, 2 * SSL3_RANDOM_SIZE,
+                                   "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
                                    _out, skip + out_len) == 0) {
                ret = 0;
        }
        os_memset(master_key, 0, sizeof(master_key));
        os_free(rnd);
-       if (ret == 0 && skip_keyblock)
+       if (ret == 0)
                os_memcpy(out, _out + skip, out_len);
        bin_clear_free(tmp_out, skip);
 
        return ret;
-#endif
-#endif /* CONFIG_FIPS */
-}
-
-
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-                      const char *label, int server_random_first,
-                      int skip_keyblock, u8 *out, size_t out_len)
-{
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
-       SSL *ssl;
-       if (conn == NULL)
-               return -1;
-       if (server_random_first || skip_keyblock)
-               return openssl_tls_prf(conn, label,
-                                      server_random_first, skip_keyblock,
-                                      out, out_len);
-       ssl = conn->ssl;
-       if (SSL_export_keying_material(ssl, out, out_len, label,
-                                      os_strlen(label), NULL, 0, 0) == 1) {
-               wpa_printf(MSG_DEBUG, "OpenSSL: Using internal PRF");
-               return 0;
-       }
-#endif
-       return openssl_tls_prf(conn, label, server_random_first,
-                              skip_keyblock, out, out_len);
+#else /* OPENSSL_NEED_EAP_FAST_PRF */
+       wpa_printf(MSG_ERROR,
+                  "OpenSSL: EAP-FAST keys cannot be exported in FIPS mode");
+       return -1;
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
 }
 
 
@@ -3370,18 +3536,14 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx,
 
 int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
 {
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
        return conn ? SSL_cache_hit(conn->ssl) : 0;
-#else
-       return conn ? conn->ssl->hit : 0;
-#endif
 }
 
 
 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
                                   u8 *ciphers)
 {
-       char buf[100], *pos, *end;
+       char buf[500], *pos, *end;
        u8 *c;
        int ret;
 
@@ -3409,6 +3571,12 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
                case TLS_CIPHER_ANON_DH_AES128_SHA:
                        suite = "ADH-AES128-SHA";
                        break;
+               case TLS_CIPHER_RSA_DHE_AES256_SHA:
+                       suite = "DHE-RSA-AES256-SHA";
+                       break;
+               case TLS_CIPHER_AES256_SHA:
+                       suite = "AES256-SHA";
+                       break;
                default:
                        wpa_printf(MSG_DEBUG, "TLS: Unsupported "
                                   "cipher selection: %d", *c);
@@ -3424,7 +3592,7 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
 
        wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
 
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
 #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
        if (os_strstr(buf, ":ADH-")) {
                /*
@@ -3717,10 +3885,12 @@ static int ocsp_resp_cb(SSL *s, void *arg)
                wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
                           (conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" :
                           " (OCSP not required)");
+               OCSP_CERTID_free(id);
                OCSP_BASICRESP_free(basic);
                OCSP_RESPONSE_free(rsp);
                return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
        }
+       OCSP_CERTID_free(id);
 
        if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
                tls_show_errors(MSG_INFO, __func__,
@@ -3799,6 +3969,12 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
        if (conn == NULL)
                return -1;
 
+       if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+               wpa_printf(MSG_INFO,
+                          "OpenSSL: ocsp=3 not supported");
+               return -1;
+       }
+
        /*
         * If the engine isn't explicitly configured, and any of the
         * cert/key fields are actually PKCS#11 URIs, then automatically
@@ -3912,6 +4088,11 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
 
        tls_set_conn_flags(conn->ssl, params->flags);
 
+#ifdef OPENSSL_IS_BORINGSSL
+       if (params->flags & TLS_CONN_REQUEST_OCSP) {
+               SSL_enable_ocsp_stapling(conn->ssl);
+       }
+#else /* OPENSSL_IS_BORINGSSL */
 #ifdef HAVE_OCSP
        if (params->flags & TLS_CONN_REQUEST_OCSP) {
                SSL_CTX *ssl_ctx = data->ssl;
@@ -3930,6 +4111,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
                           "OpenSSL: No OCSP support included - allow optional OCSP case to continue");
        }
 #endif /* HAVE_OCSP */
+#endif /* OPENSSL_IS_BORINGSSL */
 
        conn->flags = params->flags;
 
@@ -3997,7 +4179,7 @@ int tls_global_set_params(void *tls_ctx,
  * commented out unless explicitly needed for EAP-FAST in order to be able to
  * build this file with unmodified openssl. */
 
-#ifdef OPENSSL_IS_BORINGSSL
+#if (defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
 static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
                           STACK_OF(SSL_CIPHER) *peer_ciphers,
                           const SSL_CIPHER **cipher, void *arg)
@@ -4010,7 +4192,7 @@ static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
        struct tls_connection *conn = arg;
        int ret;
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
        if (conn == NULL || conn->session_ticket_cb == NULL)
                return 0;
 
@@ -4105,9 +4287,15 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx,
 
 int tls_get_library_version(char *buf, size_t buf_len)
 {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+       return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
+                          OPENSSL_VERSION_TEXT,
+                          OpenSSL_version(OPENSSL_VERSION));
+#else
        return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
                           OPENSSL_VERSION_TEXT,
                           SSLeay_version(SSLEAY_VERSION));
+#endif
 }
 
 
diff --git a/libeap/src/crypto/tls_openssl.h b/libeap/src/crypto/tls_openssl.h
new file mode 100644 (file)
index 0000000..2a62d5c
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * SSL/TLS interface functions for OpenSSL
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TLS_OPENSSL_H
+#define TLS_OPENSSL_H
+
+enum ocsp_result {
+       OCSP_GOOD, OCSP_REVOKED, OCSP_NO_RESPONSE, OCSP_INVALID
+};
+
+enum ocsp_result check_ocsp_resp(SSL_CTX *ssl_ctx, SSL *ssl, X509 *cert,
+                                X509 *issuer, X509 *issuer_issuer);
+
+#endif /* TLS_OPENSSL_H */
diff --git a/libeap/src/crypto/tls_openssl_ocsp.c b/libeap/src/crypto/tls_openssl_ocsp.c
new file mode 100644 (file)
index 0000000..8b37b34
--- /dev/null
@@ -0,0 +1,846 @@
+/*
+ * SSL/TLS interface functions for OpenSSL - BoringSSL OCSP
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/x509v3.h>
+#ifdef OPENSSL_IS_BORINGSSL
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#endif /* OPENSSL_IS_BORINGSSL */
+
+#include "common.h"
+#include "tls_openssl.h"
+
+
+#ifdef OPENSSL_IS_BORINGSSL
+
+static void tls_show_errors(int level, const char *func, const char *txt)
+{
+       unsigned long err;
+
+       wpa_printf(level, "OpenSSL: %s - %s %s",
+                  func, txt, ERR_error_string(ERR_get_error(), NULL));
+
+       while ((err = ERR_get_error())) {
+               wpa_printf(MSG_INFO, "OpenSSL: pending error: %s",
+                          ERR_error_string(err, NULL));
+       }
+}
+
+
+/*
+ * CertID ::= SEQUENCE {
+ *     hashAlgorithm      AlgorithmIdentifier,
+ *     issuerNameHash     OCTET STRING, -- Hash of Issuer's DN
+ *     issuerKeyHash      OCTET STRING, -- Hash of Issuer's public key
+ *     serialNumber       CertificateSerialNumber }
+ */
+typedef struct {
+       X509_ALGOR *hashAlgorithm;
+       ASN1_OCTET_STRING *issuerNameHash;
+       ASN1_OCTET_STRING *issuerKeyHash;
+       ASN1_INTEGER *serialNumber;
+} CertID;
+
+/*
+ * ResponseBytes ::=       SEQUENCE {
+ *     responseType   OBJECT IDENTIFIER,
+ *     response       OCTET STRING }
+ */
+typedef struct {
+       ASN1_OBJECT *responseType;
+       ASN1_OCTET_STRING *response;
+} ResponseBytes;
+
+/*
+ * OCSPResponse ::= SEQUENCE {
+ *    responseStatus         OCSPResponseStatus,
+ *    responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
+ */
+typedef struct {
+       ASN1_ENUMERATED *responseStatus;
+       ResponseBytes *responseBytes;
+} OCSPResponse;
+
+ASN1_SEQUENCE(ResponseBytes) = {
+       ASN1_SIMPLE(ResponseBytes, responseType, ASN1_OBJECT),
+       ASN1_SIMPLE(ResponseBytes, response, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(ResponseBytes);
+
+ASN1_SEQUENCE(OCSPResponse) = {
+       ASN1_SIMPLE(OCSPResponse, responseStatus, ASN1_ENUMERATED),
+       ASN1_EXP_OPT(OCSPResponse, responseBytes, ResponseBytes, 0)
+} ASN1_SEQUENCE_END(OCSPResponse);
+
+IMPLEMENT_ASN1_FUNCTIONS(OCSPResponse);
+
+/*
+ * ResponderID ::= CHOICE {
+ *    byName               [1] Name,
+ *    byKey                [2] KeyHash }
+ */
+typedef struct {
+       int type;
+       union {
+               X509_NAME *byName;
+               ASN1_OCTET_STRING *byKey;
+       } value;
+} ResponderID;
+
+/*
+ * RevokedInfo ::= SEQUENCE {
+ *     revocationTime              GeneralizedTime,
+ *     revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
+ */
+typedef struct {
+       ASN1_GENERALIZEDTIME *revocationTime;
+       ASN1_ENUMERATED *revocationReason;
+} RevokedInfo;
+
+/*
+ * CertStatus ::= CHOICE {
+ *     good        [0]     IMPLICIT NULL,
+ *     revoked     [1]     IMPLICIT RevokedInfo,
+ *     unknown     [2]     IMPLICIT UnknownInfo }
+ */
+typedef struct {
+       int type;
+       union {
+               ASN1_NULL *good;
+               RevokedInfo *revoked;
+               ASN1_NULL *unknown;
+       } value;
+} CertStatus;
+
+/*
+ * SingleResponse ::= SEQUENCE {
+ *    certID                       CertID,
+ *    certStatus                   CertStatus,
+ *    thisUpdate                   GeneralizedTime,
+ *    nextUpdate         [0]       EXPLICIT GeneralizedTime OPTIONAL,
+ *    singleExtensions   [1]       EXPLICIT Extensions OPTIONAL }
+ */
+typedef struct {
+       CertID *certID;
+       CertStatus *certStatus;
+       ASN1_GENERALIZEDTIME *thisUpdate;
+       ASN1_GENERALIZEDTIME *nextUpdate;
+       STACK_OF(X509_EXTENSION) *singleExtensions;
+} SingleResponse;
+
+/*
+ * ResponseData ::= SEQUENCE {
+ *   version              [0] EXPLICIT Version DEFAULT v1,
+ *   responderID              ResponderID,
+ *   producedAt               GeneralizedTime,
+ *   responses                SEQUENCE OF SingleResponse,
+ *   responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
+ */
+typedef struct {
+       ASN1_INTEGER *version;
+       ResponderID *responderID;
+       ASN1_GENERALIZEDTIME *producedAt;
+       STACK_OF(SingleResponse) *responses;
+       STACK_OF(X509_EXTENSION) *responseExtensions;
+} ResponseData;
+
+/*
+ * BasicOCSPResponse       ::= SEQUENCE {
+ *   tbsResponseData      ResponseData,
+ *   signatureAlgorithm   AlgorithmIdentifier,
+ *   signature            BIT STRING,
+ *   certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ */
+typedef struct {
+       ResponseData *tbsResponseData;
+       X509_ALGOR *signatureAlgorithm;
+       ASN1_BIT_STRING *signature;
+       STACK_OF(X509) *certs;
+} BasicOCSPResponse;
+
+ASN1_SEQUENCE(CertID) = {
+       ASN1_SIMPLE(CertID, hashAlgorithm, X509_ALGOR),
+       ASN1_SIMPLE(CertID, issuerNameHash, ASN1_OCTET_STRING),
+       ASN1_SIMPLE(CertID, issuerKeyHash, ASN1_OCTET_STRING),
+       ASN1_SIMPLE(CertID, serialNumber, ASN1_INTEGER)
+} ASN1_SEQUENCE_END(CertID);
+
+ASN1_CHOICE(ResponderID) = {
+       ASN1_EXP(ResponderID, value.byName, X509_NAME, 1),
+       ASN1_EXP(ResponderID, value.byKey, ASN1_OCTET_STRING, 2)
+} ASN1_CHOICE_END(ResponderID);
+
+ASN1_SEQUENCE(RevokedInfo) = {
+       ASN1_SIMPLE(RevokedInfo, revocationTime, ASN1_GENERALIZEDTIME),
+       ASN1_EXP_OPT(RevokedInfo, revocationReason, ASN1_ENUMERATED, 0)
+} ASN1_SEQUENCE_END(RevokedInfo);
+
+ASN1_CHOICE(CertStatus) = {
+       ASN1_IMP(CertStatus, value.good, ASN1_NULL, 0),
+       ASN1_IMP(CertStatus, value.revoked, RevokedInfo, 1),
+       ASN1_IMP(CertStatus, value.unknown, ASN1_NULL, 2)
+} ASN1_CHOICE_END(CertStatus);
+
+ASN1_SEQUENCE(SingleResponse) = {
+       ASN1_SIMPLE(SingleResponse, certID, CertID),
+       ASN1_SIMPLE(SingleResponse, certStatus, CertStatus),
+       ASN1_SIMPLE(SingleResponse, thisUpdate, ASN1_GENERALIZEDTIME),
+       ASN1_EXP_OPT(SingleResponse, nextUpdate, ASN1_GENERALIZEDTIME, 0),
+       ASN1_EXP_SEQUENCE_OF_OPT(SingleResponse, singleExtensions,
+                                X509_EXTENSION, 1)
+} ASN1_SEQUENCE_END(SingleResponse);
+
+ASN1_SEQUENCE(ResponseData) = {
+       ASN1_EXP_OPT(ResponseData, version, ASN1_INTEGER, 0),
+       ASN1_SIMPLE(ResponseData, responderID, ResponderID),
+       ASN1_SIMPLE(ResponseData, producedAt, ASN1_GENERALIZEDTIME),
+       ASN1_SEQUENCE_OF(ResponseData, responses, SingleResponse),
+       ASN1_EXP_SEQUENCE_OF_OPT(ResponseData, responseExtensions,
+                                X509_EXTENSION, 1)
+} ASN1_SEQUENCE_END(ResponseData);
+
+ASN1_SEQUENCE(BasicOCSPResponse) = {
+       ASN1_SIMPLE(BasicOCSPResponse, tbsResponseData, ResponseData),
+       ASN1_SIMPLE(BasicOCSPResponse, signatureAlgorithm, X509_ALGOR),
+       ASN1_SIMPLE(BasicOCSPResponse, signature, ASN1_BIT_STRING),
+       ASN1_EXP_SEQUENCE_OF_OPT(BasicOCSPResponse, certs, X509, 0)
+} ASN1_SEQUENCE_END(BasicOCSPResponse);
+
+IMPLEMENT_ASN1_FUNCTIONS(BasicOCSPResponse);
+
+#define sk_SingleResponse_num(sk) \
+sk_num(CHECKED_CAST(_STACK *, STACK_OF(SingleResponse) *, sk))
+
+#define sk_SingleResponse_value(sk, i) \
+       ((SingleResponse *)                                             \
+        sk_value(CHECKED_CAST(_STACK *, STACK_OF(SingleResponse) *, sk), (i)))
+
+
+static char * mem_bio_to_str(BIO *out)
+{
+       char *txt;
+       size_t rlen;
+       int res;
+
+       rlen = BIO_ctrl_pending(out);
+       txt = os_malloc(rlen + 1);
+       if (!txt) {
+               BIO_free(out);
+               return NULL;
+       }
+
+       res = BIO_read(out, txt, rlen);
+       BIO_free(out);
+       if (res < 0) {
+               os_free(txt);
+               return NULL;
+       }
+
+       txt[res] = '\0';
+       return txt;
+}
+
+
+static char * generalizedtime_str(ASN1_GENERALIZEDTIME *t)
+{
+       BIO *out;
+
+       out = BIO_new(BIO_s_mem());
+       if (!out)
+               return NULL;
+
+       if (!ASN1_GENERALIZEDTIME_print(out, t)) {
+               BIO_free(out);
+               return NULL;
+       }
+
+       return mem_bio_to_str(out);
+}
+
+
+static char * responderid_str(ResponderID *rid)
+{
+       BIO *out;
+
+       out = BIO_new(BIO_s_mem());
+       if (!out)
+               return NULL;
+
+       switch (rid->type) {
+       case 0:
+               X509_NAME_print_ex(out, rid->value.byName, 0, XN_FLAG_ONELINE);
+               break;
+       case 1:
+               i2a_ASN1_STRING(out, rid->value.byKey, V_ASN1_OCTET_STRING);
+               break;
+       default:
+               BIO_free(out);
+               return NULL;
+       }
+
+       return mem_bio_to_str(out);
+}
+
+
+static char * octet_string_str(ASN1_OCTET_STRING *o)
+{
+       BIO *out;
+
+       out = BIO_new(BIO_s_mem());
+       if (!out)
+               return NULL;
+
+       i2a_ASN1_STRING(out, o, V_ASN1_OCTET_STRING);
+       return mem_bio_to_str(out);
+}
+
+
+static char * integer_str(ASN1_INTEGER *i)
+{
+       BIO *out;
+
+       out = BIO_new(BIO_s_mem());
+       if (!out)
+               return NULL;
+
+       i2a_ASN1_INTEGER(out, i);
+       return mem_bio_to_str(out);
+}
+
+
+static char * algor_str(X509_ALGOR *alg)
+{
+       BIO *out;
+
+       out = BIO_new(BIO_s_mem());
+       if (!out)
+               return NULL;
+
+       i2a_ASN1_OBJECT(out, alg->algorithm);
+       return mem_bio_to_str(out);
+}
+
+
+static char * extensions_str(const char *title, STACK_OF(X509_EXTENSION) *ext)
+{
+       BIO *out;
+
+       if (!ext)
+               return NULL;
+
+       out = BIO_new(BIO_s_mem());
+       if (!out)
+               return NULL;
+
+       if (!X509V3_extensions_print(out, title, ext, 0, 0)) {
+               BIO_free(out);
+               return NULL;
+       }
+       return mem_bio_to_str(out);
+}
+
+
+static int ocsp_resp_valid(ASN1_GENERALIZEDTIME *thisupd,
+                          ASN1_GENERALIZEDTIME *nextupd)
+{
+       time_t now, tmp;
+
+       if (!ASN1_GENERALIZEDTIME_check(thisupd)) {
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: Invalid OCSP response thisUpdate");
+               return 0;
+       }
+
+       time(&now);
+       tmp = now + 5 * 60; /* allow five minute clock difference */
+       if (X509_cmp_time(thisupd, &tmp) > 0) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response not yet valid");
+               return 0;
+       }
+
+       if (!nextupd)
+               return 1; /* OK - no limit on response age */
+
+       if (!ASN1_GENERALIZEDTIME_check(nextupd)) {
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: Invalid OCSP response nextUpdate");
+               return 0;
+       }
+
+       tmp = now - 5 * 60; /* allow five minute clock difference */
+       if (X509_cmp_time(nextupd, &tmp) < 0) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response expired");
+               return 0;
+       }
+
+       if (ASN1_STRING_cmp(nextupd, thisupd) < 0) {
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: OCSP response nextUpdate before thisUpdate");
+               return 0;
+       }
+
+       /* Both thisUpdate and nextUpdate are valid */
+       return -1;
+}
+
+
+static int issuer_match(X509 *cert, X509 *issuer, CertID *certid)
+{
+       X509_NAME *iname;
+       ASN1_BIT_STRING *ikey;
+       const EVP_MD *dgst;
+       unsigned int len;
+       unsigned char md[EVP_MAX_MD_SIZE];
+       ASN1_OCTET_STRING *hash;
+       char *txt;
+
+       dgst = EVP_get_digestbyobj(certid->hashAlgorithm->algorithm);
+       if (!dgst) {
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: Could not find matching hash algorithm for OCSP");
+               return -1;
+       }
+
+       iname = X509_get_issuer_name(cert);
+       if (!X509_NAME_digest(iname, dgst, md, &len))
+               return -1;
+       hash = ASN1_OCTET_STRING_new();
+       if (!hash)
+               return -1;
+       if (!ASN1_OCTET_STRING_set(hash, md, len)) {
+               ASN1_OCTET_STRING_free(hash);
+               return -1;
+       }
+
+       txt = octet_string_str(hash);
+       if (txt) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: calculated issuerNameHash: %s",
+                          txt);
+               os_free(txt);
+       }
+
+       if (ASN1_OCTET_STRING_cmp(certid->issuerNameHash, hash)) {
+               ASN1_OCTET_STRING_free(hash);
+               return -1;
+       }
+
+       ikey = X509_get0_pubkey_bitstr(issuer);
+       if (!ikey ||
+           !EVP_Digest(ikey->data, ikey->length, md, &len, dgst, NULL) ||
+           !ASN1_OCTET_STRING_set(hash, md, len)) {
+               ASN1_OCTET_STRING_free(hash);
+               return -1;
+       }
+
+       txt = octet_string_str(hash);
+       if (txt) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: calculated issuerKeyHash: %s",
+                          txt);
+               os_free(txt);
+       }
+
+       if (ASN1_OCTET_STRING_cmp(certid->issuerKeyHash, hash)) {
+               ASN1_OCTET_STRING_free(hash);
+               return -1;
+       }
+
+       ASN1_OCTET_STRING_free(hash);
+       return 0;
+}
+
+
+static X509 * ocsp_find_signer(STACK_OF(X509) *certs, ResponderID *rid)
+{
+       unsigned int i;
+       unsigned char hash[SHA_DIGEST_LENGTH];
+
+       if (rid->type == 0) {
+               /* byName */
+               return X509_find_by_subject(certs, rid->value.byName);
+       }
+
+       /* byKey */
+       if (rid->value.byKey->length != SHA_DIGEST_LENGTH)
+               return NULL;
+       for (i = 0; i < sk_X509_num(certs); i++) {
+               X509 *x = sk_X509_value(certs, i);
+
+               X509_pubkey_digest(x, EVP_sha1(), hash, NULL);
+               if (os_memcmp(rid->value.byKey->data, hash,
+                             SHA_DIGEST_LENGTH) == 0)
+                       return x;
+       }
+
+       return NULL;
+}
+
+
+enum ocsp_result check_ocsp_resp(SSL_CTX *ssl_ctx, SSL *ssl, X509 *cert,
+                                X509 *issuer, X509 *issuer_issuer)
+{
+       const uint8_t *resp_data;
+       size_t resp_len;
+       OCSPResponse *resp;
+       int status;
+       ResponseBytes *bytes;
+       const u8 *basic_data;
+       size_t basic_len;
+       BasicOCSPResponse *basic;
+       ResponseData *rd;
+       char *txt;
+       int i, num;
+       unsigned int j, num_resp;
+       SingleResponse *matching_resp = NULL, *cmp_sresp;
+       enum ocsp_result result = OCSP_INVALID;
+       X509_STORE *store;
+       STACK_OF(X509) *untrusted = NULL, *certs = NULL, *chain = NULL;
+       X509_STORE_CTX ctx;
+       X509 *signer, *tmp_cert;
+       int signer_trusted = 0;
+       EVP_PKEY *skey;
+       int ret;
+       char buf[256];
+
+       txt = integer_str(X509_get_serialNumber(cert));
+       if (txt) {
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: Searching OCSP response for peer certificate serialNumber: %s", txt);
+               os_free(txt);
+       }
+
+       SSL_get0_ocsp_response(ssl, &resp_data, &resp_len);
+       if (resp_data == NULL || resp_len == 0) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
+               return OCSP_NO_RESPONSE;
+       }
+
+       wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", resp_data, resp_len);
+
+       resp = d2i_OCSPResponse(NULL, &resp_data, resp_len);
+       if (!resp) {
+               wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSPResponse");
+               return OCSP_INVALID;
+       }
+
+       status = ASN1_ENUMERATED_get(resp->responseStatus);
+       if (status != 0) {
+               wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d",
+                          status);
+               return OCSP_INVALID;
+       }
+
+       bytes = resp->responseBytes;
+
+       if (!bytes ||
+           OBJ_obj2nid(bytes->responseType) != NID_id_pkix_OCSP_basic) {
+               wpa_printf(MSG_INFO,
+                          "OpenSSL: Could not find BasicOCSPResponse");
+               return OCSP_INVALID;
+       }
+
+       basic_data = ASN1_STRING_data(bytes->response);
+       basic_len = ASN1_STRING_length(bytes->response);
+       wpa_hexdump(MSG_DEBUG, "OpenSSL: BasicOCSPResponse",
+                   basic_data, basic_len);
+
+       basic = d2i_BasicOCSPResponse(NULL, &basic_data, basic_len);
+       if (!basic) {
+               wpa_printf(MSG_INFO,
+                          "OpenSSL: Could not parse BasicOCSPResponse");
+               OCSPResponse_free(resp);
+               return OCSP_INVALID;
+       }
+
+       rd = basic->tbsResponseData;
+
+       if (basic->certs) {
+               untrusted = sk_X509_dup(basic->certs);
+               if (!untrusted)
+                       goto fail;
+
+               num = sk_X509_num(basic->certs);
+               for (i = 0; i < num; i++) {
+                       X509 *extra_cert;
+
+                       extra_cert = sk_X509_value(basic->certs, i);
+                       X509_NAME_oneline(X509_get_subject_name(extra_cert),
+                                         buf, sizeof(buf));
+                       wpa_printf(MSG_DEBUG,
+                                  "OpenSSL: BasicOCSPResponse cert %s", buf);
+
+                       if (!sk_X509_push(untrusted, extra_cert)) {
+                               wpa_printf(MSG_DEBUG,
+                                          "OpenSSL: Could not add certificate to the untrusted stack");
+                       }
+               }
+       }
+
+       store = SSL_CTX_get_cert_store(ssl_ctx);
+       if (issuer) {
+               if (X509_STORE_add_cert(store, issuer) != 1) {
+                       tls_show_errors(MSG_INFO, __func__,
+                                       "OpenSSL: Could not add issuer to certificate store");
+               }
+               certs = sk_X509_new_null();
+               if (certs) {
+                       tmp_cert = X509_dup(issuer);
+                       if (tmp_cert && !sk_X509_push(certs, tmp_cert)) {
+                               tls_show_errors(
+                                       MSG_INFO, __func__,
+                                       "OpenSSL: Could not add issuer to OCSP responder trust store");
+                               X509_free(tmp_cert);
+                               sk_X509_free(certs);
+                               certs = NULL;
+                       }
+                       if (certs && issuer_issuer) {
+                               tmp_cert = X509_dup(issuer_issuer);
+                               if (tmp_cert &&
+                                   !sk_X509_push(certs, tmp_cert)) {
+                                       tls_show_errors(
+                                               MSG_INFO, __func__,
+                                               "OpenSSL: Could not add issuer's issuer to OCSP responder trust store");
+                                       X509_free(tmp_cert);
+                               }
+                       }
+               }
+       }
+
+       signer = ocsp_find_signer(certs, rd->responderID);
+       if (!signer)
+               signer = ocsp_find_signer(untrusted, rd->responderID);
+       else
+               signer_trusted = 1;
+       if (!signer) {
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: Could not find OCSP signer certificate");
+               goto fail;
+       }
+
+       skey = X509_get_pubkey(signer);
+       if (!skey) {
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: Could not get OCSP signer public key");
+               goto fail;
+       }
+       if (ASN1_item_verify(ASN1_ITEM_rptr(ResponseData),
+                            basic->signatureAlgorithm, basic->signature,
+                            basic->tbsResponseData, skey) <= 0) {
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: BasicOCSPResponse signature is invalid");
+               goto fail;
+       }
+
+       X509_NAME_oneline(X509_get_subject_name(signer), buf, sizeof(buf));
+       wpa_printf(MSG_DEBUG,
+                  "OpenSSL: Found OCSP signer certificate %s and verified BasicOCSPResponse signature",
+                  buf);
+
+       if (!X509_STORE_CTX_init(&ctx, store, signer, untrusted))
+               goto fail;
+       X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_OCSP_HELPER);
+       ret = X509_verify_cert(&ctx);
+       chain = X509_STORE_CTX_get1_chain(&ctx);
+       X509_STORE_CTX_cleanup(&ctx);
+       if (ret <= 0) {
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: Could not validate OCSP signer certificate");
+               goto fail;
+       }
+
+       if (!chain || sk_X509_num(chain) <= 0) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP signer chain found");
+               goto fail;
+       }
+
+       if (!signer_trusted) {
+               X509_check_purpose(signer, -1, 0);
+               if ((signer->ex_flags & EXFLAG_XKUSAGE) &&
+                   (signer->ex_xkusage & XKU_OCSP_SIGN)) {
+                       wpa_printf(MSG_DEBUG,
+                                  "OpenSSL: OCSP signer certificate delegation OK");
+               } else {
+                       tmp_cert = sk_X509_value(chain, sk_X509_num(chain) - 1);
+                       if (X509_check_trust(tmp_cert, NID_OCSP_sign, 0) !=
+                           X509_TRUST_TRUSTED) {
+                               wpa_printf(MSG_DEBUG,
+                                          "OpenSSL: OCSP signer certificate not trusted");
+                               result = OCSP_NO_RESPONSE;
+                               goto fail;
+                       }
+               }
+       }
+
+       wpa_printf(MSG_DEBUG, "OpenSSL: OCSP version: %lu",
+                  ASN1_INTEGER_get(rd->version));
+
+       txt = responderid_str(rd->responderID);
+       if (txt) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP responderID: %s",
+                          txt);
+               os_free(txt);
+       }
+
+       txt = generalizedtime_str(rd->producedAt);
+       if (txt) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP producedAt: %s",
+                          txt);
+               os_free(txt);
+       }
+
+       num_resp = sk_SingleResponse_num(rd->responses);
+       if (num_resp == 0) {
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: No OCSP SingleResponse within BasicOCSPResponse");
+               result = OCSP_NO_RESPONSE;
+               goto fail;
+       }
+       cmp_sresp = sk_SingleResponse_value(rd->responses, 0);
+       for (j = 0; j < num_resp; j++) {
+               SingleResponse *sresp;
+               CertID *cid1, *cid2;
+
+               sresp = sk_SingleResponse_value(rd->responses, j);
+               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP SingleResponse %u/%u",
+                          j + 1, num_resp);
+
+               txt = algor_str(sresp->certID->hashAlgorithm);
+               if (txt) {
+                       wpa_printf(MSG_DEBUG,
+                                  "OpenSSL: certID hashAlgorithm: %s", txt);
+                       os_free(txt);
+               }
+
+               txt = octet_string_str(sresp->certID->issuerNameHash);
+               if (txt) {
+                       wpa_printf(MSG_DEBUG,
+                                  "OpenSSL: certID issuerNameHash: %s", txt);
+                       os_free(txt);
+               }
+
+               txt = octet_string_str(sresp->certID->issuerKeyHash);
+               if (txt) {
+                       wpa_printf(MSG_DEBUG,
+                                  "OpenSSL: certID issuerKeyHash: %s", txt);
+                       os_free(txt);
+               }
+
+               txt = integer_str(sresp->certID->serialNumber);
+               if (txt) {
+                       wpa_printf(MSG_DEBUG,
+                                  "OpenSSL: certID serialNumber: %s", txt);
+                       os_free(txt);
+               }
+
+               switch (sresp->certStatus->type) {
+               case 0:
+                       wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: good");
+                       break;
+               case 1:
+                       wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: revoked");
+                       break;
+               default:
+                       wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: unknown");
+                       break;
+               }
+
+               txt = generalizedtime_str(sresp->thisUpdate);
+               if (txt) {
+                       wpa_printf(MSG_DEBUG, "OpenSSL: thisUpdate: %s", txt);
+                       os_free(txt);
+               }
+
+               if (sresp->nextUpdate) {
+                       txt = generalizedtime_str(sresp->nextUpdate);
+                       if (txt) {
+                               wpa_printf(MSG_DEBUG, "OpenSSL: nextUpdate: %s",
+                                          txt);
+                               os_free(txt);
+                       }
+               }
+
+               txt = extensions_str("singleExtensions",
+                                    sresp->singleExtensions);
+               if (txt) {
+                       wpa_printf(MSG_DEBUG, "OpenSSL: %s", txt);
+                       os_free(txt);
+               }
+
+               cid1 = cmp_sresp->certID;
+               cid2 = sresp->certID;
+               if (j > 0 &&
+                   (OBJ_cmp(cid1->hashAlgorithm->algorithm,
+                            cid2->hashAlgorithm->algorithm) != 0 ||
+                    ASN1_OCTET_STRING_cmp(cid1->issuerNameHash,
+                                          cid2->issuerNameHash) != 0 ||
+                    ASN1_OCTET_STRING_cmp(cid1->issuerKeyHash,
+                                          cid2->issuerKeyHash) != 0)) {
+                       wpa_printf(MSG_DEBUG,
+                                  "OpenSSL: Different OCSP response issuer information between SingleResponse values within BasicOCSPResponse");
+                       goto fail;
+               }
+
+               if (!matching_resp && issuer &&
+                   ASN1_INTEGER_cmp(sresp->certID->serialNumber,
+                                    X509_get_serialNumber(cert)) == 0 &&
+                   issuer_match(cert, issuer, sresp->certID) == 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "OpenSSL: This response matches peer certificate");
+                       matching_resp = sresp;
+               }
+       }
+
+       txt = extensions_str("responseExtensions", rd->responseExtensions);
+       if (txt) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: %s", txt);
+               os_free(txt);
+       }
+
+       if (!matching_resp) {
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: Could not find OCSP response that matches the peer certificate");
+               result = OCSP_NO_RESPONSE;
+               goto fail;
+       }
+
+       if (!ocsp_resp_valid(matching_resp->thisUpdate,
+                            matching_resp->nextUpdate)) {
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: OCSP response not valid at this time");
+               goto fail;
+       }
+
+       if (matching_resp->certStatus->type == 1) {
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: OCSP response indicated that the peer certificate has been revoked");
+               result = OCSP_REVOKED;
+               goto fail;
+       }
+
+       if (matching_resp->certStatus->type != 0) {
+               wpa_printf(MSG_DEBUG,
+                          "OpenSSL: OCSP response did not indicate good status");
+               result = OCSP_NO_RESPONSE;
+               goto fail;
+       }
+
+       /* OCSP response indicated the certificate is good. */
+       result = OCSP_GOOD;
+fail:
+       sk_X509_pop_free(chain, X509_free);
+       sk_X509_free(untrusted);
+       sk_X509_pop_free(certs, X509_free);
+       BasicOCSPResponse_free(basic);
+       OCSPResponse_free(resp);
+
+       return result;
+}
+
+#endif /* OPENSSL_IS_BORINGSSL */
index 3cdab5a..a449cc9 100644 (file)
 #define HOSTAPD_CHAN_INDOOR_ONLY 0x00010000
 #define HOSTAPD_CHAN_GO_CONCURRENT 0x00020000
 
+#define HOSTAPD_CHAN_VHT_10_150 0x00100000
+#define HOSTAPD_CHAN_VHT_30_130 0x00200000
+#define HOSTAPD_CHAN_VHT_50_110 0x00400000
+#define HOSTAPD_CHAN_VHT_70_90  0x00800000
+#define HOSTAPD_CHAN_VHT_90_70  0x01000000
+#define HOSTAPD_CHAN_VHT_110_50 0x02000000
+#define HOSTAPD_CHAN_VHT_130_30 0x04000000
+#define HOSTAPD_CHAN_VHT_150_10 0x08000000
+
+/* Filter gratuitous ARP */
+#define WPA_DATA_FRAME_FILTER_FLAG_ARP BIT(0)
+/* Filter unsolicited Neighbor Advertisement */
+#define WPA_DATA_FRAME_FILTER_FLAG_NA BIT(1)
+/* Filter unicast IP packets encrypted using the GTK */
+#define WPA_DATA_FRAME_FILTER_FLAG_GTK BIT(2)
+
 /**
  * enum reg_change_initiator - Regulatory change initiator
  */
@@ -284,6 +300,18 @@ struct wpa_interface_info {
 #define WPAS_MAX_SCAN_SSIDS 16
 
 /**
+ * struct wpa_driver_scan_ssid - SSIDs to scan for
+ * @ssid - specific SSID to scan for (ProbeReq)
+ *     %NULL or zero-length SSID is used to indicate active scan
+ *     with wildcard SSID.
+ * @ssid_len - Length of the SSID in octets
+ */
+struct wpa_driver_scan_ssid {
+       const u8 *ssid;
+       size_t ssid_len;
+};
+
+/**
  * struct wpa_driver_scan_params - Scan parameters
  * Data for struct wpa_driver_ops::scan2().
  */
@@ -291,18 +319,7 @@ struct wpa_driver_scan_params {
        /**
         * ssids - SSIDs to scan for
         */
-       struct wpa_driver_scan_ssid {
-               /**
-                * ssid - specific SSID to scan for (ProbeReq)
-                * %NULL or zero-length SSID is used to indicate active scan
-                * with wildcard SSID.
-                */
-               const u8 *ssid;
-               /**
-                * ssid_len: Length of the SSID in octets
-                */
-               size_t ssid_len;
-       } ssids[WPAS_MAX_SCAN_SSIDS];
+       struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS];
 
        /**
         * num_ssids - Number of entries in ssids array
@@ -407,6 +424,37 @@ struct wpa_driver_scan_params {
         */
        const u8 *mac_addr_mask;
 
+       /**
+        * sched_scan_plans - Scan plans for scheduled scan
+        *
+        * Each scan plan consists of the number of iterations to scan and the
+        * interval between scans. When a scan plan finishes (i.e., it was run
+        * for the specified number of iterations), the next scan plan is
+        * executed. The scan plans are executed in the order they appear in
+        * the array (lower index first). The last scan plan will run infinitely
+        * (until requested to stop), thus must not specify the number of
+        * iterations. All other scan plans must specify the number of
+        * iterations.
+        */
+       struct sched_scan_plan {
+                u32 interval; /* In seconds */
+                u32 iterations; /* Zero to run infinitely */
+        } *sched_scan_plans;
+
+       /**
+        * sched_scan_plans_num - Number of scan plans in sched_scan_plans array
+        */
+        unsigned int sched_scan_plans_num;
+
+       /**
+        * bssid - Specific BSSID to scan for
+        *
+        * This optional parameter can be used to replace the default wildcard
+        * BSSID with a specific BSSID to scan for if results are needed from
+        * only a single BSS.
+        */
+       const u8 *bssid;
+
        /*
         * NOTE: Whenever adding new parameters here, please make sure
         * wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -828,6 +876,12 @@ struct wpa_driver_associate_params {
         * RRM (Radio Resource Measurements)
         */
        int rrm_used;
+
+       /**
+        * pbss - If set, connect to a PCP in a PBSS. Otherwise, connect to an
+        * AP as usual. Valid for DMG network only.
+        */
+       int pbss;
 };
 
 enum hide_ssid {
@@ -1055,16 +1109,28 @@ struct wpa_driver_ap_params {
         * reenable - Whether this is to re-enable beaconing
         */
        int reenable;
+
+       /**
+        * pbss - Whether to start a PCP (in PBSS) instead of an AP in
+        * infrastructure BSS. Valid only for DMG network.
+        */
+       int pbss;
 };
 
 struct wpa_driver_mesh_bss_params {
-#define WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS  0x00000001
+#define WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS          0x00000001
+#define WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT    0x00000002
+#define WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS       0x00000004
+#define WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE           0x00000008
        /*
         * TODO: Other mesh configuration parameters would go here.
         * See NL80211_MESHCONF_* for all the mesh config parameters.
         */
        unsigned int flags;
+       int auto_plinks;
        int peer_link_timeout;
+       int max_peer_links;
+       u16 ht_opmode;
 };
 
 struct wpa_driver_mesh_join_params {
@@ -1075,7 +1141,7 @@ struct wpa_driver_mesh_join_params {
        int ie_len;
        struct hostapd_freq_params freq;
        int beacon_int;
-       int max_peer_links;
+       int dtim_period;
        struct wpa_driver_mesh_bss_params conf;
 #define WPA_DRIVER_MESH_FLAG_USER_MPM  0x00000001
 #define WPA_DRIVER_MESH_FLAG_DRIVER_MPM        0x00000002
@@ -1214,8 +1280,17 @@ struct wpa_driver_capa {
 #define WPA_DRIVER_FLAGS_VHT_IBSS              0x0000002000000000ULL
 /** Driver supports automatic band selection */
 #define WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY   0x0000004000000000ULL
+/** Driver supports simultaneous off-channel operations */
+#define WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS       0x0000008000000000ULL
+/** Driver supports full AP client state */
+#define WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE  0x0000010000000000ULL
+/** Driver supports P2P Listen offload */
+#define WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD     0x0000020000000000ULL
        u64 flags;
 
+#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
+       (drv_flags & WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE)
+
 #define WPA_DRIVER_SMPS_MODE_STATIC                    0x00000001
 #define WPA_DRIVER_SMPS_MODE_DYNAMIC                   0x00000002
        unsigned int smps_modes;
@@ -1231,6 +1306,15 @@ struct wpa_driver_capa {
        /** Maximum number of supported active probe SSIDs for sched_scan */
        int max_sched_scan_ssids;
 
+       /** Maximum number of supported scan plans for scheduled scan */
+       unsigned int max_sched_scan_plans;
+
+       /** Maximum interval in a scan plan. In seconds */
+       u32 max_sched_scan_plan_interval;
+
+       /** Maximum number of iterations in a single scan plan */
+       u32 max_sched_scan_plan_iterations;
+
        /** Whether sched_scan (offloaded scanning) is supported */
        int sched_scan_supported;
 
@@ -1296,6 +1380,12 @@ struct wpa_driver_capa {
  * offset, namely the 6th byte in the Action frame body.
  */
 #define WPA_DRIVER_FLAGS_TX_POWER_INSERTION            0x00000008
+/**
+ * Driver supports RRM. With this support, the driver will accept to use RRM in
+ * (Re)Association Request frames, without supporting quiet period.
+ */
+#define WPA_DRIVER_FLAGS_SUPPORT_RRM                   0x00000010
+
        u32 rrm_flags;
 
        /* Driver concurrency capabilities */
@@ -1304,13 +1394,18 @@ struct wpa_driver_capa {
        unsigned int max_conc_chan_2_4;
        /* Maximum number of concurrent channels on 5 GHz */
        unsigned int max_conc_chan_5_0;
+
+       /* Maximum number of supported CSA counters */
+       u16 max_csa_counters;
 };
 
 
 struct hostapd_data;
 
 struct hostap_sta_driver_data {
-       unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes;
+       unsigned long rx_packets, tx_packets;
+       unsigned long long rx_bytes, tx_bytes;
+       int bytes_64bit; /* whether 64-bit byte counters are supported */
        unsigned long current_tx_rate;
        unsigned long inactive_msec;
        unsigned long flags;
@@ -1336,6 +1431,7 @@ struct hostapd_sta_add_params {
        u32 flags_mask; /* unset bits in flags */
 #ifdef CONFIG_MESH
        enum mesh_plink_state plink_state;
+       u16 peer_aid;
 #endif /* CONFIG_MESH */
        int set; /* Set STA parameters instead of add */
        u8 qosinfo;
@@ -1345,6 +1441,7 @@ struct hostapd_sta_add_params {
        size_t supp_channels_len;
        const u8 *supp_oper_classes;
        size_t supp_oper_classes_len;
+       int support_p2p_ps;
 };
 
 struct mac_address {
@@ -1450,6 +1547,7 @@ struct wpa_bss_params {
 #define WPA_STA_MFP BIT(3)
 #define WPA_STA_TDLS_PEER BIT(4)
 #define WPA_STA_AUTHENTICATED BIT(5)
+#define WPA_STA_ASSOCIATED BIT(6)
 
 enum tdls_oper {
        TDLS_DISCOVERY_REQ,
@@ -1554,8 +1652,8 @@ struct csa_settings {
        struct beacon_data beacon_csa;
        struct beacon_data beacon_after;
 
-       u16 counter_offset_beacon;
-       u16 counter_offset_presp;
+       u16 counter_offset_beacon[2];
+       u16 counter_offset_presp[2];
 };
 
 /* TDLS peer capabilities for send_tdls_mgmt() */
@@ -1883,6 +1981,14 @@ struct wpa_driver_ops {
        void (*poll)(void *priv);
 
        /**
+        * get_ifindex - Get interface index
+        * @priv: private driver interface data
+        *
+        * Returns: Interface index
+        */
+       unsigned int (*get_ifindex)(void *priv);
+
+       /**
         * get_ifname - Get interface name
         * @priv: private driver interface data
         *
@@ -1960,10 +2066,13 @@ struct wpa_driver_ops {
         * @noack: Do not wait for this frame to be acked (disable retries)
         * @freq: Frequency (in MHz) to send the frame on, or 0 to let the
         * driver decide
+        * @csa_offs: Array of CSA offsets or %NULL
+        * @csa_offs_len: Number of elements in csa_offs
         * Returns: 0 on success, -1 on failure
         */
        int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
-                        int noack, unsigned int freq);
+                        int noack, unsigned int freq, const u16 *csa_offs,
+                        size_t csa_offs_len);
 
        /**
         * update_ft_ies - Update FT (IEEE 802.11r) IEs
@@ -2013,6 +2122,7 @@ struct wpa_driver_ops {
 
        /**
         * global_init - Global driver initialization
+        * @ctx: wpa_global pointer
         * Returns: Pointer to private data (global), %NULL on failure
         *
         * This optional function is called to initialize the driver wrapper
@@ -2022,7 +2132,7 @@ struct wpa_driver_ops {
         * use init2() function instead of init() to get the pointer to global
         * data available to per-interface initializer.
         */
-       void * (*global_init)(void);
+       void * (*global_init)(void *ctx);
 
        /**
         * global_deinit - Global driver deinitialization
@@ -2308,12 +2418,17 @@ struct wpa_driver_ops {
         * @params: Station parameters
         * Returns: 0 on success, -1 on failure
         *
-        * This function is used to add a station entry to the driver once the
-        * station has completed association. This is only used if the driver
+        * This function is used to add or set (params->set 1) a station
+        * entry in the driver. Adding STA entries is used only if the driver
         * does not take care of association processing.
         *
-        * With TDLS, this function is also used to add or set (params->set 1)
-        * TDLS peer entries.
+        * With drivers that don't support full AP client state, this function
+        * is used to add a station entry to the driver once the station has
+        * completed association.
+        *
+        * With TDLS, this function is used to add or set (params->set 1)
+        * TDLS peer entries (even with drivers that do not support full AP
+        * client state).
         */
        int (*sta_add)(void *priv, struct hostapd_sta_add_params *params);
 
@@ -2399,12 +2514,13 @@ struct wpa_driver_ops {
         *      change interface address)
         * @bridge: Bridge interface to use or %NULL if no bridge configured
         * @use_existing: Whether to allow existing interface to be used
+        * @setup_ap: Whether to setup AP for %WPA_IF_AP_BSS interfaces
         * Returns: 0 on success, -1 on failure
         */
        int (*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);
+                     const char *bridge, int use_existing, int setup_ap);
 
        /**
         * if_remove - Remove a virtual interface
@@ -2986,7 +3102,6 @@ struct wpa_driver_ops {
         * sched_scan - Request the driver to initiate scheduled scan
         * @priv: Private driver interface data
         * @params: Scan parameters
-        * @interval: Interval between scan cycles in milliseconds
         * Returns: 0 on success, -1 on failure
         *
         * This operation should be used for scheduled scan offload to
@@ -2997,8 +3112,7 @@ struct wpa_driver_ops {
         * and if not provided or if it returns -1, we fall back to
         * normal host-scheduled scans.
         */
-       int (*sched_scan)(void *priv, struct wpa_driver_scan_params *params,
-                         u32 interval);
+       int (*sched_scan)(void *priv, struct wpa_driver_scan_params *params);
 
        /**
         * stop_sched_scan - Request the driver to stop a scheduled scan
@@ -3203,11 +3317,9 @@ struct wpa_driver_ops {
         * set_current_cipher_suite - Set current cipher suite
         * @priv: Private driver interface data
         * @cs: EUI64 identifier
-        * @cs_len: Length of the cs buffer in octets
         * Returns: 0 on success, -1 on failure (or if not supported)
         */
-       int (*set_current_cipher_suite)(void *priv, const u8 *cs,
-                                       size_t cs_len);
+       int (*set_current_cipher_suite)(void *priv, u64 cs);
 
        /**
         * enable_controlled_port - Set controlled port status
@@ -3439,6 +3551,78 @@ struct wpa_driver_ops {
         * on. Local device is assuming P2P Client role.
         */
        int (*set_prob_oper_freq)(void *priv, unsigned int freq);
+
+       /**
+        * abort_scan - Request the driver to abort an ongoing scan
+        * @priv: Private driver interface data
+        * Returns 0 on success, -1 on failure
+        */
+       int (*abort_scan)(void *priv);
+
+       /**
+        * configure_data_frame_filters - Request to configure frame filters
+        * @priv: Private driver interface data
+        * @filter_flags: The type of frames to filter (bitfield of
+        * WPA_DATA_FRAME_FILTER_FLAG_*)
+        * Returns: 0 on success or -1 on failure
+        */
+       int (*configure_data_frame_filters)(void *priv, u32 filter_flags);
+
+       /**
+        * get_ext_capab - Get extended capabilities for the specified interface
+        * @priv: Private driver interface data
+        * @type: Interface type for which to get extended capabilities
+        * @ext_capab: Extended capabilities fetched
+        * @ext_capab_mask: Extended capabilities mask
+        * @ext_capab_len: Length of the extended capabilities
+        * Returns: 0 on success or -1 on failure
+        */
+       int (*get_ext_capab)(void *priv, enum wpa_driver_if_type type,
+                            const u8 **ext_capab, const u8 **ext_capab_mask,
+                            unsigned int *ext_capab_len);
+
+       /**
+        * p2p_lo_start - Start offloading P2P listen to device
+        * @priv: Private driver interface data
+        * @freq: Listening frequency (MHz) for P2P listen
+        * @period: Length of the listen operation in milliseconds
+        * @interval: Interval for running the listen operation in milliseconds
+        * @count: Number of times to run the listen operation
+        * @device_types: Device primary and secondary types
+        * @dev_types_len: Number of bytes for device_types
+        * @ies: P2P IE and WSC IE for Probe Response frames
+        * @ies_len: Length of ies in bytes
+        * Returns: 0 on success or -1 on failure
+        */
+       int (*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);
+
+       /**
+        * p2p_lo_stop - Stop P2P listen offload
+        * @priv: Private driver interface data
+        * Returns: 0 on success or -1 on failure
+        */
+       int (*p2p_lo_stop)(void *priv);
+
+       /**
+        * set_default_scan_ies - Set default scan IEs
+        * @priv: Private driver interface data
+        * @ies: Scan default IEs buffer
+        * @ies_len: Length of IEs in bytes
+        * Returns: 0 on success or -1 on failure
+        *
+        * The driver can use these by default when there are no scan IEs coming
+        * in the subsequent scan requests. Also in case of one or more of IEs
+        * given in set_default_scan_ies() are missing in the subsequent scan
+        * request, the driver should merge the missing scan IEs in the scan
+        * request from the IEs set by set_default_scan_ies() in the Probe
+        * Request frames sent.
+        */
+       int (*set_default_scan_ies)(void *priv, const u8 *ies, size_t ies_len);
+
 };
 
 
@@ -3923,6 +4107,11 @@ enum wpa_event_type {
         * on a DFS frequency by a driver that supports DFS Offload.
         */
        EVENT_DFS_CAC_STARTED,
+
+       /**
+        * EVENT_P2P_LO_STOP - Notify that P2P listen offload is stopped
+        */
+       EVENT_P2P_LO_STOP,
 };
 
 
@@ -4098,6 +4287,12 @@ union wpa_event_data {
                 * ptk_kek_len - The length of ptk_kek
                 */
                size_t ptk_kek_len;
+
+               /**
+                * subnet_status - The subnet status:
+                * 0 = unknown, 1 = unchanged, 2 = changed
+                */
+               u8 subnet_status;
        } assoc_info;
 
        /**
@@ -4174,6 +4369,7 @@ union wpa_event_data {
         * struct interface_status - Data for EVENT_INTERFACE_STATUS
         */
        struct interface_status {
+               unsigned int ifindex;
                char ifname[100];
                enum {
                        EVENT_INTERFACE_ADDED, EVENT_INTERFACE_REMOVED
@@ -4301,6 +4497,12 @@ union wpa_event_data {
                 * status_code - Status Code from (Re)association Response
                 */
                u16 status_code;
+
+               /**
+                * timed_out - Whether failure is due to timeout (etc.) rather
+                * than explicit rejection response from the AP.
+                */
+               int timed_out;
        } assoc_reject;
 
        struct timeout_event {
@@ -4381,6 +4583,9 @@ union wpa_event_data {
         * @ssids: Scanned SSIDs (%NULL or zero-length SSID indicates wildcard
         *      SSID)
         * @num_ssids: Number of entries in ssids array
+        * @external_scan: Whether the scan info is for an external scan
+        * @nl_scan_event: 1 if the source of this scan event is a normal scan,
+        *      0 if the source of the scan event is a vendor scan
         */
        struct scan_info {
                int aborted;
@@ -4388,6 +4593,8 @@ union wpa_event_data {
                size_t num_freqs;
                struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS];
                size_t num_ssids;
+               int external_scan;
+               int nl_scan_event;
        } scan_info;
 
        /**
@@ -4630,6 +4837,27 @@ union wpa_event_data {
                u16 ch_width;
                enum hostapd_hw_mode hw_mode;
        } acs_selected_channels;
+
+       /**
+        * struct p2p_lo_stop - Reason code for P2P Listen offload stop event
+        * @reason_code: Reason for stopping offload
+        *      P2P_LO_STOPPED_REASON_COMPLETE: Listen offload finished as
+        *      scheduled.
+        *      P2P_LO_STOPPED_REASON_RECV_STOP_CMD: Host requested offload to
+        *      be stopped.
+        *      P2P_LO_STOPPED_REASON_INVALID_PARAM: Invalid listen offload
+        *      parameters.
+        *      P2P_LO_STOPPED_REASON_NOT_SUPPORTED: Listen offload not
+        *      supported by device.
+        */
+       struct p2p_lo_stop {
+               enum {
+                       P2P_LO_STOPPED_REASON_COMPLETE = 0,
+                       P2P_LO_STOPPED_REASON_RECV_STOP_CMD,
+                       P2P_LO_STOPPED_REASON_INVALID_PARAM,
+                       P2P_LO_STOPPED_REASON_NOT_SUPPORTED,
+               } reason_code;
+       } p2p_lo_stop;
 };
 
 /**
@@ -4645,6 +4873,18 @@ union wpa_event_data {
 void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                          union wpa_event_data *data);
 
+/**
+ * wpa_supplicant_event_global - Report a driver event for wpa_supplicant
+ * @ctx: Context pointer (wpa_s); this is the ctx variable registered
+ *     with struct wpa_driver_ops::init()
+ * @event: event type (defined above)
+ * @data: possible extra data for the event
+ *
+ * Same as wpa_supplicant_event(), but we search for the interface in
+ * wpa_global.
+ */
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+                                union wpa_event_data *data);
 
 /*
  * The following inline functions are provided for convenience to simplify
@@ -4697,8 +4937,52 @@ int vht_supported(const struct hostapd_hw_modes *mode);
 struct wowlan_triggers *
 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);
 
 /* NULL terminated array of linked in driver wrappers */
 extern const struct wpa_driver_ops *const wpa_drivers[];
 
+
+/* Available drivers */
+
+#ifdef CONFIG_DRIVER_WEXT
+extern const struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
+#endif /* CONFIG_DRIVER_WEXT */
+#ifdef CONFIG_DRIVER_NL80211
+/* driver_nl80211.c */
+extern const struct wpa_driver_ops wpa_driver_nl80211_ops;
+#endif /* CONFIG_DRIVER_NL80211 */
+#ifdef CONFIG_DRIVER_HOSTAP
+extern const struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
+#endif /* CONFIG_DRIVER_HOSTAP */
+#ifdef CONFIG_DRIVER_BSD
+extern const struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
+#endif /* CONFIG_DRIVER_BSD */
+#ifdef CONFIG_DRIVER_OPENBSD
+/* driver_openbsd.c */
+extern const struct wpa_driver_ops wpa_driver_openbsd_ops;
+#endif /* CONFIG_DRIVER_OPENBSD */
+#ifdef CONFIG_DRIVER_NDIS
+extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */
+#endif /* CONFIG_DRIVER_NDIS */
+#ifdef CONFIG_DRIVER_WIRED
+extern const struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */
+#endif /* CONFIG_DRIVER_WIRED */
+#ifdef CONFIG_DRIVER_MACSEC_QCA
+/* driver_macsec_qca.c */
+extern const struct wpa_driver_ops wpa_driver_macsec_qca_ops;
+#endif /* CONFIG_DRIVER_MACSEC_QCA */
+#ifdef CONFIG_DRIVER_ROBOSWITCH
+/* driver_roboswitch.c */
+extern const struct wpa_driver_ops wpa_driver_roboswitch_ops;
+#endif /* CONFIG_DRIVER_ROBOSWITCH */
+#ifdef CONFIG_DRIVER_ATHEROS
+/* driver_atheros.c */
+extern const struct wpa_driver_ops wpa_driver_atheros_ops;
+#endif /* CONFIG_DRIVER_ATHEROS */
+#ifdef CONFIG_DRIVER_NONE
+extern const struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */
+#endif /* CONFIG_DRIVER_NONE */
+
 #endif /* DRIVER_H */
index ef14093..a88345f 100644 (file)
@@ -189,13 +189,13 @@ set80211priv(struct atheros_driver_data *drv, int op, void *data, int len)
            op == IEEE80211_IOCTL_FILTERFRAME)
                do_inline = 0;
 
-       memset(&iwr, 0, sizeof(iwr));
+       os_memset(&iwr, 0, sizeof(iwr));
        os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
        if (do_inline) {
                /*
                 * Argument data fits inline; put it there.
                 */
-               memcpy(iwr.u.name, data, len);
+               os_memcpy(iwr.u.name, data, len);
        } else {
                /*
                 * Argument data too big for inline transfer; setup a
@@ -222,10 +222,10 @@ set80211param(struct atheros_driver_data *drv, int op, int arg)
 {
        struct iwreq iwr;
 
-       memset(&iwr, 0, sizeof(iwr));
+       os_memset(&iwr, 0, sizeof(iwr));
        os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
        iwr.u.mode = op;
-       memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg));
+       os_memcpy(iwr.u.name + sizeof(__u32), &arg, sizeof(arg));
 
        if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
                wpa_printf(MSG_INFO,
@@ -244,9 +244,9 @@ ether_sprintf(const u8 *addr)
        static char buf[sizeof(MACSTR)];
 
        if (addr != NULL)
-               snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+               os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
        else
-               snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
+               os_snprintf(buf, sizeof(buf), MACSTR, 0, 0, 0, 0, 0, 0);
        return buf;
 }
 #endif /* CONFIG_NO_STDOUT_DEBUG */
@@ -422,7 +422,7 @@ atheros_set_sta_authorized(void *priv, const u8 *addr, int authorized)
        else
                mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
        mlme.im_reason = 0;
-       memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+       os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
        ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
        if (ret < 0) {
                wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR,
@@ -455,9 +455,9 @@ atheros_del_key(void *priv, const u8 *addr, int key_idx)
        wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
                   __func__, ether_sprintf(addr), key_idx);
 
-       memset(&wk, 0, sizeof(wk));
+       os_memset(&wk, 0, sizeof(wk));
        if (addr != NULL) {
-               memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
+               os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
                wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE;
        } else {
                wk.idk_keyix = key_idx;
@@ -538,20 +538,20 @@ atheros_set_key(const char *ifname, void *priv, enum wpa_alg alg,
                return -3;
        }
 
-       memset(&wk, 0, sizeof(wk));
+       os_memset(&wk, 0, sizeof(wk));
        wk.ik_type = cipher;
        wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
        if (addr == NULL || is_broadcast_ether_addr(addr)) {
-               memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+               os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
                wk.ik_keyix = key_idx;
                if (set_tx)
                        wk.ik_flags |= IEEE80211_KEY_DEFAULT;
        } else {
-               memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+               os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
                wk.ik_keyix = IEEE80211_KEYIX_NONE;
        }
        wk.ik_keylen = key_len;
-       memcpy(wk.ik_keydata, key, key_len);
+       os_memcpy(wk.ik_keydata, key, key_len);
 
        ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk));
        if (ret < 0) {
@@ -575,11 +575,11 @@ atheros_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
        wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
                   __func__, ether_sprintf(addr), idx);
 
-       memset(&wk, 0, sizeof(wk));
+       os_memset(&wk, 0, sizeof(wk));
        if (addr == NULL)
-               memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+               os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
        else
-               memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+               os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
        wk.ik_keyix = idx;
 
        if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) {
@@ -600,13 +600,13 @@ atheros_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
 #define WPA_KEY_RSC_LEN 8
 #endif
                u8 tmp[WPA_KEY_RSC_LEN];
-               memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+               os_memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
                for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
                        seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];
                }
        }
 #else /* WORDS_BIGENDIAN */
-       memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+       os_memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
 #endif /* WORDS_BIGENDIAN */
        return 0;
 }
@@ -616,7 +616,7 @@ static int
 atheros_flush(void *priv)
 {
        u8 allsta[IEEE80211_ADDR_LEN];
-       memset(allsta, 0xff, IEEE80211_ADDR_LEN);
+       os_memset(allsta, 0xff, IEEE80211_ADDR_LEN);
        return atheros_sta_deauth(priv, NULL, allsta,
                                  IEEE80211_REASON_AUTH_LEAVE);
 }
@@ -629,19 +629,19 @@ atheros_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
        struct atheros_driver_data *drv = priv;
        struct ieee80211req_sta_stats stats;
 
-       memset(data, 0, sizeof(*data));
+       os_memset(data, 0, sizeof(*data));
 
        /*
         * Fetch statistics for station from the system.
         */
-       memset(&stats, 0, sizeof(stats));
-       memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
+       os_memset(&stats, 0, sizeof(stats));
+       os_memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
        if (set80211priv(drv, IEEE80211_IOCTL_STA_STATS,
                         &stats, sizeof(stats))) {
                wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr "
                           MACSTR ")", __func__, MAC2STR(addr));
-               if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
-                       memcpy(data, &drv->acct_data, sizeof(*data));
+               if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
+                       os_memcpy(data, &drv->acct_data, sizeof(*data));
                        return 0;
                }
 
@@ -668,7 +668,7 @@ atheros_sta_clear_stats(void *priv, const u8 *addr)
        wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr));
 
        mlme.im_op = IEEE80211_MLME_CLEAR_STATS;
-       memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+       os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
        ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
                           sizeof(mlme));
        if (ret < 0) {
@@ -744,7 +744,7 @@ atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
 
        mlme.im_op = IEEE80211_MLME_DEAUTH;
        mlme.im_reason = reason_code;
-       memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+       os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
        ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
        if (ret < 0) {
                wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR
@@ -768,7 +768,7 @@ atheros_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
 
        mlme.im_op = IEEE80211_MLME_DISASSOC;
        mlme.im_reason = reason_code;
-       memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+       os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
        ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
        if (ret < 0) {
                wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr "
@@ -794,7 +794,7 @@ static int atheros_set_qos_map(void *ctx, const u8 *qos_map_set,
                wpa_printf(MSG_ERROR, "Invalid QoS Map");
                return -1;
        } else {
-               memset(&req, 0, sizeof(struct ieee80211req_athdbg));
+               os_memset(&req, 0, sizeof(struct ieee80211req_athdbg));
                req.cmd = IEEE80211_DBGREQ_SETQOSMAPCONF;
                os_memset(&iwr, 0, sizeof(iwr));
                os_strlcpy(iwr.ifr_name, drv->iface, sizeof(iwr.ifr_name));
@@ -855,20 +855,29 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
                   (int) len);
 
        if (stype == WLAN_FC_STYPE_PROBE_REQ) {
-               if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+               if (len < IEEE80211_HDRLEN)
                        return;
 
                os_memset(&event, 0, sizeof(event));
                event.rx_probe_req.sa = mgmt->sa;
                event.rx_probe_req.da = mgmt->da;
                event.rx_probe_req.bssid = mgmt->bssid;
-               event.rx_probe_req.ie = mgmt->u.probe_req.variable;
-               event.rx_probe_req.ie_len =
-                       len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+               event.rx_probe_req.ie = buf + IEEE80211_HDRLEN;
+               event.rx_probe_req.ie_len = len - IEEE80211_HDRLEN;
                wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
                return;
        }
 
+       if (stype == WLAN_FC_STYPE_ACTION &&
+           (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) == 0 ||
+            is_broadcast_ether_addr(mgmt->bssid))) {
+               os_memset(&event, 0, sizeof(event));
+               event.rx_mgmt.frame = buf;
+               event.rx_mgmt.frame_len = len;
+               wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
+               return;
+       }
+
        if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
                wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
                           __func__);
@@ -890,12 +899,6 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
                iebuf = mgmt->u.reassoc_req.variable;
                drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1);
                break;
-       case WLAN_FC_STYPE_ACTION:
-               os_memset(&event, 0, sizeof(event));
-               event.rx_mgmt.frame = buf;
-               event.rx_mgmt.frame_len = len;
-               wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
-               break;
        case WLAN_FC_STYPE_AUTH:
                if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth))
                        break;
@@ -1120,8 +1123,8 @@ atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
        /*
         * Fetch negotiated WPA/RSN parameters from the system.
         */
-       memset(&ie, 0, sizeof(ie));
-       memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
+       os_memset(&ie, 0, sizeof(ie));
+       os_memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
        if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) {
                /*
                 * See ATH_WPS_IE comment in the beginning of the file for a
@@ -1171,10 +1174,10 @@ atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
 no_ie:
        drv_event_assoc(hapd, addr, iebuf, ielen, 0);
 
-       if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
+       if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
                /* Cached accounting data is not valid anymore. */
-               memset(drv->acct_mac, 0, ETH_ALEN);
-               memset(&drv->acct_data, 0, sizeof(drv->acct_data));
+               os_memset(drv->acct_mac, 0, ETH_ALEN);
+               os_memset(&drv->acct_data, 0, sizeof(drv->acct_data));
        }
 }
 
@@ -1185,10 +1188,10 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
 #define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */
        wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
 
-       if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+       if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
                char *pos;
                u8 addr[ETH_ALEN];
-               pos = strstr(custom, "addr=");
+               pos = os_strstr(custom, "addr=");
                if (pos == NULL) {
                        wpa_printf(MSG_DEBUG,
                                   "MLME-MICHAELMICFAILURE.indication "
@@ -1212,33 +1215,33 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
                char *key, *value;
                u32 val;
                key = custom;
-               while ((key = strchr(key, '\n')) != NULL) {
+               while ((key = os_strchr(key, '\n')) != NULL) {
                        key++;
-                       value = strchr(key, '=');
+                       value = os_strchr(key, '=');
                        if (value == NULL)
                                continue;
                        *value++ = '\0';
                        val = strtoul(value, NULL, 10);
-                       if (strcmp(key, "mac") == 0)
+                       if (os_strcmp(key, "mac") == 0)
                                hwaddr_aton(value, drv->acct_mac);
-                       else if (strcmp(key, "rx_packets") == 0)
+                       else if (os_strcmp(key, "rx_packets") == 0)
                                drv->acct_data.rx_packets = val;
-                       else if (strcmp(key, "tx_packets") == 0)
+                       else if (os_strcmp(key, "tx_packets") == 0)
                                drv->acct_data.tx_packets = val;
-                       else if (strcmp(key, "rx_bytes") == 0)
+                       else if (os_strcmp(key, "rx_bytes") == 0)
                                drv->acct_data.rx_bytes = val;
-                       else if (strcmp(key, "tx_bytes") == 0)
+                       else if (os_strcmp(key, "tx_bytes") == 0)
                                drv->acct_data.tx_bytes = val;
                        key = value;
                }
 #ifdef CONFIG_WPS
-       } else if (strncmp(custom, "PUSH-BUTTON.indication", 22) == 0) {
+       } else if (os_strncmp(custom, "PUSH-BUTTON.indication", 22) == 0) {
                /* Some atheros kernels send push button as a wireless event */
                /* PROBLEM! this event is received for ALL BSSs ...
                 * so all are enabled for WPS... ugh.
                 */
                wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL);
-       } else if (strncmp(custom, "Manage.prob_req ", 16) == 0) {
+       } else if (os_strncmp(custom, "Manage.prob_req ", 16) == 0) {
                /*
                 * Atheros driver uses a hack to pass Probe Request frames as a
                 * binary data in the custom wireless event. The old way (using
@@ -1246,7 +1249,7 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
                 * Format: "Manage.prob_req <frame len>" | zero padding | frame
                 */
                int len = atoi(custom + 16);
-               if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
+               if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) {
                        wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event "
                                   "length %d", len);
                        return;
@@ -1255,11 +1258,11 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
                                    (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
 #endif /* CONFIG_WPS */
 #if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
-       } else if (strncmp(custom, "Manage.assoc_req ", 17) == 0) {
+       } else if (os_strncmp(custom, "Manage.assoc_req ", 17) == 0) {
                /* Format: "Manage.assoc_req <frame len>" | zero padding |
                 * frame */
                int len = atoi(custom + 17);
-               if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
+               if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) {
                        wpa_printf(MSG_DEBUG,
                                   "Invalid Manage.assoc_req event length %d",
                                   len);
@@ -1267,11 +1270,11 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
                }
                atheros_raw_receive(drv, NULL,
                                    (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
-               } else if (strncmp(custom, "Manage.auth ", 12) == 0) {
+               } else if (os_strncmp(custom, "Manage.auth ", 12) == 0) {
                /* Format: "Manage.auth <frame len>" | zero padding | frame */
                int len = atoi(custom + 12);
                        if (len < 0 ||
-                           custom + MGMT_FRAM_TAG_SIZE + len > end) {
+                           MGMT_FRAM_TAG_SIZE + len > end - custom) {
                        wpa_printf(MSG_DEBUG,
                                   "Invalid Manage.auth event length %d", len);
                        return;
@@ -1280,11 +1283,11 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
                                    (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
 #endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */
 #ifdef ATHEROS_USE_RAW_RECEIVE
-               } else if (strncmp(custom, "Manage.action ", 14) == 0) {
+               } else if (os_strncmp(custom, "Manage.action ", 14) == 0) {
                /* Format: "Manage.assoc_req <frame len>" | zero padding | frame
                 */
                int len = atoi(custom + 14);
-               if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
+               if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) {
                        wpa_printf(MSG_DEBUG,
                                   "Invalid Manage.action event length %d",
                                   len);
@@ -1384,7 +1387,7 @@ atheros_wireless_event_atheros_custom(struct atheros_driver_data *drv,
 
 static void
 atheros_wireless_event_wireless(struct atheros_driver_data *drv,
-                               char *data, int len)
+                               char *data, unsigned int len)
 {
        struct iw_event iwe_buf, *iwe = &iwe_buf;
        char *pos, *end, *custom, *buf;
@@ -1392,13 +1395,13 @@ atheros_wireless_event_wireless(struct atheros_driver_data *drv,
        pos = data;
        end = data + len;
 
-       while (pos + IW_EV_LCP_LEN <= end) {
+       while ((size_t) (end - pos) >= IW_EV_LCP_LEN) {
                /* Event data may be unaligned, so make a local, aligned copy
                 * before processing. */
-               memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+               os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
                wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d",
                           iwe->cmd, iwe->len);
-               if (iwe->len <= IW_EV_LCP_LEN)
+               if (iwe->len <= IW_EV_LCP_LEN || iwe->len > end - pos)
                        return;
 
                custom = pos + IW_EV_POINT_LEN;
@@ -1409,10 +1412,10 @@ atheros_wireless_event_wireless(struct atheros_driver_data *drv,
                        /* WE-19 removed the pointer from struct iw_point */
                        char *dpos = (char *) &iwe_buf.u.data.length;
                        int dlen = dpos - (char *) &iwe_buf;
-                       memcpy(dpos, pos + IW_EV_LCP_LEN,
-                              sizeof(struct iw_event) - dlen);
+                       os_memcpy(dpos, pos + IW_EV_LCP_LEN,
+                                 sizeof(struct iw_event) - dlen);
                } else {
-                       memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+                       os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
                        custom += IW_EV_POINT_OFF;
                }
 
@@ -1430,12 +1433,12 @@ atheros_wireless_event_wireless(struct atheros_driver_data *drv,
                         * just like IWEVCUSTOM.
                         */
                case IWEVCUSTOM:
-                       if (custom + iwe->u.data.length > end)
+                       if (iwe->u.data.length > end - custom)
                                return;
-                       buf = malloc(iwe->u.data.length + 1);
+                       buf = os_malloc(iwe->u.data.length + 1);
                        if (buf == NULL)
                                return;         /* XXX */
-                       memcpy(buf, custom, iwe->u.data.length);
+                       os_memcpy(buf, custom, iwe->u.data.length);
                        buf[iwe->u.data.length] = '\0';
 
                        if (iwe->u.data.flags != 0) {
@@ -1446,7 +1449,7 @@ atheros_wireless_event_wireless(struct atheros_driver_data *drv,
                                atheros_wireless_event_wireless_custom(
                                        drv, buf, buf + iwe->u.data.length);
                        }
-                       free(buf);
+                       os_free(buf);
                        break;
                }
 
@@ -1500,7 +1503,7 @@ atheros_get_we_version(struct atheros_driver_data *drv)
        if (range == NULL)
                return -1;
 
-       memset(&iwr, 0, sizeof(iwr));
+       os_memset(&iwr, 0, sizeof(iwr));
        os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
        iwr.u.data.pointer = (caddr_t) range;
        iwr.u.data.length = buflen;
@@ -1569,7 +1572,7 @@ atheros_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
         */
        len = data_len + sizeof(struct l2_ethhdr);
        if (len > sizeof(buf)) {
-               bp = malloc(len);
+               bp = os_malloc(len);
                if (bp == NULL) {
                        wpa_printf(MSG_INFO,
                                   "EAPOL frame discarded, cannot malloc temp buffer of size %lu!",
@@ -1578,17 +1581,17 @@ atheros_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
                }
        }
        eth = (struct l2_ethhdr *) bp;
-       memcpy(eth->h_dest, addr, ETH_ALEN);
-       memcpy(eth->h_source, own_addr, ETH_ALEN);
+       os_memcpy(eth->h_dest, addr, ETH_ALEN);
+       os_memcpy(eth->h_source, own_addr, ETH_ALEN);
        eth->h_proto = host_to_be16(ETH_P_EAPOL);
-       memcpy(eth+1, data, data_len);
+       os_memcpy(eth + 1, data, data_len);
 
        wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len);
 
        status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len);
 
        if (bp != buf)
-               free(bp);
+               os_free(bp);
        return status;
 }
 
@@ -1622,9 +1625,9 @@ atheros_init(struct hostapd_data *hapd, struct wpa_init_params *params)
                           strerror(errno));
                goto bad;
        }
-       memcpy(drv->iface, params->ifname, sizeof(drv->iface));
+       os_memcpy(drv->iface, params->ifname, sizeof(drv->iface));
 
-       memset(&ifr, 0, sizeof(ifr));
+       os_memset(&ifr, 0, sizeof(ifr));
        os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
        if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
                wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
@@ -1658,7 +1661,7 @@ atheros_init(struct hostapd_data *hapd, struct wpa_init_params *params)
        } else
                drv->sock_recv = drv->sock_xmit;
 
-       memset(&iwr, 0, sizeof(iwr));
+       os_memset(&iwr, 0, sizeof(iwr));
        os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
 
        iwr.u.mode = IW_MODE_MASTER;
@@ -1704,10 +1707,10 @@ atheros_deinit(void *priv)
        atheros_reset_appfilter(drv);
 
        if (drv->wpa_ie || drv->wps_beacon_ie || drv->wps_probe_resp_ie) {
+               atheros_set_opt_ie(priv, NULL, 0);
                wpabuf_free(drv->wpa_ie);
                wpabuf_free(drv->wps_beacon_ie);
                wpabuf_free(drv->wps_probe_resp_ie);
-               atheros_set_opt_ie(priv, NULL, 0);
        }
        netlink_deinit(drv->netlink);
        (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
@@ -1728,7 +1731,7 @@ atheros_set_ssid(void *priv, const u8 *buf, int len)
        struct atheros_driver_data *drv = priv;
        struct iwreq iwr;
 
-       memset(&iwr, 0, sizeof(iwr));
+       os_memset(&iwr, 0, sizeof(iwr));
        os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
        iwr.u.essid.flags = 1; /* SSID active */
        iwr.u.essid.pointer = (caddr_t) buf;
@@ -1749,7 +1752,7 @@ atheros_get_ssid(void *priv, u8 *buf, int len)
        struct iwreq iwr;
        int ret = 0;
 
-       memset(&iwr, 0, sizeof(iwr));
+       os_memset(&iwr, 0, sizeof(iwr));
        os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
        iwr.u.essid.pointer = (caddr_t) buf;
        iwr.u.essid.length = (len > IW_ESSID_MAX_SIZE) ?
@@ -1848,7 +1851,8 @@ static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params)
 #if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
 
 static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
-                            int noack, unsigned int freq)
+                            int noack, unsigned int freq,
+                            const u16 *csa_offs, size_t csa_offs_len)
 {
        struct atheros_driver_data *drv = priv;
        u8 buf[1510];
@@ -1859,7 +1863,7 @@ static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
        wpa_printf(MSG_DEBUG, "%s frmlen = %lu " MACSTR, __func__,
                   (unsigned long) data_len, MAC2STR(mgmt->da));
        mgmt_frm = (struct ieee80211req_mgmtbuf *) buf;
-       memcpy(mgmt_frm->macaddr, (u8 *)mgmt->da, IEEE80211_ADDR_LEN);
+       os_memcpy(mgmt_frm->macaddr, (u8 *)mgmt->da, IEEE80211_ADDR_LEN);
        mgmt_frm->buflen = data_len;
        if (&mgmt_frm->buf[0] + data_len > buf + sizeof(buf)) {
                wpa_printf(MSG_INFO, "atheros: Too long frame for "
index bab1f03..2afd7df 100644 (file)
 
 #include "l2_packet/l2_packet.h"
 
+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 */
 
-       int     sock;                   /* open socket for 802.11 ioctls */
        struct l2_packet_data *sock_xmit;/* raw packet xmit socket */
-       int     route;                  /* routing socket for events */
        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 */
@@ -62,18 +73,47 @@ struct bsd_driver_data {
        int     prev_privacy;   /* privacy state to restore on deinit */
        int     prev_wpa;       /* wpa state to restore on deinit */
        enum ieee80211_opmode opmode;   /* operation mode */
-       char    *event_buf;
-       size_t  event_buf_len;
 };
 
 /* Generic functions for hostapd and wpa_supplicant */
 
+static struct bsd_driver_data *
+bsd_get_drvindex(void *priv, unsigned int ifindex)
+{
+       struct bsd_driver_global *global = priv;
+       struct bsd_driver_data *drv;
+
+       dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) {
+               if (drv->ifindex == ifindex)
+                       return drv;
+       }
+       return NULL;
+}
+
+#ifndef HOSTAPD
+static struct bsd_driver_data *
+bsd_get_drvname(void *priv, const char *ifname)
+{
+       struct bsd_driver_global *global = priv;
+       struct bsd_driver_data *drv;
+
+       dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) {
+               if (os_strcmp(drv->ifname, ifname) == 0)
+                       return drv;
+       }
+       return NULL;
+}
+#endif /* HOSTAPD */
+
 static int
 bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
 {
        struct bsd_driver_data *drv = priv;
        struct ieee80211req ireq;
 
+       if (drv->ifindex == 0 || drv->if_removed)
+               return -1;
+
        os_memset(&ireq, 0, sizeof(ireq));
        os_strlcpy(ireq.i_name, drv->ifname, sizeof(ireq.i_name));
        ireq.i_type = op;
@@ -81,7 +121,7 @@ bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
        ireq.i_data = (void *) arg;
        ireq.i_len = arg_len;
 
-       if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
+       if (ioctl(drv->global->sock, SIOCS80211, &ireq) < 0) {
                wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, val=%u, "
                           "arg_len=%u]: %s", op, val, arg_len,
                           strerror(errno));
@@ -102,7 +142,7 @@ bsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg,
        ireq->i_len = arg_len;
        ireq->i_data = arg;
 
-       if (ioctl(drv->sock, SIOCG80211, ireq) < 0) {
+       if (ioctl(drv->global->sock, SIOCG80211, ireq) < 0) {
                wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, "
                           "arg_len=%u]: %s", op, arg_len, strerror(errno));
                return -1;
@@ -143,7 +183,7 @@ bsd_get_ssid(void *priv, u8 *ssid, int len)
        os_memset(&ifr, 0, sizeof(ifr));
        os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
        ifr.ifr_data = (void *)&nwid;
-       if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 ||
+       if (ioctl(drv->global->sock, SIOCG80211NWID, &ifr) < 0 ||
            nwid.i_len > IEEE80211_NWID_LEN)
                return -1;
        os_memcpy(ssid, nwid.i_nwid, nwid.i_len);
@@ -166,7 +206,7 @@ bsd_set_ssid(void *priv, const u8 *ssid, int ssid_len)
        os_memset(&ifr, 0, sizeof(ifr));
        os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
        ifr.ifr_data = (void *)&nwid;
-       return ioctl(drv->sock, SIOCS80211NWID, &ifr);
+       return ioctl(drv->global->sock, SIOCS80211NWID, &ifr);
 #else
        return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
 #endif
@@ -181,7 +221,7 @@ bsd_get_if_media(void *priv)
        os_memset(&ifmr, 0, sizeof(ifmr));
        os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
 
-       if (ioctl(drv->sock, SIOCGIFMEDIA, &ifmr) < 0) {
+       if (ioctl(drv->global->sock, SIOCGIFMEDIA, &ifmr) < 0) {
                wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__,
                           strerror(errno));
                return -1;
@@ -200,7 +240,7 @@ bsd_set_if_media(void *priv, int media)
        os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
        ifr.ifr_media = media;
 
-       if (ioctl(drv->sock, SIOCSIFMEDIA, &ifr) < 0) {
+       if (ioctl(drv->global->sock, SIOCSIFMEDIA, &ifr) < 0) {
                wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__,
                           strerror(errno));
                return -1;
@@ -263,11 +303,12 @@ bsd_ctrl_iface(void *priv, int enable)
        os_memset(&ifr, 0, sizeof(ifr));
        os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
 
-       if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) {
+       if (ioctl(drv->global->sock, SIOCGIFFLAGS, &ifr) < 0) {
                wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
                           strerror(errno));
                return -1;
        }
+       drv->flags = ifr.ifr_flags;
 
        if (enable) {
                if (ifr.ifr_flags & IFF_UP)
@@ -279,12 +320,13 @@ bsd_ctrl_iface(void *priv, int enable)
                ifr.ifr_flags &= ~IFF_UP;
        }
 
-       if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) {
+       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;
 }
 
@@ -576,7 +618,7 @@ bsd_set_freq(void *priv, struct hostapd_freq_params *freq)
        os_memset(&creq, 0, sizeof(creq));
        os_strlcpy(creq.i_name, drv->ifname, sizeof(creq.i_name));
        creq.i_channel = (u_int16_t)channel;
-       return ioctl(drv->sock, SIOCS80211CHANNEL, &creq);
+       return ioctl(drv->global->sock, SIOCS80211CHANNEL, &creq);
 #else /* SIOCS80211CHANNEL */
        return set80211param(priv, IEEE80211_IOC_CHANNEL, channel);
 #endif /* SIOCS80211CHANNEL */
@@ -730,7 +772,8 @@ 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_data *drv = 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;
@@ -739,7 +782,7 @@ bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
        int n;
        union wpa_event_data data;
 
-       n = read(sock, drv->event_buf, drv->event_buf_len);
+       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",
@@ -747,15 +790,18 @@ bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
                return;
        }
 
-       rtm = (struct rt_msghdr *) drv->event_buf;
+       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;
        }
-       ifan = (struct if_announcemsghdr *) rtm;
        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:
@@ -811,21 +857,15 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
                return NULL;
        }
 
-       drv->event_buf_len = rtbuf_len();
-
-       drv->event_buf = os_malloc(drv->event_buf_len);
-       if (drv->event_buf == NULL) {
-               wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
+       drv->ifindex = if_nametoindex(params->ifname);
+       if (drv->ifindex == 0) {
+               wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
+                          __func__, params->ifname);
                goto bad;
        }
 
        drv->hapd = hapd;
-       drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-       if (drv->sock < 0) {
-               wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
-                          strerror(errno));
-               goto bad;
-       }
+       drv->global = params->global_priv;
        os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
 
        drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL,
@@ -839,28 +879,18 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
        if (bsd_ctrl_iface(drv, 0) < 0)
                goto bad;
 
-       drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
-       if (drv->route < 0) {
-               wpa_printf(MSG_ERROR, "socket(PF_ROUTE,SOCK_RAW): %s",
-                          strerror(errno));
-               goto bad;
-       }
-       eloop_register_read_sock(drv->route, bsd_wireless_event_receive, drv,
-                                NULL);
-
        if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) {
                wpa_printf(MSG_ERROR, "%s: failed to set operation mode",
                           __func__);
                goto bad;
        }
 
+       dl_list_add(&drv->global->ifaces, &drv->list);
+
        return drv;
 bad:
        if (drv->sock_xmit != NULL)
                l2_packet_deinit(drv->sock_xmit);
-       if (drv->sock >= 0)
-               close(drv->sock);
-       os_free(drv->event_buf);
        os_free(drv);
        return NULL;
 }
@@ -871,16 +901,10 @@ bsd_deinit(void *priv)
 {
        struct bsd_driver_data *drv = priv;
 
-       if (drv->route >= 0) {
-               eloop_unregister_read_sock(drv->route);
-               close(drv->route);
-       }
-       bsd_ctrl_iface(drv, 0);
-       if (drv->sock >= 0)
-               close(drv->sock);
+       if (drv->ifindex != 0)
+               bsd_ctrl_iface(drv, 0);
        if (drv->sock_xmit != NULL)
                l2_packet_deinit(drv->sock_xmit);
-       os_free(drv->event_buf);
        os_free(drv);
 }
 
@@ -932,7 +956,7 @@ wpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
        struct ieee80211_bssid bs;
 
        os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name));
-       if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0)
+       if (ioctl(drv->global->sock, SIOCG80211BSSID, &bs) < 0)
                return -1;
        os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid));
        return 0;
@@ -966,7 +990,7 @@ wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy)
        int ret = 0;
 
        wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d",
-               __FUNCTION__, wpa, privacy);
+               __func__, wpa, privacy);
 
        if (!wpa && wpa_driver_bsd_set_wpa_ie(priv, NULL, 0) < 0)
                ret = -1;
@@ -981,7 +1005,7 @@ wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy)
 static int
 wpa_driver_bsd_set_wpa(void *priv, int enabled)
 {
-       wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+       wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
 
        return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled);
 }
@@ -1186,7 +1210,8 @@ 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_data *drv = 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;
@@ -1196,7 +1221,7 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
        struct ieee80211_join_event *join;
        int n;
 
-       n = read(sock, drv->event_buf, drv->event_buf_len);
+       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",
@@ -1204,7 +1229,7 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
                return;
        }
 
-       rtm = (struct rt_msghdr *) drv->event_buf;
+       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);
@@ -1214,53 +1239,79 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
        switch (rtm->rtm_type) {
        case RTM_IFANNOUNCE:
                ifan = (struct if_announcemsghdr *) rtm;
-               if (ifan->ifan_index != drv->ifindex)
-                       break;
-               os_strlcpy(event.interface_status.ifname, drv->ifname,
-                          sizeof(event.interface_status.ifname));
                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",
-                          event.interface_status.ifname,
+                          ifan->ifan_name,
                           ifan->ifan_what == IFAN_DEPARTURE ?
                                "removed" : "added");
-               wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+               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;
-               if (ifan->ifan_index != drv->ifindex)
-                       break;
+               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(ctx, EVENT_ASSOC, NULL);
+                       wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
                        break;
                case RTM_IEEE80211_DISASSOC:
                        if (drv->is_ap)
                                break;
-                       wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
+                       wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
                        break;
                case RTM_IEEE80211_SCAN:
                        if (drv->is_ap)
                                break;
-                       wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
+                       wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
+                                            NULL);
                        break;
                case RTM_IEEE80211_LEAVE:
                        leave = (struct ieee80211_leave_event *) &ifan[1];
-                       drv_event_disassoc(ctx, leave->iev_addr);
+                       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, ctx, join->iev_addr);
+                       bsd_new_sta(drv, drv->ctx, join->iev_addr);
                        break;
                case RTM_IEEE80211_REPLAY:
                        /* ignore */
@@ -1275,23 +1326,30 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
                        os_memset(&event, 0, sizeof(event));
                        event.michael_mic_failure.unicast =
                                !IEEE80211_IS_MULTICAST(mic->iev_dst);
-                       wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE,
-                               &event);
+                       wpa_supplicant_event(drv->ctx,
+                                            EVENT_MICHAEL_MIC_FAILURE, &event);
                        break;
                }
                break;
        case RTM_IFINFO:
                ifm = (struct if_msghdr *) rtm;
-               if (ifm->ifm_index != drv->ifindex)
-                       break;
-               if ((rtm->rtm_flags & RTF_UP) == 0) {
-                       os_strlcpy(event.interface_status.ifname, drv->ifname,
-                                  sizeof(event.interface_status.ifname));
-                       event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+               drv = bsd_get_drvindex(global, ifm->ifm_index);
+               if (drv == NULL)
+                       return;
+               if ((ifm->ifm_flags & IFF_UP) == 0 &&
+                   (drv->flags & IFF_UP) != 0) {
                        wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
-                                  event.interface_status.ifname);
-                       wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+                                  drv->ifname);
+                       wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED,
+                                            NULL);
+               } else if ((ifm->ifm_flags & IFF_UP) != 0 &&
+                   (drv->flags & IFF_UP) == 0) {
+                       wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP",
+                                  drv->ifname);
+                       wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+                                            NULL);
                }
+               drv->flags = ifm->ifm_flags;
                break;
        }
 }
@@ -1318,11 +1376,16 @@ wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res,
        result->caps = sr->isr_capinfo;
        result->qual = sr->isr_rssi;
        result->noise = sr->isr_noise;
+
+#ifdef __FreeBSD__
        /*
         * the rssi value reported by the kernel is in 0.5dB steps relative to
         * the reported noise floor. see ieee80211_node.h for details.
         */
        result->level = sr->isr_rssi / 2 + sr->isr_noise;
+#else
+       result->level = sr->isr_rssi;
+#endif
 
        pos = (u8 *)(result + 1);
 
@@ -1477,7 +1540,7 @@ get80211opmode(struct bsd_driver_data *drv)
        (void) memset(&ifmr, 0, sizeof(ifmr));
        (void) os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
 
-       if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
+       if (ioctl(drv->global->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
                if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
                        if (ifmr.ifm_current & IFM_FLAG0)
                                return IEEE80211_M_AHDEMO;
@@ -1497,7 +1560,7 @@ get80211opmode(struct bsd_driver_data *drv)
 }
 
 static void *
-wpa_driver_bsd_init(void *ctx, const char *ifname)
+wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv)
 {
 #define        GETPARAM(drv, param, v) \
        (((v) = get80211param(drv, param)) != -1)
@@ -1507,14 +1570,6 @@ wpa_driver_bsd_init(void *ctx, const char *ifname)
        if (drv == NULL)
                return NULL;
 
-       drv->event_buf_len = rtbuf_len();
-
-       drv->event_buf = os_malloc(drv->event_buf_len);
-       if (drv->event_buf == NULL) {
-               wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
-               goto fail1;
-       }
-
        /*
         * NB: We require the interface name be mappable to an index.
         *     This implies we do not support having wpa_supplicant
@@ -1525,24 +1580,12 @@ wpa_driver_bsd_init(void *ctx, const char *ifname)
        if (drv->ifindex == 0) {
                wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
                           __func__, ifname);
-               goto fail1;
-       }
-       drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-       if (drv->sock < 0)
-               goto fail1;
-
-       os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-       /* Down interface during setup. */
-       if (bsd_ctrl_iface(drv, 0) < 0)
-               goto fail;
-
-       drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
-       if (drv->route < 0)
                goto fail;
-       eloop_register_read_sock(drv->route,
-               wpa_driver_bsd_event_receive, ctx, drv);
+       }
 
        drv->ctx = ctx;
+       drv->global = priv;
+       os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
 
        if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
                wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
@@ -1563,13 +1606,15 @@ wpa_driver_bsd_init(void *ctx, const char *ifname)
        if (wpa_driver_bsd_capa(drv))
                goto fail;
 
+       /* Down interface during setup. */
+       if (bsd_ctrl_iface(drv, 0) < 0)
+               goto fail;
+
        drv->opmode = get80211opmode(drv);
+       dl_list_add(&drv->global->ifaces, &drv->list);
 
        return drv;
 fail:
-       close(drv->sock);
-fail1:
-       os_free(drv->event_buf);
        os_free(drv);
        return NULL;
 #undef GETPARAM
@@ -1580,22 +1625,25 @@ wpa_driver_bsd_deinit(void *priv)
 {
        struct bsd_driver_data *drv = priv;
 
-       wpa_driver_bsd_set_wpa(drv, 0);
-       eloop_unregister_read_sock(drv->route);
+       if (drv->ifindex != 0 && !drv->if_removed) {
+               wpa_driver_bsd_set_wpa(drv, 0);
 
-       /* NB: mark interface down */
-       bsd_ctrl_iface(drv, 0);
+               /* NB: mark interface down */
+               bsd_ctrl_iface(drv, 0);
 
-       wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy);
-       if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0)
-               wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state",
-                       __func__);
+               wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa,
+                                               drv->prev_privacy);
+
+               if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)
+                   < 0)
+                       wpa_printf(MSG_DEBUG,
+                                  "%s: failed to restore roaming state",
+                                  __func__);
+       }
 
        if (drv->sock_xmit != NULL)
                l2_packet_deinit(drv->sock_xmit);
-       (void) close(drv->route);               /* ioctl socket */
-       (void) close(drv->sock);                /* event socket */
-       os_free(drv->event_buf);
+       dl_list_del(&drv->list);
        os_free(drv);
 }
 
@@ -1609,10 +1657,74 @@ wpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa)
 }
 #endif /* HOSTAPD */
 
+static void *
+bsd_global_init(void *ctx)
+{
+       struct bsd_driver_global *global;
+
+       global = os_zalloc(sizeof(*global));
+       if (global == NULL)
+               return NULL;
+
+       global->ctx = ctx;
+       dl_list_init(&global->ifaces);
+
+       global->sock = socket(PF_INET, SOCK_DGRAM, 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);
+       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;
+       }
+
+#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:
+       close(global->sock);
+fail1:
+       os_free(global);
+       return NULL;
+}
+
+static void
+bsd_global_deinit(void *priv)
+{
+       struct bsd_driver_global *global = priv;
+
+       eloop_unregister_read_sock(global->route);
+       (void) close(global->route);
+       (void) close(global->sock);
+       os_free(global);
+}
+
 
 const struct wpa_driver_ops wpa_driver_bsd_ops = {
        .name                   = "bsd",
        .desc                   = "BSD 802.11 support",
+       .global_init            = bsd_global_init,
+       .global_deinit          = bsd_global_deinit,
 #ifdef HOSTAPD
        .hapd_init              = bsd_init,
        .hapd_deinit            = bsd_deinit,
@@ -1625,7 +1737,7 @@ const struct wpa_driver_ops wpa_driver_bsd_ops = {
        .sta_set_flags          = bsd_set_sta_authorized,
        .commit                 = bsd_commit,
 #else /* HOSTAPD */
-       .init                   = wpa_driver_bsd_init,
+       .init2                  = wpa_driver_bsd_init,
        .deinit                 = wpa_driver_bsd_deinit,
        .get_bssid              = wpa_driver_bsd_get_bssid,
        .get_ssid               = wpa_driver_bsd_get_ssid,
index aebea8c..c7107ba 100644 (file)
@@ -80,6 +80,7 @@ const char * event_to_string(enum wpa_event_type event)
        E2S(NEW_PEER_CANDIDATE);
        E2S(ACS_CHANNEL_SELECTED);
        E2S(DFS_CAC_STARTED);
+       E2S(P2P_LO_STOP);
        }
 
        return "UNKNOWN";
@@ -183,12 +184,12 @@ wpa_get_wowlan_triggers(const char *wowlan_triggers,
 
        start = buf;
        while (*start != '\0') {
-               while (isblank(*start))
+               while (isblank((unsigned char) *start))
                        start++;
                if (*start == '\0')
                        break;
                end = start;
-               while (!isblank(*end) && *end != '\0')
+               while (!isblank((unsigned char) *end) && *end != '\0')
                        end++;
                last = *end == '\0';
                *end = '\0';
@@ -218,3 +219,55 @@ out:
        os_free(buf);
        return triggers;
 }
+
+
+const char * driver_flag_to_string(u64 flag)
+{
+#define DF2S(x) case WPA_DRIVER_FLAGS_ ## x: return #x
+       switch (flag) {
+       DF2S(DRIVER_IE);
+       DF2S(SET_KEYS_AFTER_ASSOC);
+       DF2S(DFS_OFFLOAD);
+       DF2S(4WAY_HANDSHAKE);
+       DF2S(WIRED);
+       DF2S(SME);
+       DF2S(AP);
+       DF2S(SET_KEYS_AFTER_ASSOC_DONE);
+       DF2S(HT_2040_COEX);
+       DF2S(P2P_CONCURRENT);
+       DF2S(P2P_DEDICATED_INTERFACE);
+       DF2S(P2P_CAPABLE);
+       DF2S(AP_TEARDOWN_SUPPORT);
+       DF2S(P2P_MGMT_AND_NON_P2P);
+       DF2S(SANE_ERROR_CODES);
+       DF2S(OFFCHANNEL_TX);
+       DF2S(EAPOL_TX_STATUS);
+       DF2S(DEAUTH_TX_STATUS);
+       DF2S(BSS_SELECTION);
+       DF2S(TDLS_SUPPORT);
+       DF2S(TDLS_EXTERNAL_SETUP);
+       DF2S(PROBE_RESP_OFFLOAD);
+       DF2S(AP_UAPSD);
+       DF2S(INACTIVITY_TIMER);
+       DF2S(AP_MLME);
+       DF2S(SAE);
+       DF2S(OBSS_SCAN);
+       DF2S(IBSS);
+       DF2S(RADAR);
+       DF2S(DEDICATED_P2P_DEVICE);
+       DF2S(QOS_MAPPING);
+       DF2S(AP_CSA);
+       DF2S(MESH);
+       DF2S(ACS_OFFLOAD);
+       DF2S(KEY_MGMT_OFFLOAD);
+       DF2S(TDLS_CHANNEL_SWITCH);
+       DF2S(HT_IBSS);
+       DF2S(VHT_IBSS);
+       DF2S(SUPPORT_HW_MODE_ANY);
+       DF2S(OFFCHANNEL_SIMULTANEOUS);
+       DF2S(FULL_AP_CLIENT_STATE);
+       DF2S(P2P_LISTEN_OFFLOAD);
+       }
+       return "UNKNOWN";
+#undef DF2S
+}
index a7aa5ef..517a3bb 100644 (file)
@@ -258,7 +258,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)
+                           unsigned int freq,
+                           const u16 *csa_offs, size_t csa_offs_len)
 {
        struct hostap_driver_data *drv = priv;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
@@ -307,7 +308,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);
+       res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0, NULL, 0);
        if (res < 0) {
                wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - "
                           "failed: %d (%s)",
@@ -813,7 +814,7 @@ hostapd_wireless_event_wireless_custom(struct hostap_driver_data *drv,
 
 
 static void hostapd_wireless_event_wireless(struct hostap_driver_data *drv,
-                                           char *data, int len)
+                                           char *data, unsigned int len)
 {
        struct iw_event iwe_buf, *iwe = &iwe_buf;
        char *pos, *end, *custom, *buf;
@@ -821,13 +822,13 @@ static void hostapd_wireless_event_wireless(struct hostap_driver_data *drv,
        pos = data;
        end = data + len;
 
-       while (pos + IW_EV_LCP_LEN <= end) {
+       while ((size_t) (end - pos) >= IW_EV_LCP_LEN) {
                /* Event data may be unaligned, so make a local, aligned copy
                 * before processing. */
                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)
+               if (iwe->len <= IW_EV_LCP_LEN || iwe->len > end - pos)
                        return;
 
                custom = pos + IW_EV_POINT_LEN;
@@ -846,7 +847,7 @@ static void hostapd_wireless_event_wireless(struct hostap_driver_data *drv,
 
                switch (iwe->cmd) {
                case IWEVCUSTOM:
-                       if (custom + iwe->u.data.length > end)
+                       if (iwe->u.data.length > end - custom)
                                return;
                        buf = malloc(iwe->u.data.length + 1);
                        if (buf == NULL)
@@ -1045,7 +1046,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);
+                               sizeof(mgmt.u.deauth), 0, 0, NULL, 0);
 }
 
 
@@ -1083,7 +1084,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);
+                                sizeof(mgmt.u.disassoc), 0, 0, NULL, 0);
 }
 
 
@@ -1161,7 +1162,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);
+       hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0, NULL, 0);
 }
 
 
index 3eae2f8..826d3cc 100644 (file)
@@ -11,6 +11,7 @@
 #include "includes.h"
 #include <sys/ioctl.h>
 #include <net/if.h>
+#include <inttypes.h>
 #ifdef __linux__
 #include <netpacket/packet.h>
 #include <net/if_arp.h>
@@ -485,15 +486,12 @@ static int macsec_qca_set_replay_protect(void *priv, Boolean enabled,
 }
 
 
-static int macsec_qca_set_current_cipher_suite(void *priv, const u8 *cs,
-                                              size_t cs_len)
+static int macsec_qca_set_current_cipher_suite(void *priv, u64 cs)
 {
-       u8 default_cs_id[] = CS_ID_GCM_AES_128;
-
-       if (cs_len != CS_ID_LEN ||
-           os_memcmp(cs, default_cs_id, cs_len) != 0) {
-               wpa_hexdump(MSG_ERROR, "macsec: NOT supported CipherSuite",
-                           cs, cs_len);
+       if (cs != CS_ID_GCM_AES_128) {
+               wpa_printf(MSG_ERROR,
+                          "%s: NOT supported CipherSuite: %016" PRIx64,
+                          __func__, cs);
                return -1;
        }
 
index 669f1b8..9440f01 100644 (file)
@@ -35,6 +35,7 @@ int close(int fd);
 #include "driver.h"
 #include "eloop.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
 #include "driver_ndis.h"
 
 int wpa_driver_register_event_cb(struct wpa_driver_ndis_data *drv);
@@ -780,20 +781,7 @@ static int wpa_driver_ndis_scan(void *priv,
 
 static const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
 {
-       const u8 *end, *pos;
-
-       pos = (const u8 *) (res + 1);
-       end = pos + res->ie_len;
-
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
-                       break;
-               if (pos[0] == ie)
-                       return pos;
-               pos += 2 + pos[1];
-       }
-
-       return NULL;
+       return get_ie((const u8 *) (res + 1), res->ie_len, ie);
 }
 
 
index 00b173f..1210d43 100644 (file)
@@ -176,13 +176,19 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
 static int nl80211_send_frame_cmd(struct i802_bss *bss,
                                  unsigned int freq, unsigned int wait,
                                  const u8 *buf, size_t buf_len, u64 *cookie,
-                                 int no_cck, int no_ack, int offchanok);
+                                 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);
 
-static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
-static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
-static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
+#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);
@@ -194,6 +200,10 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
 
 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 */
 
 
 /* Converts nl80211_chan_width to a common format */
@@ -439,6 +449,8 @@ static int nl_get_multicast_id(struct nl80211_global *global,
 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);
 }
@@ -757,6 +769,15 @@ static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
 }
 
 
+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;
@@ -780,11 +801,12 @@ static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
 
 
 static void wpa_driver_nl80211_event_newlink(
-       struct wpa_driver_nl80211_data *drv, const char *ifname)
+       struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
+       int ifindex, const char *ifname)
 {
        union wpa_event_data event;
 
-       if (os_strcmp(drv->first_bss->ifname, ifname) == 0) {
+       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);
@@ -798,19 +820,25 @@ static void wpa_driver_nl80211_event_newlink(
        }
 
        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;
-       wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+       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 wpa_driver_nl80211_data *drv, const char *ifname)
+       struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
+       int ifindex, const char *ifname)
 {
        union wpa_event_data event;
 
-       if (os_strcmp(drv->first_bss->ifname, ifname) == 0) {
+       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);
@@ -825,10 +853,15 @@ static void wpa_driver_nl80211_event_dellink(
        }
 
        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;
-       wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+       if (drv)
+               wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+       else
+               wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
+                                           &event);
 }
 
 
@@ -882,7 +915,7 @@ nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len)
        dl_list_for_each(drv, &global->interfaces,
                         struct wpa_driver_nl80211_data, list) {
                if (wpa_driver_nl80211_own_ifindex(drv, idx, buf, len) ||
-                   have_ifidx(drv, idx))
+                   have_ifidx(drv, idx, IFIDX_ANY))
                        return drv;
        }
        return NULL;
@@ -902,13 +935,6 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
        char ifname[IFNAMSIZ + 1];
        char extra[100], *pos, *end;
 
-       drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
-       if (!drv) {
-               wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_NEWLINK event for foreign ifindex %d",
-                          ifi->ifi_index);
-               return;
-       }
-
        extra[0] = '\0';
        pos = extra;
        end = pos + sizeof(extra);
@@ -952,6 +978,10 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
                   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
 
+       drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+       if (!drv)
+               goto event_newlink;
+
        if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
                namebuf[0] = '\0';
                if (if_indextoname(ifi->ifi_index, namebuf) &&
@@ -1046,10 +1076,12 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                                       -1, IF_OPER_UP);
        }
 
+event_newlink:
        if (ifname[0])
-               wpa_driver_nl80211_event_newlink(drv, ifname);
+               wpa_driver_nl80211_event_newlink(global, drv, ifi->ifi_index,
+                                                ifname);
 
-       if (ifi->ifi_family == AF_BRIDGE && brid) {
+       if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
                struct i802_bss *bss;
 
                /* device has been added to bridge */
@@ -1061,7 +1093,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                }
                wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
                           brid, namebuf);
-               add_ifidx(drv, brid);
+               add_ifidx(drv, brid, ifi->ifi_index);
 
                for (bss = drv->first_bss; bss; bss = bss->next) {
                        if (os_strcmp(ifname, bss->ifname) == 0) {
@@ -1085,13 +1117,6 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
        char ifname[IFNAMSIZ + 1];
        char extra[100], *pos, *end;
 
-       drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
-       if (!drv) {
-               wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_DELLINK event for foreign ifindex %d",
-                          ifi->ifi_index);
-               return;
-       }
-
        extra[0] = '\0';
        pos = extra;
        end = pos + sizeof(extra);
@@ -1132,10 +1157,9 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
                   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
                   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
 
-       if (ifname[0] && (ifi->ifi_family != AF_BRIDGE || !brid))
-               wpa_driver_nl80211_event_dellink(drv, ifname);
+       drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
 
-       if (ifi->ifi_family == AF_BRIDGE && brid) {
+       if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
                /* device has been removed from bridge */
                char namebuf[IFNAMSIZ];
 
@@ -1148,8 +1172,12 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
                                   "nl80211: Remove ifindex %u for bridge %s",
                                   brid, namebuf);
                }
-               del_ifidx(drv, brid);
+               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);
 }
 
 
@@ -1519,11 +1547,16 @@ static void nl80211_check_global(struct nl80211_global *global)
 
 static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
 {
+       struct wpa_driver_nl80211_data *drv = ctx;
+
        wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
+
        /*
-        * This may be for any interface; use ifdown event to disable
-        * interface.
+        * 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);
 }
 
 
@@ -1536,7 +1569,16 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
                           "after rfkill unblock");
                return;
        }
-       /* rtnetlink ifup handler will report interface as enabled */
+
+       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);
 }
 
 
@@ -1621,13 +1663,65 @@ static void nl80211_destroy_bss(struct i802_bss *bss)
 }
 
 
+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 rfkill_config *rcfg;
        struct i802_bss *bss;
 
        if (global_priv == NULL)
@@ -1649,6 +1743,7 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
 
        drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
        drv->if_indices = drv->default_if_indices;
+       drv->if_indices_reason = drv->default_if_indices_reason;
 
        drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
        if (!drv->first_bss) {
@@ -1668,22 +1763,6 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
        if (nl80211_init_bss(bss))
                goto failed;
 
-       rcfg = os_zalloc(sizeof(*rcfg));
-       if (rcfg == NULL)
-               goto failed;
-       rcfg->ctx = drv;
-       os_strlcpy(rcfg->ifname, 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 == NULL) {
-               wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
-               os_free(rcfg);
-       }
-
-       if (linux_iface_up(drv->global->ioctl_sock, ifname) > 0)
-               drv->start_iface_up = 1;
-
        if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
                goto failed;
 
@@ -1916,6 +1995,10 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
        if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0)
                ret = -1;
 
+       /* Radio Measurement - Radio Measurement Request */
+       if (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))
@@ -1977,6 +2060,49 @@ static int nl80211_register_spurious_class3(struct i802_bss *bss)
 }
 
 
+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 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;
+#ifdef CONFIG_IEEE80211W
+       /* SA Query */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x08", 1) < 0)
+               ret = -1;
+#endif /* CONFIG_IEEE80211W */
+       /* 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[] = {
@@ -1985,7 +2111,6 @@ static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
                WLAN_FC_STYPE_REASSOC_REQ,
                WLAN_FC_STYPE_DISASSOC,
                WLAN_FC_STYPE_DEAUTH,
-               WLAN_FC_STYPE_ACTION,
                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
@@ -2010,6 +2135,9 @@ static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
                }
        }
 
+       if (nl80211_action_subscribe_ap(bss))
+               goto out_err;
+
        if (nl80211_register_spurious_class3(bss))
                goto out_err;
 
@@ -2032,10 +2160,7 @@ static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
        wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
                   "handle %p (device SME)", bss->nl_mgmt);
 
-       if (nl80211_register_frame(bss, bss->nl_mgmt,
-                                  (WLAN_FC_TYPE_MGMT << 2) |
-                                  (WLAN_FC_STYPE_ACTION << 4),
-                                  NULL, 0) < 0)
+       if (nl80211_action_subscribe_ap(bss))
                goto out_err;
 
        nl80211_mgmt_handle_register_eloop(bss);
@@ -2186,6 +2311,11 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
        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;
 
@@ -2206,7 +2336,8 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
 
        if (drv->hostapd || bss->static_ap)
                nlmode = NL80211_IFTYPE_AP;
-       else if (bss->if_dynamic)
+       else if (bss->if_dynamic ||
+                nl80211_get_ifmode(bss) == NL80211_IFTYPE_MESH_POINT)
                nlmode = nl80211_get_ifmode(bss);
        else
                nlmode = NL80211_IFTYPE_STATION;
@@ -2219,6 +2350,8 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
        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) {
@@ -2226,25 +2359,32 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
                                   "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)
-                       return 0;
-               drv->if_disabled = 1;
+               if (nlmode != NL80211_IFTYPE_P2P_DEVICE)
+                       drv->if_disabled = 1;
+
                send_rfkill_event = 1;
        }
 
-       if (!drv->hostapd)
+       if (!drv->hostapd && nlmode != NL80211_IFTYPE_P2P_DEVICE)
                netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
                                       1, IF_OPER_DORMANT);
 
-       if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-                              bss->addr))
-               return -1;
-       os_memcpy(drv->perm_addr, bss->addr, ETH_ALEN);
+       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,
@@ -2279,6 +2419,7 @@ static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
 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);
@@ -2325,6 +2466,9 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
        if (drv->if_indices != drv->default_if_indices)
                os_free(drv->if_indices);
 
+       if (drv->if_indices_reason != drv->default_if_indices_reason)
+               os_free(drv->if_indices_reason);
+
        if (drv->disabled_11b_rates)
                nl80211_disable_11b_rates(drv, drv->ifindex, 0);
 
@@ -2372,6 +2516,10 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
 
        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);
        os_free(drv);
 }
@@ -2468,6 +2616,7 @@ static int wpa_cipher_to_cipher_suites(unsigned int ciphers, u32 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)
 {
@@ -2495,6 +2644,7 @@ static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
 
        return ret;
 }
+#endif /* CONFIG_DRIVER_NL80211_QCA */
 
 
 static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
@@ -2525,6 +2675,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
        }
 #endif /* CONFIG_TDLS */
 
+#ifdef CONFIG_DRIVER_NL80211_QCA
        if (alg == WPA_ALG_PMK &&
            (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
                wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key",
@@ -2532,6 +2683,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
                ret = issue_key_mgmt_set_key(drv, key, key_len);
                return ret;
        }
+#endif /* CONFIG_DRIVER_NL80211_QCA */
 
        if (alg == WPA_ALG_NONE) {
                msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
@@ -3089,7 +3241,9 @@ static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
                                         const void *data, size_t len,
                                         int encrypt, int noack,
                                         unsigned int freq, int no_cck,
-                                        int offchanok, unsigned int wait_time)
+                                        int offchanok, unsigned int wait_time,
+                                        const u16 *csa_offs,
+                                        size_t csa_offs_len)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
        u64 cookie;
@@ -3115,7 +3269,8 @@ static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
 
        wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd");
        res = nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
-                                    &cookie, no_cck, noack, offchanok);
+                                    &cookie, no_cck, noack, offchanok,
+                                    csa_offs, csa_offs_len);
        if (res == 0 && !noack) {
                const struct ieee80211_mgmt *mgmt;
                u16 fc;
@@ -3141,7 +3296,9 @@ 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)
+                                       unsigned int wait_time,
+                                       const u16 *csa_offs,
+                                       size_t csa_offs_len)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct ieee80211_mgmt *mgmt;
@@ -3171,7 +3328,7 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
                }
                return nl80211_send_frame_cmd(bss, freq, 0,
                                              data, data_len, NULL, 1, noack,
-                                             1);
+                                             1, csa_offs, csa_offs_len);
        }
 
        if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
@@ -3185,7 +3342,8 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
                                              wait_time,
                                              data, data_len,
                                              &drv->send_action_cookie,
-                                             no_cck, noack, offchanok);
+                                             no_cck, noack, offchanok,
+                                             csa_offs, csa_offs_len);
        }
 
        if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
@@ -3205,7 +3363,8 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
        wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame");
        return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
                                             noack, freq, no_cck, offchanok,
-                                            wait_time);
+                                            wait_time, csa_offs,
+                                            csa_offs_len);
 }
 
 
@@ -3314,6 +3473,48 @@ static int nl80211_put_beacon_int(struct nl_msg *msg, int beacon_int)
 }
 
 
+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);
+       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 wpa_driver_nl80211_set_ap(void *priv,
                                     struct wpa_driver_ap_params *params)
 {
@@ -3327,6 +3528,9 @@ static int wpa_driver_nl80211_set_ap(void *priv,
        int smps_mode;
        u32 suites[10], 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;
 
@@ -3350,7 +3554,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
            nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
                    params->tail) ||
            nl80211_put_beacon_int(msg, params->beacon_int) ||
-           nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period) ||
+           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) {
@@ -3421,8 +3625,10 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                goto fail;
 
        if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
-           params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40) &&
-           nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
+           (!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;
 
        wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
@@ -3441,24 +3647,26 @@ static int wpa_driver_nl80211_set_ap(void *priv,
            nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite))
                goto fail;
 
-       switch (params->smps_mode) {
-       case HT_CAP_INFO_SMPS_DYNAMIC:
-               wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - dynamic");
-               smps_mode = NL80211_SMPS_DYNAMIC;
-               break;
-       case HT_CAP_INFO_SMPS_STATIC:
-               wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - static");
-               smps_mode = NL80211_SMPS_STATIC;
-               break;
-       default:
-               /* invalid - fallback to smps off */
-       case HT_CAP_INFO_SMPS_DISABLED:
-               wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - off");
-               smps_mode = NL80211_SMPS_OFF;
-               break;
+       if (params->ht_opmode != -1) {
+               switch (params->smps_mode) {
+               case HT_CAP_INFO_SMPS_DYNAMIC:
+                       wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - dynamic");
+                       smps_mode = NL80211_SMPS_DYNAMIC;
+                       break;
+               case HT_CAP_INFO_SMPS_STATIC:
+                       wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - static");
+                       smps_mode = NL80211_SMPS_STATIC;
+                       break;
+               default:
+                       /* invalid - fallback to smps off */
+               case HT_CAP_INFO_SMPS_DISABLED:
+                       wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - off");
+                       smps_mode = NL80211_SMPS_OFF;
+                       break;
+               }
+               if (nla_put_u32(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
+                       goto fail;
        }
-       if (nla_put_u32(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
-               goto fail;
 
        if (params->beacon_ies) {
                wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
@@ -3508,6 +3716,12 @@ static int wpa_driver_nl80211_set_ap(void *priv,
        }
 #endif /* CONFIG_P2P */
 
+       if (params->pbss) {
+               wpa_printf(MSG_DEBUG, "nl80211: PBSS");
+               if (nla_put_flag(msg, NL80211_ATTR_PBSS))
+                       goto fail;
+       }
+
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        if (ret) {
                wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
@@ -3533,7 +3747,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                                           "nl80211: Frequency set succeeded for ht2040 coex");
                                bss->bandwidth = params->freq->bandwidth;
                        }
-               } else if (!beacon_set) {
+               } 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
@@ -3542,6 +3756,18 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                        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);
@@ -3615,6 +3841,12 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
                wpa_printf(MSG_DEBUG, "  * channel_type=%d", ct);
                if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
                        return -ENOBUFS;
+       } 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;
 }
@@ -3666,6 +3898,8 @@ static u32 sta_flags_nl80211(int flags)
                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;
 }
@@ -3675,11 +3909,11 @@ static u32 sta_flags_nl80211(int flags)
 static u32 sta_plink_state_nl80211(enum mesh_plink_state state)
 {
        switch (state) {
-       case PLINK_LISTEN:
+       case PLINK_IDLE:
                return NL80211_PLINK_LISTEN;
-       case PLINK_OPEN_SENT:
+       case PLINK_OPN_SNT:
                return NL80211_PLINK_OPN_SNT;
-       case PLINK_OPEN_RCVD:
+       case PLINK_OPN_RCVD:
                return NL80211_PLINK_OPN_RCVD;
        case PLINK_CNF_RCVD:
                return NL80211_PLINK_CNF_RCVD;
@@ -3718,7 +3952,17 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        if (!msg || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr))
                goto fail;
 
-       if (!params->set || (params->flags & WPA_STA_TDLS_PEER)) {
+       /*
+        * 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",
@@ -3756,6 +4000,13 @@ static int wpa_driver_nl80211_sta_add(void *priv,
                                    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) {
@@ -3766,9 +4017,12 @@ static int wpa_driver_nl80211_sta_add(void *priv,
                        /*
                         * 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.
+                        * a dummy STA entry is used for now and for a station
+                        * that is still not associated.
                         */
-                       wpa_printf(MSG_DEBUG, "  * aid=1 (TDLS workaround)");
+                       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;
                }
@@ -3781,6 +4035,15 @@ static int wpa_driver_nl80211_sta_add(void *priv,
                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) {
@@ -3811,6 +4074,45 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        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))
@@ -3933,7 +4235,11 @@ void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int 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);
+       {
+               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) == 0)
@@ -3942,7 +4248,7 @@ void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx)
 }
 
 
-static const char * nl80211_iftype_str(enum nl80211_iftype mode)
+const char * nl80211_iftype_str(enum nl80211_iftype mode)
 {
        switch (mode) {
        case NL80211_IFTYPE_ADHOC:
@@ -4041,7 +4347,7 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
            iftype == NL80211_IFTYPE_WDS ||
            iftype == NL80211_IFTYPE_MONITOR) {
                /* start listening for EAPOL on this interface */
-               add_ifidx(drv, ifidx);
+               add_ifidx(drv, ifidx, IFIDX_ANY);
        }
 
        if (addr && iftype != NL80211_IFTYPE_MONITOR &&
@@ -4124,7 +4430,8 @@ static int nl80211_setup_ap(struct i802_bss *bss)
 
        if (drv->device_ap_sme && !drv->use_monitor)
                if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
-                       return -1;
+                       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) &&
@@ -4244,7 +4551,7 @@ static int wpa_driver_nl80211_hapd_send_eapol(
        memcpy(pos, data, data_len);
 
        res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0,
-                                           0, 0, 0, 0);
+                                           0, 0, 0, 0, NULL, 0);
        if (res < 0) {
                wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
                           "failed: %d (%s)",
@@ -4473,8 +4780,9 @@ retry:
                        goto fail;
        }
 
-       if (nl80211_ht_vht_overrides(msg, params) < 0)
-               return -1;
+       ret = nl80211_ht_vht_overrides(msg, params);
+       if (ret < 0)
+               goto fail;
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
@@ -4648,15 +4956,24 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
        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->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
            nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
                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) ||
+               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;
        }
@@ -4667,6 +4984,22 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
        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;
+       }
+
        return 0;
 }
 
@@ -4680,6 +5013,7 @@ static int wpa_driver_nl80211_try_connect(
        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 ||
@@ -4689,6 +5023,7 @@ static int wpa_driver_nl80211_try_connect(
                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);
@@ -4817,14 +5152,6 @@ static int wpa_driver_nl80211_associate(
        if (ret)
                goto fail;
 
-       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))
-                       goto fail;
-       }
-
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
@@ -4880,6 +5207,9 @@ static int wpa_driver_nl80211_set_mode_impl(
        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;
@@ -5236,6 +5566,8 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
                [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 },
        };
 
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
@@ -5261,10 +5593,23 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
        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]);
@@ -5433,7 +5778,7 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
        return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
                                            IEEE80211_HDRLEN +
                                            sizeof(mgmt.u.deauth), 0, 0, 0, 0,
-                                           0);
+                                           0, NULL, 0);
 }
 
 
@@ -5460,7 +5805,7 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
        return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
                                            IEEE80211_HDRLEN +
                                            sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
-                                           0);
+                                           0, NULL, 0);
 }
 
 
@@ -5475,7 +5820,9 @@ static void dump_ifidx(struct wpa_driver_nl80211_data *drv)
        for (i = 0; i < drv->num_if_indices; i++) {
                if (!drv->if_indices[i])
                        continue;
-               res = os_snprintf(pos, end - pos, " %d", drv->if_indices[i]);
+               res = os_snprintf(pos, end - pos, " %d(%d)",
+                                 drv->if_indices[i],
+                                 drv->if_indices_reason[i]);
                if (os_snprintf_error(end - pos, res))
                        break;
                pos += res;
@@ -5487,14 +5834,16 @@ static void dump_ifidx(struct wpa_driver_nl80211_data *drv)
 }
 
 
-static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
+                     int ifidx_reason)
 {
        int i;
-       int *old;
+       int *old, *old_reason;
 
-       wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
-                  ifidx);
-       if (have_ifidx(drv, ifidx)) {
+       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;
@@ -5502,6 +5851,7 @@ static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
        for (i = 0; i < drv->num_if_indices; i++) {
                if (drv->if_indices[i] == 0) {
                        drv->if_indices[i] = ifidx;
+                       drv->if_indices_reason[i] = ifidx_reason;
                        dump_ifidx(drv);
                        return;
                }
@@ -5512,32 +5862,57 @@ static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
        else
                old = NULL;
 
+       if (drv->if_indices_reason != drv->default_if_indices_reason)
+               old_reason = drv->if_indices_reason;
+       else
+               old_reason = NULL;
+
        drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
                                           sizeof(int));
+       drv->if_indices_reason = os_realloc_array(old_reason,
+                                                 drv->num_if_indices + 1,
+                                                 sizeof(int));
        if (!drv->if_indices) {
                if (!old)
                        drv->if_indices = drv->default_if_indices;
                else
                        drv->if_indices = old;
+       }
+       if (!drv->if_indices_reason) {
+               if (!old_reason)
+                       drv->if_indices_reason = drv->default_if_indices_reason;
+               else
+                       drv->if_indices_reason = old_reason;
+       }
+       if (!drv->if_indices || !drv->if_indices_reason) {
                wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
                           "interfaces");
                wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
                return;
-       } else if (!old)
+       }
+       if (!old)
                os_memcpy(drv->if_indices, drv->default_if_indices,
                          sizeof(drv->default_if_indices));
+       if (!old_reason)
+               os_memcpy(drv->if_indices_reason,
+                         drv->default_if_indices_reason,
+                         sizeof(drv->default_if_indices_reason));
        drv->if_indices[drv->num_if_indices] = ifidx;
+       drv->if_indices_reason[drv->num_if_indices] = ifidx_reason;
        drv->num_if_indices++;
        dump_ifidx(drv);
 }
 
 
-static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+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] == ifidx) {
+               if ((drv->if_indices[i] == ifidx || ifidx == IFIDX_ANY) &&
+                   (drv->if_indices_reason[i] == ifidx_reason ||
+                    ifidx_reason == IFIDX_ANY)) {
                        drv->if_indices[i] = 0;
                        break;
                }
@@ -5546,12 +5921,15 @@ static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 }
 
 
-static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+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] == ifidx)
+               if (drv->if_indices[i] == ifidx &&
+                   (drv->if_indices_reason[i] == ifidx_reason ||
+                    ifidx_reason == IFIDX_ANY))
                        return 1;
 
        return 0;
@@ -5616,7 +5994,7 @@ static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
                return;
        }
 
-       if (have_ifidx(drv, lladdr.sll_ifindex))
+       if (have_ifidx(drv, lladdr.sll_ifindex, IFIDX_ANY))
                drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
 }
 
@@ -5643,7 +6021,7 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
                }
                bss->added_bridge = 1;
                br_ifindex = if_nametoindex(brname);
-               add_ifidx(drv, br_ifindex);
+               add_ifidx(drv, br_ifindex, drv->ifindex);
        }
        bss->br_ifindex = br_ifindex;
 
@@ -5705,7 +6083,15 @@ static void *i802_init(struct hostapd_data *hapd,
                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));
+               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';
        }
@@ -5716,14 +6102,14 @@ static void *i802_init(struct hostapd_data *hapd,
                if (params->bridge[i]) {
                        ifindex = if_nametoindex(params->bridge[i]);
                        if (ifindex)
-                               add_ifidx(drv, 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);
+       add_ifidx(drv, drv->ifindex, IFIDX_ANY);
 
        if (params->num_bridge && params->bridge[0]) {
                if (i802_check_bridge(drv, bss, params->bridge[0],
@@ -5735,7 +6121,7 @@ static void *i802_init(struct hostapd_data *hapd,
 
        if (!br_added && br_ifindex &&
            (params->num_bridge == 0 || !params->bridge[0]))
-               add_ifidx(drv, br_ifindex);
+               add_ifidx(drv, br_ifindex, drv->ifindex);
 
 #ifdef CONFIG_LIBNL3_ROUTE
        if (bss->added_if_into_bridge) {
@@ -5880,7 +6266,8 @@ 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)
+                                    const char *bridge, int use_existing,
+                                    int setup_ap)
 {
        enum nl80211_iftype nlmode;
        struct i802_bss *bss = priv;
@@ -5964,7 +6351,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                os_memcpy(if_addr, new_addr, ETH_ALEN);
        }
 
-       if (type == WPA_IF_AP_BSS) {
+       if (type == WPA_IF_AP_BSS && setup_ap) {
                struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
                if (new_bss == NULL) {
                        if (added)
@@ -6020,7 +6407,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
             nlmode == NL80211_IFTYPE_AP_VLAN ||
             nlmode == NL80211_IFTYPE_WDS ||
             nlmode == NL80211_IFTYPE_MONITOR))
-               add_ifidx(drv, ifidx);
+               add_ifidx(drv, ifidx, IFIDX_ANY);
 
        return 0;
 }
@@ -6040,8 +6427,10 @@ static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
        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);
+                                struct wpa_driver_nl80211_data, list) {
+                       del_ifidx(drv2, ifindex, IFIDX_ANY);
+                       del_ifidx(drv2, IFIDX_ANY, ifindex);
+               }
        }
 
        if (type != WPA_IF_AP_BSS)
@@ -6119,7 +6508,8 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
                                  unsigned int freq, unsigned int wait,
                                  const u8 *buf, size_t buf_len,
                                  u64 *cookie_out, int no_cck, int no_ack,
-                                 int offchanok)
+                                 int offchanok, const u16 *csa_offs,
+                                 size_t csa_offs_len)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
@@ -6139,6 +6529,8 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
             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;
 
@@ -6156,6 +6548,20 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
 
                if (cookie_out)
                        *cookie_out = no_ack ? (u64) -1 : cookie;
+
+               if (drv->num_send_action_cookies == MAX_SEND_ACTION_COOKIES) {
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: Drop oldest pending send action cookie 0x%llx",
+                                  (long long unsigned int)
+                                  drv->send_action_cookies[0]);
+                       os_memmove(&drv->send_action_cookies[0],
+                                  &drv->send_action_cookies[1],
+                                  (MAX_SEND_ACTION_COOKIES - 1) *
+                                  sizeof(u64));
+                       drv->num_send_action_cookies--;
+               }
+               drv->send_action_cookies[drv->num_send_action_cookies] = cookie;
+               drv->num_send_action_cookies++;
        }
 
 fail:
@@ -6198,29 +6604,28 @@ static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
             !drv->use_monitor))
                ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
                                                   0, freq, no_cck, 1,
-                                                  wait_time);
+                                                  wait_time, NULL, 0);
        else
                ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
                                             24 + data_len,
                                             &drv->send_action_cookie,
-                                            no_cck, 0, 1);
+                                            no_cck, 0, 1, NULL, 0);
 
        os_free(buf);
        return ret;
 }
 
 
-static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
+static void nl80211_frame_wait_cancel(struct i802_bss *bss, u64 cookie)
 {
-       struct i802_bss *bss = priv;
        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) drv->send_action_cookie);
+                  (long long unsigned int) cookie);
        if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME_WAIT_CANCEL)) ||
-           nla_put_u64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie)) {
+           nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) {
                nlmsg_free(msg);
                return;
        }
@@ -6232,6 +6637,30 @@ static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
 }
 
 
+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_action_cookie);
+
+       /*
+        * Cancel the other pending TX cookies, if any. This is needed since
+        * the driver may keep a list of all pending offchannel TX operations
+        * and free up the radio only once they have expired or cancelled.
+        */
+       for (i = drv->num_send_action_cookies; i > 0; i--) {
+               cookie = drv->send_action_cookies[i - 1];
+               if (cookie != drv->send_action_cookie)
+                       nl80211_frame_wait_cancel(bss, cookie);
+       }
+       drv->num_send_action_cookies = 0;
+}
+
+
 static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
                                                unsigned int duration)
 {
@@ -6454,9 +6883,13 @@ static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
 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);
 }
 
 
@@ -6529,8 +6962,12 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
 
        os_memset(si, 0, sizeof(*si));
        res = nl80211_get_link_signal(drv, si);
-       if (res != 0)
-               return res;
+       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)
@@ -6545,21 +6982,21 @@ static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
 {
        struct i802_bss *bss = priv;
        return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0,
-                                            0, 0, 0, 0);
+                                            0, 0, 0, 0, NULL, 0);
 }
 
 
 static int nl80211_set_param(void *priv, const char *param)
 {
-       wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", 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")) {
-               struct i802_bss *bss = priv;
-               struct wpa_driver_nl80211_data *drv = bss->drv;
-
                wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
                           "interface");
                drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
@@ -6567,22 +7004,18 @@ static int nl80211_set_param(void *priv, const char *param)
        }
 #endif /* CONFIG_P2P */
 
-       if (os_strstr(param, "use_monitor=1")) {
-               struct i802_bss *bss = priv;
-               struct wpa_driver_nl80211_data *drv = bss->drv;
+       if (os_strstr(param, "use_monitor=1"))
                drv->use_monitor = 1;
-       }
 
        if (os_strstr(param, "force_connect_cmd=1")) {
-               struct i802_bss *bss = priv;
-               struct wpa_driver_nl80211_data *drv = bss->drv;
                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")) {
-               struct i802_bss *bss = priv;
-               struct wpa_driver_nl80211_data *drv = bss->drv;
                drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
                drv->test_use_roc_tx = 1;
        }
@@ -6591,7 +7024,7 @@ static int nl80211_set_param(void *priv, const char *param)
 }
 
 
-static void * nl80211_global_init(void)
+static void * nl80211_global_init(void *ctx)
 {
        struct nl80211_global *global;
        struct netlink_config *cfg;
@@ -6599,6 +7032,7 @@ static void * nl80211_global_init(void)
        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;
@@ -6954,7 +7388,7 @@ static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
        os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
 
        if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
-                                        0, 0) < 0)
+                                        0, 0, NULL, 0) < 0)
                wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
                           "send poll frame");
 }
@@ -7224,6 +7658,19 @@ 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);
 }
 
@@ -7261,11 +7708,13 @@ static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
 
 static int driver_nl80211_send_mlme(void *priv, const u8 *data,
                                    size_t data_len, int noack,
-                                   unsigned int freq)
+                                   unsigned int freq,
+                                   const u16 *csa_offs, size_t csa_offs_len)
 {
        struct i802_bss *bss = priv;
        return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
-                                           freq, 0, 0, 0);
+                                           freq, 0, 0, 0, csa_offs,
+                                           csa_offs_len);
 }
 
 
@@ -7340,7 +7789,7 @@ static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md,
 }
 
 
-const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
+static const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -7495,7 +7944,10 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
                                  "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_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,
@@ -7514,7 +7966,10 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
                                  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_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;
@@ -7557,6 +8012,8 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
        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 width=%d cf1=%d cf2=%d)",
                   settings->cs_count, settings->block_tx,
@@ -7573,21 +8030,57 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
            (drv->nlmode != NL80211_IFTYPE_P2P_GO))
                return -EOPNOTSUPP;
 
-       /* check settings validity */
-       if (!settings->beacon_csa.tail ||
-           ((settings->beacon_csa.tail_len <=
-             settings->counter_offset_beacon) ||
-            (settings->beacon_csa.tail[settings->counter_offset_beacon] !=
-             settings->cs_count)))
+       /*
+        * 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.probe_resp &&
-           ((settings->beacon_csa.probe_resp_len <=
-             settings->counter_offset_presp) ||
-            (settings->beacon_csa.probe_resp[settings->counter_offset_presp] !=
-             settings->cs_count)))
+       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) ||
@@ -7610,11 +8103,13 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
        if (ret)
                goto error;
 
-       if (nla_put_u16(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
-                       settings->counter_offset_beacon) ||
+       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_u16(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
-                        settings->counter_offset_presp)))
+            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);
@@ -7860,6 +8355,7 @@ static int nl80211_set_wowlan(void *priv,
 }
 
 
+#ifdef CONFIG_DRIVER_NL80211_QCA
 static int nl80211_roaming(void *priv, int allowed, const u8 *bssid)
 {
        struct i802_bss *bss = priv;
@@ -7892,6 +8388,7 @@ static int nl80211_roaming(void *priv, int allowed, const u8 *bssid)
 
        return send_and_recv_msgs(drv, msg, NULL, NULL);
 }
+#endif /* CONFIG_DRIVER_NL80211_QCA */
 
 
 static int nl80211_set_mac_addr(void *priv, const u8 *addr)
@@ -7900,6 +8397,9 @@ static int nl80211_set_mac_addr(void *priv, const u8 *addr)
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int new_addr = addr != NULL;
 
+       if (TEST_FAIL())
+               return -1;
+
        if (!addr)
                addr = drv->perm_addr;
 
@@ -7960,6 +8460,46 @@ static int nl80211_put_mesh_id(struct nl_msg *msg, const u8 *mesh_id,
 }
 
 
+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_u32(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)))
+               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)
 {
@@ -7974,7 +8514,8 @@ static int nl80211_join_mesh(struct i802_bss *bss,
            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_beacon_int(msg, params->beacon_int) ||
+           nl80211_put_dtim_period(msg, params->dtim_period))
                goto fail;
 
        wpa_printf(MSG_DEBUG, "  * flags=%08X", params->flags);
@@ -8003,30 +8544,12 @@ static int nl80211_join_mesh(struct i802_bss *bss,
                goto fail;
        nla_nest_end(msg, container);
 
-       container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
-       if (!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;
 
-       if (!(params->conf.flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
-           nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, 0))
-               goto fail;
-       if ((params->conf.flags & WPA_DRIVER_MESH_FLAG_DRIVER_MPM) &&
-           nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
-                       params->max_peer_links))
-               goto fail;
-
-       /*
-        * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
-        * the timer could disconnect stations even in that case.
-        */
-       if (nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
-                       params->conf.peer_link_timeout)) {
-               wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
-               goto fail;
-       }
-
-       nla_nest_end(msg, container);
-
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
@@ -8035,7 +8558,7 @@ static int nl80211_join_mesh(struct i802_bss *bss,
                goto fail;
        }
        ret = 0;
-       bss->freq = params->freq.freq;
+       drv->assoc_freq = bss->freq = params->freq.freq;
        wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
 
 fail:
@@ -8376,6 +8899,8 @@ set_val:
 }
 
 
+#ifdef CONFIG_DRIVER_NL80211_QCA
+
 static int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode)
 {
        switch (hw_mode) {
@@ -8700,6 +9225,215 @@ static int nl80211_set_prob_oper_freq(void *priv, unsigned int freq)
 }
 
 
+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);
+       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);
+}
+
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+
+static int nl80211_write_to_file(const char *name, unsigned int val)
+{
+       int fd, len;
+       char tmp[128];
+
+       fd = open(name, O_RDWR);
+       if (fd < 0) {
+               wpa_printf(MSG_ERROR, "nl80211: Failed to open %s: %s",
+                          name, strerror(errno));
+               return fd;
+       }
+
+       len = os_snprintf(tmp, sizeof(tmp), "%u\n", val);
+       len = write(fd, tmp, len);
+       if (len < 0)
+               wpa_printf(MSG_ERROR, "nl80211: Failed to write to %s: %s",
+                          name, strerror(errno));
+       close(fd);
+
+       return 0;
+}
+
+
+static int nl80211_configure_data_frame_filters(void *priv, u32 filter_flags)
+{
+       struct i802_bss *bss = priv;
+       char path[128];
+       int ret;
+
+       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;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
        .desc = "Linux nl80211/cfg80211",
@@ -8710,6 +9444,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .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,
@@ -8793,7 +9528,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .vendor_cmd = nl80211_vendor_cmd,
        .set_qos_map = nl80211_set_qos_map,
        .set_wowlan = nl80211_set_wowlan,
-       .roaming = nl80211_roaming,
        .set_mac_addr = nl80211_set_mac_addr,
 #ifdef CONFIG_MESH
        .init_mesh = wpa_driver_nl80211_init_mesh,
@@ -8806,8 +9540,17 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .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,
        .do_acs = wpa_driver_do_acs,
        .set_band = nl80211_set_band,
        .get_pref_freq_list = nl80211_get_pref_freq_list,
        .set_prob_oper_freq = nl80211_set_prob_oper_freq,
+       .p2p_lo_start = nl80211_p2p_lo_start,
+       .p2p_lo_stop = nl80211_p2p_lo_stop,
+       .set_default_scan_ies = nl80211_set_default_scan_ies,
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+       .configure_data_frame_filters = nl80211_configure_data_frame_filters,
+       .get_ext_capab = nl80211_get_ext_capab,
 };
index 5c21e0f..d0ec48c 100644 (file)
@@ -25,6 +25,7 @@
 #endif /* CONFIG_LIBNL20 */
 
 struct nl80211_global {
+       void *ctx;
        struct dl_list interfaces;
        int if_add_ifindex;
        u64 if_add_wdevid;
@@ -84,6 +85,7 @@ struct wpa_driver_nl80211_data {
        struct dl_list list;
        struct dl_list wiphy_list;
        char phyname[32];
+       unsigned int wiphy_idx;
        u8 perm_addr[ETH_ALEN];
        void *ctx;
        int ifindex;
@@ -94,6 +96,13 @@ struct wpa_driver_nl80211_data {
        struct wpa_driver_capa capa;
        u8 *extended_capa, *extended_capa_mask;
        unsigned int extended_capa_len;
+       struct drv_nl80211_ext_capa {
+               enum nl80211_iftype iftype;
+               u8 *ext_capa, *ext_capa_mask;
+               unsigned int ext_capa_len;
+       } iface_ext_capa[NL80211_IFTYPE_MAX];
+       unsigned int num_iface_ext_capa;
+
        int has_capability;
 
        int operstate;
@@ -148,9 +157,16 @@ struct wpa_driver_nl80211_data {
        unsigned int setband_vendor_cmd_avail:1;
        unsigned int get_pref_freq_list:1;
        unsigned int set_prob_oper_freq:1;
+       unsigned int scan_vendor_cmd_avail:1;
+       unsigned int connect_reassoc:1;
+       unsigned int set_wifi_conf_vendor_cmd_avail: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;
 
        unsigned int last_mgmt_freq;
 
@@ -166,7 +182,10 @@ struct wpa_driver_nl80211_data {
        struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
 
        int default_if_indices[16];
+       /* the AP/AP_VLAN iface that is in this bridge */
+       int default_if_indices_reason[16];
        int *if_indices;
+       int *if_indices_reason;
        int num_if_indices;
 
        /* From failed authentication command */
@@ -182,6 +201,13 @@ struct wpa_driver_nl80211_data {
        int auth_wep_tx_keyidx;
        int auth_local_state_change;
        int auth_p2p;
+
+       /*
+        * Tells whether the last scan issued from wpa_supplicant was a normal
+        * scan (NL80211_CMD_TRIGGER_SCAN) or a vendor scan
+        * (NL80211_CMD_VENDOR). 0 if no pending scan request.
+        */
+       int last_scan_cmd;
 };
 
 struct nl_msg;
@@ -233,6 +259,8 @@ nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags);
 int process_global_event(struct nl_msg *msg, void *arg);
 int process_bss_event(struct nl_msg *msg, void *arg);
 
+const char * nl80211_iftype_str(enum nl80211_iftype mode);
+
 #ifdef ANDROID
 int android_nl_socket_set_nonblocking(struct nl_handle *handle);
 int android_pno_start(struct i802_bss *bss,
@@ -267,11 +295,13 @@ void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx);
 int wpa_driver_nl80211_scan(struct i802_bss *bss,
                            struct wpa_driver_scan_params *params);
 int wpa_driver_nl80211_sched_scan(void *priv,
-                                 struct wpa_driver_scan_params *params,
-                                 u32 interval);
+                                 struct wpa_driver_scan_params *params);
 int wpa_driver_nl80211_stop_sched_scan(void *priv);
 struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv);
 void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv);
-const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie);
+int wpa_driver_nl80211_abort_scan(void *priv);
+int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss,
+                                  struct wpa_driver_scan_params *params);
+int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len);
 
 #endif /* DRIVER_NL80211_H */
index 4cf3123..6adc3f6 100644 (file)
@@ -66,7 +66,6 @@ struct wiphy_info_data {
        unsigned int device_ap_sme:1;
        unsigned int poll_command_supported:1;
        unsigned int data_tx_status:1;
-       unsigned int monitor_supported:1;
        unsigned int auth_supported:1;
        unsigned int connect_supported:1;
        unsigned int p2p_go_supported:1;
@@ -129,9 +128,6 @@ static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
                case NL80211_IFTYPE_P2P_CLIENT:
                        info->p2p_client_supported = 1;
                        break;
-               case NL80211_IFTYPE_MONITOR:
-                       info->monitor_supported = 1;
-                       break;
                }
        }
 }
@@ -352,13 +348,20 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
                                         struct nlattr *tb)
 {
        struct wpa_driver_capa *capa = info->capa;
+       u8 *ext_features;
+       int len;
 
        if (tb == NULL)
                return;
 
-       if (ext_feature_isset(nla_data(tb), nla_len(tb),
-                             NL80211_EXT_FEATURE_VHT_IBSS))
+       ext_features = nla_data(tb);
+       len = nla_len(tb);
+
+       if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_VHT_IBSS))
                capa->flags |= WPA_DRIVER_FLAGS_VHT_IBSS;
+
+       if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_RRM))
+               capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_RRM;
 }
 
 
@@ -428,6 +431,9 @@ static void wiphy_info_feature_flags(struct wiphy_info_data *info,
 
        if (flags & NL80211_FEATURE_HT_IBSS)
                capa->flags |= WPA_DRIVER_FLAGS_HT_IBSS;
+
+       if (flags & NL80211_FEATURE_FULL_AP_CLIENT_STATE)
+               capa->flags |= WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE;
 }
 
 
@@ -476,6 +482,74 @@ static void wiphy_info_wowlan_triggers(struct wpa_driver_capa *capa,
 }
 
 
+static void wiphy_info_extended_capab(struct wpa_driver_nl80211_data *drv,
+                                     struct nlattr *tb)
+{
+       int rem = 0, i;
+       struct nlattr *tb1[NL80211_ATTR_MAX + 1], *attr;
+
+       if (!tb || drv->num_iface_ext_capa == NL80211_IFTYPE_MAX)
+               return;
+
+       nla_for_each_nested(attr, tb, rem) {
+               unsigned int len;
+               struct drv_nl80211_ext_capa *capa;
+
+               nla_parse(tb1, NL80211_ATTR_MAX, nla_data(attr),
+                         nla_len(attr), NULL);
+
+               if (!tb1[NL80211_ATTR_IFTYPE] ||
+                   !tb1[NL80211_ATTR_EXT_CAPA] ||
+                   !tb1[NL80211_ATTR_EXT_CAPA_MASK])
+                       continue;
+
+               capa = &drv->iface_ext_capa[drv->num_iface_ext_capa];
+               capa->iftype = nla_get_u32(tb1[NL80211_ATTR_IFTYPE]);
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Driver-advertised extended capabilities for interface type %s",
+                          nl80211_iftype_str(capa->iftype));
+
+               len = nla_len(tb1[NL80211_ATTR_EXT_CAPA]);
+               capa->ext_capa = os_malloc(len);
+               if (!capa->ext_capa)
+                       goto err;
+
+               os_memcpy(capa->ext_capa, nla_data(tb1[NL80211_ATTR_EXT_CAPA]),
+                         len);
+               capa->ext_capa_len = len;
+               wpa_hexdump(MSG_DEBUG, "nl80211: Extended capabilities",
+                           capa->ext_capa, capa->ext_capa_len);
+
+               len = nla_len(tb1[NL80211_ATTR_EXT_CAPA_MASK]);
+               capa->ext_capa_mask = os_malloc(len);
+               if (!capa->ext_capa_mask)
+                       goto err;
+
+               os_memcpy(capa->ext_capa_mask,
+                         nla_data(tb1[NL80211_ATTR_EXT_CAPA_MASK]), len);
+               wpa_hexdump(MSG_DEBUG, "nl80211: Extended capabilities mask",
+                           capa->ext_capa_mask, capa->ext_capa_len);
+
+               drv->num_iface_ext_capa++;
+               if (drv->num_iface_ext_capa == NL80211_IFTYPE_MAX)
+                       break;
+       }
+
+       return;
+
+err:
+       /* Cleanup allocated memory on error */
+       for (i = 0; i < NL80211_IFTYPE_MAX; i++) {
+               os_free(drv->iface_ext_capa[i].ext_capa);
+               drv->iface_ext_capa[i].ext_capa = NULL;
+               os_free(drv->iface_ext_capa[i].ext_capa_mask);
+               drv->iface_ext_capa[i].ext_capa_mask = NULL;
+               drv->iface_ext_capa[i].ext_capa_len = 0;
+       }
+       drv->num_iface_ext_capa = 0;
+}
+
+
 static int wiphy_info_handler(struct nl_msg *msg, void *arg)
 {
        struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -487,6 +561,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
 
+       if (tb[NL80211_ATTR_WIPHY])
+               drv->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+
        if (tb[NL80211_ATTR_WIPHY_NAME])
                os_strlcpy(drv->phyname,
                           nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
@@ -499,6 +576,19 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
                capa->max_sched_scan_ssids =
                        nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
 
+       if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS] &&
+           tb[NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL] &&
+           tb[NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS]) {
+               capa->max_sched_scan_plans =
+                       nla_get_u32(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS]);
+
+               capa->max_sched_scan_plan_interval =
+                       nla_get_u32(tb[NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL]);
+
+               capa->max_sched_scan_plan_iterations =
+                       nla_get_u32(tb[NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS]);
+       }
+
        if (tb[NL80211_ATTR_MAX_MATCH_SETS])
                capa->max_match_sets =
                        nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
@@ -550,6 +640,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
                                  nla_len(tb[NL80211_ATTR_EXT_CAPA]));
                        drv->extended_capa_len =
                                nla_len(tb[NL80211_ATTR_EXT_CAPA]);
+                       wpa_hexdump(MSG_DEBUG,
+                                   "nl80211: Driver-advertised extended capabilities (default)",
+                                   drv->extended_capa, drv->extended_capa_len);
                }
                drv->extended_capa_mask =
                        os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
@@ -557,6 +650,10 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
                        os_memcpy(drv->extended_capa_mask,
                                  nla_data(tb[NL80211_ATTR_EXT_CAPA_MASK]),
                                  nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
+                       wpa_hexdump(MSG_DEBUG,
+                                   "nl80211: Driver-advertised extended capabilities mask (default)",
+                                   drv->extended_capa_mask,
+                                   drv->extended_capa_len);
                } else {
                        os_free(drv->extended_capa);
                        drv->extended_capa = NULL;
@@ -564,6 +661,8 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
                }
        }
 
+       wiphy_info_extended_capab(drv, tb[NL80211_ATTR_IFTYPE_EXT_CAPA]);
+
        if (tb[NL80211_ATTR_VENDOR_DATA]) {
                struct nlattr *nl;
                int rem;
@@ -580,6 +679,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
                                case QCA_NL80211_VENDOR_SUBCMD_TEST:
                                        drv->vendor_cmd_test_avail = 1;
                                        break;
+#ifdef CONFIG_DRIVER_NL80211_QCA
                                case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
                                        drv->roaming_vendor_cmd_avail = 1;
                                        break;
@@ -602,6 +702,13 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
                                case QCA_NL80211_VENDOR_SUBCMD_SETBAND:
                                        drv->setband_vendor_cmd_avail = 1;
                                        break;
+                               case QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN:
+                                       drv->scan_vendor_cmd_avail = 1;
+                                       break;
+                               case QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION:
+                                       drv->set_wifi_conf_vendor_cmd_avail = 1;
+                                       break;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
                                }
                        }
 
@@ -633,6 +740,10 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
                capa->max_stations =
                        nla_get_u32(tb[NL80211_ATTR_MAX_AP_ASSOC_STA]);
 
+       if (tb[NL80211_ATTR_MAX_CSA_COUNTERS])
+               capa->max_csa_counters =
+                       nla_get_u8(tb[NL80211_ATTR_MAX_CSA_COUNTERS]);
+
        return NL_SKIP;
 }
 
@@ -689,8 +800,6 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
        if (!drv->capa.max_remain_on_chan)
                drv->capa.max_remain_on_chan = 5000;
 
-       if (info->channel_switch_supported)
-               drv->capa.flags |= WPA_DRIVER_FLAGS_AP_CSA;
        drv->capa.wmm_ac_supported = info->wmm_ac_supported;
 
        drv->capa.mac_addr_rand_sched_scan_supported =
@@ -698,10 +807,24 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
        drv->capa.mac_addr_rand_scan_supported =
                info->mac_addr_rand_scan_supported;
 
+       if (info->channel_switch_supported) {
+               drv->capa.flags |= WPA_DRIVER_FLAGS_AP_CSA;
+               if (!drv->capa.max_csa_counters)
+                       drv->capa.max_csa_counters = 1;
+       }
+
+       if (!drv->capa.max_sched_scan_plans) {
+               drv->capa.max_sched_scan_plans = 1;
+               drv->capa.max_sched_scan_plan_interval = UINT32_MAX;
+               drv->capa.max_sched_scan_plan_iterations = 0;
+       }
+
        return 0;
 }
 
 
+#ifdef CONFIG_DRIVER_NL80211_QCA
+
 static int dfs_info_handler(struct nl_msg *msg, void *arg)
 {
        struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -780,8 +903,12 @@ static int features_info_handler(struct nl_msg *msg, void *arg)
 
                attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS];
                if (attr) {
-                       info->flags = nla_data(attr);
-                       info->flags_len = nla_len(attr);
+                       int len = nla_len(attr);
+                       info->flags = os_malloc(len);
+                       if (info->flags != NULL) {
+                               os_memcpy(info->flags, nla_data(attr), len);
+                               info->flags_len = len;
+                       }
                }
                attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_CONCURRENCY_CAPA];
                if (attr)
@@ -840,8 +967,17 @@ static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
 
        if (check_feature(QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY, &info))
                drv->capa.flags |= WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY;
+
+       if (check_feature(QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS,
+                         &info))
+               drv->capa.flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS;
+       if (check_feature(QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD, &info))
+               drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD;
+       os_free(info.flags);
 }
 
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
 
 int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
 {
@@ -898,21 +1034,8 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
         * If poll command and tx status are supported, mac80211 is new enough
         * to have everything we need to not need monitor interfaces.
         */
-       drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
-
-       if (drv->device_ap_sme && drv->use_monitor) {
-               /*
-                * Non-mac80211 drivers may not support monitor interface.
-                * Make sure we do not get stuck with incorrect capability here
-                * by explicitly testing this.
-                */
-               if (!info.monitor_supported) {
-                       wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
-                                  "with device_ap_sme since no monitor mode "
-                                  "support detected");
-                       drv->use_monitor = 0;
-               }
-       }
+       drv->use_monitor = !info.device_ap_sme &&
+               (!info.poll_command_supported || !info.data_tx_status);
 
        /*
         * If we aren't going to use monitor interfaces, but the
@@ -922,9 +1045,21 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
        if (!drv->use_monitor && !info.data_tx_status)
                drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
 
+#ifdef CONFIG_DRIVER_NL80211_QCA
        qca_nl80211_check_dfs_capa(drv);
        qca_nl80211_get_features(drv);
 
+       /*
+        * To enable offchannel simultaneous support in wpa_supplicant, the
+        * underlying driver needs to support the same along with offchannel TX.
+        * Offchannel TX support is needed since remain_on_channel and
+        * action_tx use some common data structures and hence cannot be
+        * scheduled simultaneously.
+        */
+       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX))
+               drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
        return 0;
 }
 
@@ -933,6 +1068,7 @@ struct phy_info_arg {
        u16 *num_modes;
        struct hostapd_hw_modes *modes;
        int last_mode, last_chan_idx;
+       int failed;
 };
 
 static void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa,
@@ -1050,7 +1186,7 @@ static int phy_info_freqs(struct phy_info_arg *phy_info,
                                   mode->num_channels + new_channels,
                                   sizeof(struct hostapd_channel_data));
        if (!channel)
-               return NL_SKIP;
+               return NL_STOP;
 
        mode->channels = channel;
        mode->num_channels += new_channels;
@@ -1096,7 +1232,7 @@ static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
 
        mode->rates = os_calloc(mode->num_rates, sizeof(int));
        if (!mode->rates)
-               return NL_SKIP;
+               return NL_STOP;
 
        idx = 0;
 
@@ -1125,8 +1261,10 @@ static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
                mode = os_realloc_array(phy_info->modes,
                                        *phy_info->num_modes + 1,
                                        sizeof(*mode));
-               if (!mode)
-                       return NL_SKIP;
+               if (!mode) {
+                       phy_info->failed = 1;
+                       return NL_STOP;
+               }
                phy_info->modes = mode;
 
                mode = &phy_info->modes[*(phy_info->num_modes)];
@@ -1162,11 +1300,12 @@ static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
        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]);
-       if (ret != NL_OK)
-               return ret;
-       ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
-       if (ret != NL_OK)
+       if (ret == NL_OK)
+               ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
+       if (ret != NL_OK) {
+               phy_info->failed = 1;
                return ret;
+       }
 
        return NL_OK;
 }
@@ -1381,7 +1520,7 @@ static void nl80211_reg_rule_sec(struct nlattr *tb[],
 
 
 static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
-                                int end)
+                                int end, int max_bw)
 {
        int c;
 
@@ -1398,6 +1537,32 @@ static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
 
                if (chan->freq - 70 >= start && chan->freq + 10 <= end)
                        chan->flag |= HOSTAPD_CHAN_VHT_70_10;
+
+               if (max_bw >= 160) {
+                       if (chan->freq - 10 >= start && chan->freq + 150 <= end)
+                               chan->flag |= HOSTAPD_CHAN_VHT_10_150;
+
+                       if (chan->freq - 30 >= start && chan->freq + 130 <= end)
+                               chan->flag |= HOSTAPD_CHAN_VHT_30_130;
+
+                       if (chan->freq - 50 >= start && chan->freq + 110 <= end)
+                               chan->flag |= HOSTAPD_CHAN_VHT_50_110;
+
+                       if (chan->freq - 70 >= start && chan->freq + 90 <= end)
+                               chan->flag |= HOSTAPD_CHAN_VHT_70_90;
+
+                       if (chan->freq - 90 >= start && chan->freq + 70 <= end)
+                               chan->flag |= HOSTAPD_CHAN_VHT_90_70;
+
+                       if (chan->freq - 110 >= start && chan->freq + 50 <= end)
+                               chan->flag |= HOSTAPD_CHAN_VHT_110_50;
+
+                       if (chan->freq - 130 >= start && chan->freq + 30 <= end)
+                               chan->flag |= HOSTAPD_CHAN_VHT_130_30;
+
+                       if (chan->freq - 150 >= start && chan->freq + 10 <= end)
+                               chan->flag |= HOSTAPD_CHAN_VHT_150_10;
+               }
        }
 }
 
@@ -1428,7 +1593,7 @@ static void nl80211_reg_rule_vht(struct nlattr *tb[],
                if (!results->modes[m].vht_capab)
                        continue;
 
-               nl80211_set_vht_mode(&results->modes[m], start, end);
+               nl80211_set_vht_mode(&results->modes[m], start, end, max_bw);
        }
 }
 
@@ -1566,6 +1731,7 @@ nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
                .num_modes = num_modes,
                .modes = NULL,
                .last_mode = -1,
+               .failed = 0,
        };
 
        *num_modes = 0;
@@ -1582,6 +1748,16 @@ nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
 
        if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
                nl80211_set_regulatory_flags(drv, &result);
+               if (result.failed) {
+                       int i;
+
+                       for (i = 0; result.modes && i < *num_modes; i++) {
+                               os_free(result.modes[i].channels);
+                               os_free(result.modes[i].rates);
+                       }
+                       os_free(result.modes);
+                       return NULL;
+               }
                return wpa_driver_nl80211_postprocess_modes(result.modes,
                                                            num_modes);
        }
index 7b0f721..762e3ac 100644 (file)
@@ -265,10 +265,12 @@ 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,
                               struct nlattr *resp_ie,
+                              struct nlattr *timed_out,
                               struct nlattr *authorized,
                               struct nlattr *key_replay_ctr,
                               struct nlattr *ptk_kck,
-                              struct nlattr *ptk_kek)
+                              struct nlattr *ptk_kek,
+                              struct nlattr *subnet_status)
 {
        union wpa_event_data event;
        const u8 *ssid;
@@ -284,6 +286,8 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
                return;
        }
 
+       drv->connect_reassoc = 0;
+
        status_code = status ? nla_get_u16(status) : WLAN_STATUS_SUCCESS;
 
        if (cmd == NL80211_CMD_CONNECT) {
@@ -319,6 +323,7 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
                        event.assoc_reject.resp_ies_len = nla_len(resp_ie);
                }
                event.assoc_reject.status_code = status_code;
+               event.assoc_reject.timed_out = timed_out != NULL;
                wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
                return;
        }
@@ -334,9 +339,9 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
                event.assoc_info.req_ies_len = nla_len(req_ie);
 
                if (cmd == NL80211_CMD_ROAM) {
-                       ssid = nl80211_get_ie(event.assoc_info.req_ies,
-                                             event.assoc_info.req_ies_len,
-                                             WLAN_EID_SSID);
+                       ssid = get_ie(event.assoc_info.req_ies,
+                                     event.assoc_info.req_ies_len,
+                                     WLAN_EID_SSID);
                        if (ssid && ssid[1] > 0 && ssid[1] <= 32) {
                                drv->ssid_len = ssid[1];
                                os_memcpy(drv->ssid, ssid + 2, ssid[1]);
@@ -367,6 +372,17 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
                event.assoc_info.ptk_kek_len = nla_len(ptk_kek);
        }
 
+       if (subnet_status) {
+               /*
+                * At least for now, this is only available from
+                * QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS and that
+                * attribute has the same values 0, 1, 2 as are used in the
+                * variable here, so no mapping between different values are
+                * needed.
+                */
+               event.assoc_info.subnet_status = nla_get_u8(subnet_status);
+       }
+
        wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
 }
 
@@ -560,9 +576,10 @@ static void mlme_event_mgmt(struct i802_bss *bss,
                rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq;
        }
        wpa_printf(MSG_DEBUG,
-                  "nl80211: RX frame sa=" MACSTR
+                  "nl80211: RX frame da=" MACSTR " sa=" MACSTR " bssid=" MACSTR
                   " freq=%d ssi_signal=%d fc=0x%x seq_ctrl=0x%x stype=%u (%s) len=%u",
-                  MAC2STR(mgmt->sa), rx_freq, ssi_signal, fc,
+                  MAC2STR(mgmt->da), MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid),
+                  rx_freq, ssi_signal, fc,
                   le_to_host16(mgmt->seq_ctrl), stype, fc2str(fc),
                   (unsigned int) len);
        event.rx_mgmt.frame = frame;
@@ -639,10 +656,39 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
                         * Avoid issues with some roaming cases where
                         * disconnection event for the old AP may show up after
                         * we have started connection with the new AP.
+                        * In case of locally generated event clear
+                        * ignore_next_local_deauth as well, to avoid next local
+                        * deauth event be wrongly ignored.
                         */
-                       wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR,
-                                  MAC2STR(bssid),
-                                  MAC2STR(drv->auth_attempt_bssid));
+                       if (!os_memcmp(mgmt->sa, drv->first_bss->addr,
+                                      ETH_ALEN)) {
+                               wpa_printf(MSG_DEBUG,
+                                          "nl80211: Received a locally generated deauth event. Clear ignore_next_local_deauth flag");
+                               drv->ignore_next_local_deauth = 0;
+                       } else {
+                               wpa_printf(MSG_DEBUG,
+                                          "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR,
+                                          MAC2STR(bssid),
+                                          MAC2STR(drv->auth_attempt_bssid));
+                       }
+                       return;
+               }
+
+               if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+                   drv->connect_reassoc && drv->associated &&
+                   os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0 &&
+                   os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0) {
+                       /*
+                        * Avoid issues with some roaming cases where
+                        * disconnection event for the old AP may show up after
+                        * we have started connection with the new AP.
+                        */
+                        wpa_printf(MSG_DEBUG,
+                                   "nl80211: Ignore deauth/disassoc event from old AP "
+                                   MACSTR
+                                   " when already connecting with " MACSTR,
+                                   MAC2STR(bssid),
+                                   MAC2STR(drv->auth_attempt_bssid));
                        return;
                }
 
@@ -679,13 +725,15 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
                                mgmt->u.disassoc.variable;
                }
        } else {
+               event.deauth_info.locally_generated =
+                       !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
                if (drv->ignore_deauth_event) {
                        wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event due to previous forced deauth-during-auth");
                        drv->ignore_deauth_event = 0;
+                       if (event.deauth_info.locally_generated)
+                               drv->ignore_next_local_deauth = 0;
                        return;
                }
-               event.deauth_info.locally_generated =
-                       !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
                if (drv->ignore_next_local_deauth) {
                        drv->ignore_next_local_deauth = 0;
                        if (event.deauth_info.locally_generated) {
@@ -868,6 +916,7 @@ static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
                                 struct nlattr *tb[])
 {
        unsigned int freq;
+       union wpa_event_data event;
 
        if (tb[NL80211_ATTR_MAC] == NULL) {
                wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
@@ -887,7 +936,10 @@ static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
                drv->first_bss->freq = freq;
        }
 
-       wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+       os_memset(&event, 0, sizeof(event));
+       event.assoc_info.freq = freq;
+
+       wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
 }
 
 
@@ -968,7 +1020,7 @@ static void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv,
 
 
 static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
-                           struct nlattr *tb[])
+                           struct nlattr *tb[], int external_scan)
 {
        union wpa_event_data event;
        struct nlattr *nl;
@@ -978,7 +1030,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
        int freqs[MAX_REPORT_FREQS];
        int num_freqs = 0;
 
-       if (drv->scan_for_auth) {
+       if (!external_scan && drv->scan_for_auth) {
                drv->scan_for_auth = 0;
                wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
                           "cfg80211 BSS entry");
@@ -989,6 +1041,8 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
        os_memset(&event, 0, sizeof(event));
        info = &event.scan_info;
        info->aborted = aborted;
+       info->external_scan = external_scan;
+       info->nl_scan_event = 1;
 
        if (tb[NL80211_ATTR_SCAN_SSIDS]) {
                nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) {
@@ -1004,7 +1058,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
                }
        }
        if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
-               char msg[200], *pos, *end;
+               char msg[300], *pos, *end;
                int res;
 
                pos = msg;
@@ -1109,7 +1163,7 @@ static void nl80211_new_peer_candidate(struct wpa_driver_nl80211_data *drv,
                return;
 
        addr = nla_data(tb[NL80211_ATTR_MAC]);
-       wpa_printf(MSG_DEBUG, "nl80211: New peer candidate" MACSTR,
+       wpa_printf(MSG_DEBUG, "nl80211: New peer candidate " MACSTR,
                   MAC2STR(addr));
 
        os_memset(&data, 0, sizeof(data));
@@ -1154,6 +1208,7 @@ static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
 
 
 static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
+                                     struct i802_bss *bss,
                                      struct nlattr **tb)
 {
        u8 *addr;
@@ -1166,7 +1221,7 @@ static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
                   MAC2STR(addr));
 
        if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
-               drv_event_disassoc(drv->ctx, addr);
+               drv_event_disassoc(bss->ctx, addr);
                return;
        }
 
@@ -1175,7 +1230,7 @@ static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
 
        os_memset(&data, 0, sizeof(data));
        os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN);
-       wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data);
+       wpa_supplicant_event(bss->ctx, EVENT_IBSS_PEER_LOST, &data);
 }
 
 
@@ -1444,6 +1499,8 @@ static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
 }
 
 
+#ifdef CONFIG_DRIVER_NL80211_QCA
+
 static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
                                   const u8 *data, size_t len)
 {
@@ -1593,10 +1650,12 @@ static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv,
                           tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID],
                           tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE],
                           tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE],
+                          NULL,
                           tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED],
                           tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR],
                           tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK],
-                          tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK]);
+                          tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK],
+                          tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS]);
 }
 
 
@@ -1686,6 +1745,165 @@ static void qca_nl80211_dfs_offload_radar_event(
 }
 
 
+static void qca_nl80211_scan_trigger_event(struct wpa_driver_nl80211_data *drv,
+                                          u8 *data, size_t len)
+{
+       struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1];
+       u64 cookie = 0;
+       union wpa_event_data event;
+       struct scan_info *info;
+
+       if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX,
+                     (struct nlattr *) data, len, NULL) ||
+           !tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE])
+               return;
+
+       cookie = nla_get_u64(tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]);
+       if (cookie != drv->vendor_scan_cookie) {
+               /* External scan trigger event, ignore */
+               return;
+       }
+
+       /* Cookie match, own scan */
+       os_memset(&event, 0, sizeof(event));
+       info = &event.scan_info;
+       info->external_scan = 0;
+       info->nl_scan_event = 0;
+
+       drv->scan_state = SCAN_STARTED;
+       wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, &event);
+}
+
+
+static void send_vendor_scan_event(struct wpa_driver_nl80211_data *drv,
+                                  int aborted, struct nlattr *tb[],
+                                  int external_scan)
+{
+       union wpa_event_data event;
+       struct nlattr *nl;
+       int rem;
+       struct scan_info *info;
+       int freqs[MAX_REPORT_FREQS];
+       int num_freqs = 0;
+
+       os_memset(&event, 0, sizeof(event));
+       info = &event.scan_info;
+       info->aborted = aborted;
+       info->external_scan = external_scan;
+
+       if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS]) {
+               nla_for_each_nested(nl,
+                                   tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS], rem) {
+                       struct wpa_driver_scan_ssid *s =
+                               &info->ssids[info->num_ssids];
+                       s->ssid = nla_data(nl);
+                       s->ssid_len = nla_len(nl);
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: Scan probed for SSID '%s'",
+                                  wpa_ssid_txt(s->ssid, s->ssid_len));
+                       info->num_ssids++;
+                       if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
+                               break;
+               }
+       }
+
+       if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) {
+               char msg[300], *pos, *end;
+               int res;
+
+               pos = msg;
+               end = pos + sizeof(msg);
+               *pos = '\0';
+
+               nla_for_each_nested(nl,
+                                   tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES],
+                                   rem) {
+                       freqs[num_freqs] = nla_get_u32(nl);
+                       res = os_snprintf(pos, end - pos, " %d",
+                                         freqs[num_freqs]);
+                       if (!os_snprintf_error(end - pos, res))
+                               pos += res;
+                       num_freqs++;
+                       if (num_freqs == MAX_REPORT_FREQS - 1)
+                               break;
+               }
+
+               info->freqs = freqs;
+               info->num_freqs = num_freqs;
+               wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s",
+                          msg);
+       }
+       wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
+}
+
+
+static void qca_nl80211_scan_done_event(struct wpa_driver_nl80211_data *drv,
+                                       u8 *data, size_t len)
+{
+       struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1];
+       u64 cookie = 0;
+       enum scan_status status;
+       int external_scan;
+
+       if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX,
+                     (struct nlattr *) data, len, NULL) ||
+           !tb[QCA_WLAN_VENDOR_ATTR_SCAN_STATUS] ||
+           !tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE])
+               return;
+
+       status = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_SCAN_STATUS]);
+       if (status >= VENDOR_SCAN_STATUS_MAX)
+               return; /* invalid status */
+
+       cookie = nla_get_u64(tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]);
+       if (cookie != drv->vendor_scan_cookie) {
+               /* Event from an external scan, get scan results */
+               external_scan = 1;
+       } else {
+               external_scan = 0;
+               if (status == VENDOR_SCAN_STATUS_NEW_RESULTS)
+                       drv->scan_state = SCAN_COMPLETED;
+               else
+                       drv->scan_state = SCAN_ABORTED;
+
+               eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+                                    drv->ctx);
+               drv->vendor_scan_cookie = 0;
+               drv->last_scan_cmd = 0;
+       }
+
+       send_vendor_scan_event(drv, (status == VENDOR_SCAN_STATUS_ABORTED), tb,
+                              external_scan);
+}
+
+
+static void qca_nl80211_p2p_lo_stop_event(struct wpa_driver_nl80211_data *drv,
+                                         u8 *data, size_t len)
+{
+       struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX + 1];
+       union wpa_event_data event;
+
+       wpa_printf(MSG_DEBUG,
+                  "nl80211: P2P listen offload stop vendor event received");
+
+       if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX,
+                     (struct nlattr *) data, len, NULL) ||
+           !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON])
+               return;
+
+       os_memset(&event, 0, sizeof(event));
+       event.p2p_lo_stop.reason_code =
+               nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON]);
+
+       wpa_printf(MSG_DEBUG,
+                  "nl80211: P2P Listen offload stop reason: %d",
+                  event.p2p_lo_stop.reason_code);
+       wpa_supplicant_event(drv->ctx, EVENT_P2P_LO_STOP, &event);
+}
+
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+
 static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
                                     u32 subcmd, u8 *data, size_t len)
 {
@@ -1693,6 +1911,7 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
        case QCA_NL80211_VENDOR_SUBCMD_TEST:
                wpa_hexdump(MSG_DEBUG, "nl80211: QCA test event", data, len);
                break;
+#ifdef CONFIG_DRIVER_NL80211_QCA
        case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
                qca_nl80211_avoid_freq(drv, data, len);
                break;
@@ -1709,6 +1928,16 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
        case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED:
                qca_nl80211_dfs_offload_radar_event(drv, subcmd, data, len);
                break;
+       case QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN:
+               qca_nl80211_scan_trigger_event(drv, data, len);
+               break;
+       case QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE:
+               qca_nl80211_scan_done_event(drv, data, len);
+               break;
+       case QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP:
+               qca_nl80211_p2p_lo_stop_event(drv, data, len);
+               break;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
        default:
                wpa_printf(MSG_DEBUG,
                           "nl80211: Ignore unsupported QCA vendor event %u",
@@ -1831,6 +2060,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
        union wpa_event_data data;
+       int external_scan_event = 0;
 
        wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
                   cmd, nl80211_command_to_string(cmd), bss->ifname);
@@ -1883,28 +2113,38 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
        case NL80211_CMD_NEW_SCAN_RESULTS:
                wpa_dbg(drv->ctx, MSG_DEBUG,
                        "nl80211: New scan results available");
-               drv->scan_state = SCAN_COMPLETED;
                drv->scan_complete_events = 1;
-               eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
-                                    drv->ctx);
-               send_scan_event(drv, 0, tb);
+               if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) {
+                       drv->scan_state = SCAN_COMPLETED;
+                       eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout,
+                                            drv, drv->ctx);
+                       drv->last_scan_cmd = 0;
+               } else {
+                       external_scan_event = 1;
+               }
+               send_scan_event(drv, 0, tb, external_scan_event);
                break;
        case NL80211_CMD_SCHED_SCAN_RESULTS:
                wpa_dbg(drv->ctx, MSG_DEBUG,
                        "nl80211: New sched scan results available");
                drv->scan_state = SCHED_SCAN_RESULTS;
-               send_scan_event(drv, 0, tb);
+               send_scan_event(drv, 0, tb, 0);
                break;
        case NL80211_CMD_SCAN_ABORTED:
                wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
-               drv->scan_state = SCAN_ABORTED;
-               /*
-                * Need to indicate that scan results are available in order
-                * not to make wpa_supplicant stop its scanning.
-                */
-               eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
-                                    drv->ctx);
-               send_scan_event(drv, 1, tb);
+               if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) {
+                       drv->scan_state = SCAN_ABORTED;
+                       /*
+                        * Need to indicate that scan results are available in
+                        * order not to make wpa_supplicant stop its scanning.
+                        */
+                       eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout,
+                                            drv, drv->ctx);
+                       drv->last_scan_cmd = 0;
+               } else {
+                       external_scan_event = 1;
+               }
+               send_scan_event(drv, 1, tb, external_scan_event);
                break;
        case NL80211_CMD_AUTHENTICATE:
        case NL80211_CMD_ASSOCIATE:
@@ -1927,7 +2167,8 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
                                   tb[NL80211_ATTR_MAC],
                                   tb[NL80211_ATTR_REQ_IE],
                                   tb[NL80211_ATTR_RESP_IE],
-                                  NULL, NULL, NULL, NULL);
+                                  tb[NL80211_ATTR_TIMED_OUT],
+                                  NULL, NULL, NULL, NULL, NULL);
                break;
        case NL80211_CMD_CH_SWITCH_NOTIFY:
                mlme_event_ch_switch(drv,
@@ -1972,7 +2213,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
                nl80211_new_station_event(drv, bss, tb);
                break;
        case NL80211_CMD_DEL_STATION:
-               nl80211_del_station_event(drv, tb);
+               nl80211_del_station_event(drv, bss, tb);
                break;
        case NL80211_CMD_SET_REKEY_OFFLOAD:
                nl80211_rekey_offload_event(drv, tb);
index 45385da..9376d11 100644 (file)
@@ -136,7 +136,7 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
                        break;
                case IEEE80211_RADIOTAP_TX_FLAGS:
                        injected = 1;
-                       failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
+                       failed = le_to_host16((*(le16 *) iter.this_arg)) &
                                        IEEE80211_RADIOTAP_F_TX_FAIL;
                        break;
                case IEEE80211_RADIOTAP_DATA_RETRIES:
index 4b762ea..c115b6b 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Driver interaction with Linux nl80211/cfg80211 - Scanning
+ * Copyright(c) 2015 Intel Deutschland GmbH
  * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
  * Copyright (c) 2009-2010, Atheros Communications
@@ -14,6 +15,8 @@
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/qca-vendor.h"
 #include "driver_nl80211.h"
 
 
@@ -93,12 +96,20 @@ static int nl80211_get_noise_for_scan_results(
 void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_driver_nl80211_data *drv = eloop_ctx;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Scan timeout - try to abort it");
+       if (!wpa_driver_nl80211_abort_scan(drv->first_bss))
+               return;
+
+       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;
        }
-       wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+
+       wpa_printf(MSG_DEBUG, "nl80211: Try to get scan results");
        wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
 }
 
@@ -131,6 +142,8 @@ nl80211_scan_common(struct i802_bss *bss, u8 cmd,
                                goto fail;
                }
                nla_nest_end(msg, ssids);
+       } else {
+               wpa_printf(MSG_DEBUG, "nl80211: Passive scan requested");
        }
 
        if (params->extra_ies) {
@@ -252,6 +265,13 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss,
                        goto fail;
        }
 
+       if (params->bssid) {
+               wpa_printf(MSG_DEBUG, "nl80211: Scan for a specific BSSID: "
+                          MACSTR, MAC2STR(params->bssid));
+               if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
+                       goto fail;
+       }
+
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
@@ -297,6 +317,7 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss,
        eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
        eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
                               drv, drv->ctx);
+       drv->last_scan_cmd = NL80211_CMD_TRIGGER_SCAN;
 
 fail:
        nlmsg_free(msg);
@@ -304,16 +325,82 @@ fail:
 }
 
 
+static int
+nl80211_sched_scan_add_scan_plans(struct wpa_driver_nl80211_data *drv,
+                                 struct nl_msg *msg,
+                                 struct wpa_driver_scan_params *params)
+{
+       struct nlattr *plans;
+       struct sched_scan_plan *scan_plans = params->sched_scan_plans;
+       unsigned int i;
+
+       plans = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_PLANS);
+       if (!plans)
+               return -1;
+
+       for (i = 0; i < params->sched_scan_plans_num; i++) {
+               struct nlattr *plan = nla_nest_start(msg, i + 1);
+
+               if (!plan)
+                       return -1;
+
+               if (!scan_plans[i].interval ||
+                   scan_plans[i].interval >
+                   drv->capa.max_sched_scan_plan_interval) {
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: sched scan plan no. %u: Invalid interval: %u",
+                                  i, scan_plans[i].interval);
+                       return -1;
+               }
+
+               if (nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL,
+                               scan_plans[i].interval))
+                       return -1;
+
+               if (scan_plans[i].iterations >
+                   drv->capa.max_sched_scan_plan_iterations) {
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: sched scan plan no. %u: Invalid number of iterations: %u",
+                                  i, scan_plans[i].iterations);
+                       return -1;
+               }
+
+               if (scan_plans[i].iterations &&
+                   nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_ITERATIONS,
+                               scan_plans[i].iterations))
+                       return -1;
+
+               nla_nest_end(msg, plan);
+
+               /*
+                * All the scan plans must specify the number of iterations
+                * except the last plan, which will run infinitely. So if the
+                * number of iterations is not specified, this ought to be the
+                * last scan plan.
+                */
+               if (!scan_plans[i].iterations)
+                       break;
+       }
+
+       if (i != params->sched_scan_plans_num - 1) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: All sched scan plans but the last must specify number of iterations");
+               return -1;
+       }
+
+       nla_nest_end(msg, plans);
+       return 0;
+}
+
+
 /**
  * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
  * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
  * @params: Scan parameters
- * @interval: Interval between scan cycles in milliseconds
  * Returns: 0 on success, -1 on failure or if not supported
  */
 int wpa_driver_nl80211_sched_scan(void *priv,
-                                 struct wpa_driver_scan_params *params,
-                                 u32 interval)
+                                 struct wpa_driver_scan_params *params)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -328,11 +415,27 @@ int wpa_driver_nl80211_sched_scan(void *priv,
                return android_pno_start(bss, params);
 #endif /* ANDROID */
 
+       if (!params->sched_scan_plans_num ||
+           params->sched_scan_plans_num > drv->capa.max_sched_scan_plans) {
+               wpa_printf(MSG_ERROR,
+                          "nl80211: Invalid number of sched scan plans: %u",
+                          params->sched_scan_plans_num);
+               return -1;
+       }
+
        msg = nl80211_scan_common(bss, NL80211_CMD_START_SCHED_SCAN, params);
-       if (!msg ||
-           nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval))
+       if (!msg)
                goto fail;
 
+       if (drv->capa.max_sched_scan_plan_iterations) {
+               if (nl80211_sched_scan_add_scan_plans(drv, msg, params))
+                       goto fail;
+       } else {
+               if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL,
+                               params->sched_scan_plans[0].interval * 1000))
+                       goto fail;
+       }
+
        if ((drv->num_filter_ssids &&
            (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
            params->filter_rssi) {
@@ -395,8 +498,7 @@ int wpa_driver_nl80211_sched_scan(void *priv,
                goto fail;
        }
 
-       wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
-                  "scan interval %d msec", ret, interval);
+       wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d)", ret);
 
 fail:
        nlmsg_free(msg);
@@ -436,28 +538,6 @@ int wpa_driver_nl80211_stop_sched_scan(void *priv)
 }
 
 
-const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
-{
-       const u8 *end, *pos;
-
-       if (ies == NULL)
-               return NULL;
-
-       pos = ies;
-       end = ies + ies_len;
-
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
-                       break;
-               if (pos[0] == ie)
-                       return pos;
-               pos += 2 + pos[1];
-       }
-
-       return NULL;
-}
-
-
 static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
                                 const u8 *ie, size_t ie_len)
 {
@@ -467,7 +547,7 @@ static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
        if (drv->filter_ssids == NULL)
                return 0;
 
-       ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
+       ssid = get_ie(ie, ie_len, WLAN_EID_SSID);
        if (ssid == NULL)
                return 1;
 
@@ -628,9 +708,9 @@ int bss_info_handler(struct nl_msg *msg, void *arg)
                if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
                        continue;
 
-               s1 = nl80211_get_ie((u8 *) (res->res[i] + 1),
-                                   res->res[i]->ie_len, WLAN_EID_SSID);
-               s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
+               s1 = get_ie((u8 *) (res->res[i] + 1),
+                           res->res[i]->ie_len, WLAN_EID_SSID);
+               s2 = get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
                if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
                    os_memcmp(s1, s2, 2 + s1[1]) != 0)
                        continue;
@@ -781,3 +861,263 @@ void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
 
        wpa_scan_results_free(res);
 }
+
+
+int wpa_driver_nl80211_abort_scan(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       int ret;
+       struct nl_msg *msg;
+
+       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);
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: Abort scan failed: ret=%d (%s)",
+                          ret, strerror(-ret));
+       }
+
+       return ret;
+}
+
+
+#ifdef CONFIG_DRIVER_NL80211_QCA
+
+static int scan_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_VENDOR_DATA]) {
+               struct nlattr *nl_vendor = tb[NL80211_ATTR_VENDOR_DATA];
+               struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1];
+
+               nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_SCAN_MAX,
+                         nla_data(nl_vendor), nla_len(nl_vendor), NULL);
+
+               if (tb_vendor[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE])
+                       *cookie = nla_get_u64(
+                               tb_vendor[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]);
+       }
+
+       return NL_SKIP;
+}
+
+
+/**
+ * wpa_driver_nl80211_vendor_scan - Request the driver to initiate a vendor scan
+ * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss,
+                                  struct wpa_driver_scan_params *params)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg = NULL;
+       struct nlattr *attr;
+       size_t i;
+       u32 scan_flags = 0;
+       int ret = -1;
+       u64 cookie = 0;
+
+       wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: vendor scan request");
+       drv->scan_for_auth = 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_TRIGGER_SCAN) )
+               goto fail;
+
+       attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+       if (attr == NULL)
+               goto fail;
+
+       if (params->num_ssids) {
+               struct nlattr *ssids;
+
+               ssids = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS);
+               if (ssids == NULL)
+                       goto fail;
+               for (i = 0; i < params->num_ssids; i++) {
+                       wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
+                                       params->ssids[i].ssid,
+                                       params->ssids[i].ssid_len);
+                       if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
+                                   params->ssids[i].ssid))
+                               goto fail;
+               }
+               nla_nest_end(msg, ssids);
+       }
+
+       if (params->extra_ies) {
+               wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
+                           params->extra_ies, params->extra_ies_len);
+               if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SCAN_IE,
+                           params->extra_ies_len, params->extra_ies))
+                       goto fail;
+       }
+
+       if (params->freqs) {
+               struct nlattr *freqs;
+
+               freqs = nla_nest_start(msg,
+                                      QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES);
+               if (freqs == NULL)
+                       goto fail;
+               for (i = 0; params->freqs[i]; i++) {
+                       wpa_printf(MSG_MSGDUMP,
+                                  "nl80211: Scan frequency %u MHz",
+                                  params->freqs[i]);
+                       if (nla_put_u32(msg, i + 1, params->freqs[i]))
+                               goto fail;
+               }
+               nla_nest_end(msg, freqs);
+       }
+
+       os_free(drv->filter_ssids);
+       drv->filter_ssids = params->filter_ssids;
+       params->filter_ssids = NULL;
+       drv->num_filter_ssids = params->num_filter_ssids;
+
+       if (params->low_priority && drv->have_low_prio_scan) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY");
+               scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
+       }
+
+       if (params->mac_addr_rand) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Add NL80211_SCAN_FLAG_RANDOM_ADDR");
+               scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
+
+               if (params->mac_addr) {
+                       wpa_printf(MSG_DEBUG, "nl80211: MAC address: " MACSTR,
+                                  MAC2STR(params->mac_addr));
+                       if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SCAN_MAC,
+                                   ETH_ALEN, params->mac_addr))
+                               goto fail;
+               }
+
+               if (params->mac_addr_mask) {
+                       wpa_printf(MSG_DEBUG, "nl80211: MAC address mask: "
+                                  MACSTR, MAC2STR(params->mac_addr_mask));
+                       if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK,
+                                   ETH_ALEN, params->mac_addr_mask))
+                               goto fail;
+               }
+       }
+
+       if (scan_flags &&
+           nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
+               goto fail;
+
+       if (params->p2p_probe) {
+               struct nlattr *rates;
+
+               wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
+
+               rates = nla_nest_start(msg,
+                                      QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES);
+               if (rates == NULL)
+                       goto fail;
+
+               /*
+                * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
+                * by masking out everything else apart from the OFDM rates 6,
+                * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
+                * rates are left enabled.
+                */
+               if (nla_put(msg, NL80211_BAND_2GHZ, 8,
+                           "\x0c\x12\x18\x24\x30\x48\x60\x6c"))
+                       goto fail;
+               nla_nest_end(msg, rates);
+
+               if (nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE))
+                       goto fail;
+       }
+
+       nla_nest_end(msg, attr);
+
+       ret = send_and_recv_msgs(drv, msg, scan_cookie_handler, &cookie);
+       msg = NULL;
+       if (ret) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Vendor scan trigger failed: ret=%d (%s)",
+                          ret, strerror(-ret));
+               goto fail;
+       }
+
+       drv->vendor_scan_cookie = cookie;
+       drv->scan_state = SCAN_REQUESTED;
+
+       wpa_printf(MSG_DEBUG,
+                  "nl80211: Vendor scan requested (ret=%d) - scan timeout 30 seconds, scan cookie:0x%llx",
+                  ret, (long long unsigned int) cookie);
+       eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+       eloop_register_timeout(30, 0, wpa_driver_nl80211_scan_timeout,
+                              drv, drv->ctx);
+       drv->last_scan_cmd = NL80211_CMD_VENDOR;
+
+fail:
+       nlmsg_free(msg);
+       return ret;
+}
+
+
+/**
+ * nl80211_set_default_scan_ies - Set the scan default IEs to the driver
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @ies: Pointer to IEs buffer
+ * @ies_len: Length of IEs in bytes
+ * Returns: 0 on success, -1 on failure
+ */
+int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg = NULL;
+       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 == NULL)
+               goto fail;
+
+       wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan default IEs", ies, ies_len);
+       if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES,
+                   ies_len, ies))
+               goto fail;
+
+       nla_nest_end(msg, attr);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
+       if (ret) {
+               wpa_printf(MSG_ERROR,
+                          "nl80211: Set scan default IEs failed: ret=%d (%s)",
+                          ret, strerror(-ret));
+               goto fail;
+       }
+
+fail:
+       nlmsg_free(msg);
+       return ret;
+}
+
+#endif /* CONFIG_DRIVER_NL80211_QCA */
index 1f1676a..43d4193 100644 (file)
@@ -161,11 +161,11 @@ wpa_driver_privsep_get_scan_results2(void *priv)
                return NULL;
        }
 
-       while (results->num < (size_t) num && pos + sizeof(int) < end) {
+       while (results->num < (size_t) num && end - pos > (int) sizeof(int)) {
                int len;
                os_memcpy(&len, pos, sizeof(int));
                pos += sizeof(int);
-               if (len < 0 || len > 10000 || pos + len > end)
+               if (len < 0 || len > 10000 || len > end - pos)
                        break;
 
                r = os_malloc(len);
index d3e0595..e8a5135 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - roboswitch driver interface
- * Copyright (c) 2008-2009 Jouke Witteveen
+ * Copyright (c) 2008-2012 Jouke Witteveen
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -401,7 +401,9 @@ static void * wpa_driver_roboswitch_init(void *ctx, const char *ifname)
                os_free(drv);
                return NULL;
        }
-       if (if_mii(&drv->ifr)->phy_id != ROBO_PHY_ADDR) {
+       /* 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);
index 01defdf..791cd5d 100644 (file)
@@ -422,7 +422,7 @@ static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv)
 
 
 static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
-                                          char *data, int len)
+                                          char *data, unsigned int len)
 {
        struct iw_event iwe_buf, *iwe = &iwe_buf;
        char *pos, *end, *custom, *buf;
@@ -430,13 +430,13 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
        pos = data;
        end = data + len;
 
-       while (pos + IW_EV_LCP_LEN <= end) {
+       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)
+               if (iwe->len <= IW_EV_LCP_LEN || iwe->len > end - pos)
                        return;
 
                custom = pos + IW_EV_POINT_LEN;
@@ -480,7 +480,7 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
                        }
                        break;
                case IWEVMICHAELMICFAILURE:
-                       if (custom + iwe->u.data.length > end) {
+                       if (iwe->u.data.length > end - custom) {
                                wpa_printf(MSG_DEBUG, "WEXT: Invalid "
                                           "IWEVMICHAELMICFAILURE length");
                                return;
@@ -489,7 +489,7 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
                                drv->ctx, custom, iwe->u.data.length);
                        break;
                case IWEVCUSTOM:
-                       if (custom + iwe->u.data.length > end) {
+                       if (iwe->u.data.length > end - custom) {
                                wpa_printf(MSG_DEBUG, "WEXT: Invalid "
                                           "IWEVCUSTOM length");
                                return;
@@ -508,7 +508,7 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
                                             NULL);
                        break;
                case IWEVASSOCREQIE:
-                       if (custom + iwe->u.data.length > end) {
+                       if (iwe->u.data.length > end - custom) {
                                wpa_printf(MSG_DEBUG, "WEXT: Invalid "
                                           "IWEVASSOCREQIE length");
                                return;
@@ -517,7 +517,7 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
                                drv, custom, iwe->u.data.length);
                        break;
                case IWEVASSOCRESPIE:
-                       if (custom + iwe->u.data.length > end) {
+                       if (iwe->u.data.length > end - custom) {
                                wpa_printf(MSG_DEBUG, "WEXT: Invalid "
                                           "IWEVASSOCRESPIE length");
                                return;
@@ -526,7 +526,7 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
                                drv, custom, iwe->u.data.length);
                        break;
                case IWEVPMKIDCAND:
-                       if (custom + iwe->u.data.length > end) {
+                       if (iwe->u.data.length > end - custom) {
                                wpa_printf(MSG_DEBUG, "WEXT: Invalid "
                                           "IWEVPMKIDCAND length");
                                return;
@@ -1220,7 +1220,7 @@ static void wext_get_scan_ssid(struct iw_event *iwe,
                               char *end)
 {
        int ssid_len = iwe->u.essid.length;
-       if (custom + ssid_len > end)
+       if (ssid_len > end - custom)
                return;
        if (iwe->u.essid.flags &&
            ssid_len > 0 &&
@@ -1316,7 +1316,7 @@ static void wext_get_scan_rate(struct iw_event *iwe,
        size_t clen;
 
        clen = iwe->len;
-       if (custom + clen > end)
+       if (clen > (size_t) (end - custom))
                return;
        maxrate = 0;
        while (((ssize_t) clen) >= (ssize_t) sizeof(struct iw_param)) {
@@ -1369,7 +1369,7 @@ static void wext_get_scan_custom(struct iw_event *iwe,
        u8 *tmp;
 
        clen = iwe->u.data.length;
-       if (custom + clen > end)
+       if (clen > (size_t) (end - custom))
                return;
 
        if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0) {
@@ -1441,8 +1441,8 @@ static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res,
        /* Figure out whether we need to fake any IEs */
        pos = data->ie;
        end = pos + data->ie_len;
-       while (pos && pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
+       while (pos && end - pos > 1) {
+               if (2 + pos[1] > end - pos)
                        break;
                if (pos[0] == WLAN_EID_SSID)
                        ssid_ie = pos;
@@ -1530,11 +1530,11 @@ struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv)
        end = (char *) res_buf + len;
        os_memset(&data, 0, sizeof(data));
 
-       while (pos + IW_EV_LCP_LEN <= end) {
+       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)
+               if (iwe->len <= IW_EV_LCP_LEN || iwe->len > end - pos)
                        break;
 
                custom = pos + IW_EV_POINT_LEN;
index f95f3cc..422a220 100644 (file)
@@ -8,12 +8,17 @@
  */
 
 #include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "driver.h"
+
 #include <sys/ioctl.h>
+#undef IFNAMSIZ
 #include <net/if.h>
 #ifdef __linux__
 #include <netpacket/packet.h>
 #include <net/if_arp.h>
-#include <net/if.h>
 #endif /* __linux__ */
 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
 #include <net/if_dl.h>
 #include <sys/sockio.h>
 #endif /* __sun__ */
 
-#include "common.h"
-#include "eloop.h"
-#include "driver.h"
-
 #ifdef _MSC_VER
 #pragma pack(push, 1)
 #endif /* _MSC_VER */
index a98af9a..00773a7 100644 (file)
 #include "utils/common.h"
 #include "driver.h"
 
-#ifdef CONFIG_DRIVER_WEXT
-extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
-#endif /* CONFIG_DRIVER_WEXT */
-#ifdef CONFIG_DRIVER_NL80211
-extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */
-#endif /* CONFIG_DRIVER_NL80211 */
-#ifdef CONFIG_DRIVER_HOSTAP
-extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
-#endif /* CONFIG_DRIVER_HOSTAP */
-#ifdef CONFIG_DRIVER_BSD
-extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
-#endif /* CONFIG_DRIVER_BSD */
-#ifdef CONFIG_DRIVER_OPENBSD
-extern struct wpa_driver_ops wpa_driver_openbsd_ops; /* driver_openbsd.c */
-#endif /* CONFIG_DRIVER_OPENBSD */
-#ifdef CONFIG_DRIVER_NDIS
-extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */
-#endif /* CONFIG_DRIVER_NDIS */
-#ifdef CONFIG_DRIVER_WIRED
-extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */
-#endif /* CONFIG_DRIVER_WIRED */
-#ifdef CONFIG_DRIVER_MACSEC_QCA
- /* driver_macsec_qca.c */
-extern struct wpa_driver_ops wpa_driver_macsec_qca_ops;
-#endif /* CONFIG_DRIVER_MACSEC_QCA */
-#ifdef CONFIG_DRIVER_ROBOSWITCH
-/* driver_roboswitch.c */
-extern struct wpa_driver_ops wpa_driver_roboswitch_ops;
-#endif /* CONFIG_DRIVER_ROBOSWITCH */
-#ifdef CONFIG_DRIVER_ATHEROS
-extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */
-#endif /* CONFIG_DRIVER_ATHEROS */
-#ifdef CONFIG_DRIVER_NONE
-extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */
-#endif /* CONFIG_DRIVER_NONE */
-
 
 const struct wpa_driver_ops *const wpa_drivers[] =
 {
index 3dd43c7..c6d3f81 100644 (file)
@@ -29,12 +29,15 @@ 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
-DRV_OBJS += ../src/utils/radiotap.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
 
 ifdef CONFIG_LIBNL32
   DRV_LIBS += -lnl-3
@@ -60,7 +63,9 @@ else
   endif
 
   ifdef CONFIG_LIBNL20
-    DRV_LIBS += -lnl-genl
+    ifndef CONFIG_LIBNL_TINY
+      DRV_LIBS += -lnl-genl
+    endif
     DRV_CFLAGS += -DCONFIG_LIBNL20
   endif
 endif
@@ -159,6 +164,10 @@ ifdef NEED_RFKILL
 DRV_OBJS += ../src/drivers/rfkill.o
 endif
 
+ifdef NEED_RADIOTAP
+DRV_OBJS += ../src/utils/radiotap.o
+endif
+
 ifdef CONFIG_VLAN_NETLINK
 ifdef CONFIG_FULL_DYNAMIC_VLAN
 ifdef CONFIG_LIBNL32
index 8da4c53..c6fe4c2 100644 (file)
@@ -25,12 +25,15 @@ 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
-DRV_OBJS += src/utils/radiotap.c
+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
 
 ifdef CONFIG_LIBNL32
   DRV_LIBS += -lnl-3
@@ -48,7 +51,9 @@ else
   endif
 
   ifdef CONFIG_LIBNL20
-    DRV_LIBS += -lnl-genl
+    ifndef CONFIG_LIBNL_TINY
+      DRV_LIBS += -lnl-genl
+    endif
     DRV_CFLAGS += -DCONFIG_LIBNL20
   endif
 endif
@@ -144,6 +149,10 @@ 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
index ae16ba9..2206941 100644 (file)
@@ -10,6 +10,7 @@
  * Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez@atheros.com>
  * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
  * Copyright 2008 Colin McCabe <colin@cozybit.com>
+ * Copyright 2015      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
  * @NL80211_CMD_GET_SCAN: get scan results
  * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
  *     %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
- *     probe requests at CCK rate or not.
+ *     probe requests at CCK rate or not. %NL80211_ATTR_MAC can be used to
+ *     specify a BSSID to scan for; if not included, the wildcard BSSID will
+ *     be used.
  * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
  *     NL80211_CMD_GET_SCAN and on the "scan" multicast group)
  * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
  *     partial scan results may be available
  *
  * @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan at certain
- *     intervals, as specified by %NL80211_ATTR_SCHED_SCAN_INTERVAL.
+ *     intervals and certain number of cycles, as specified by
+ *     %NL80211_ATTR_SCHED_SCAN_PLANS. If %NL80211_ATTR_SCHED_SCAN_PLANS is
+ *     not specified and only %NL80211_ATTR_SCHED_SCAN_INTERVAL is specified,
+ *     scheduled scan will run in an infinite loop with the specified interval.
+ *     These attributes are mutually exculsive,
+ *     i.e. NL80211_ATTR_SCHED_SCAN_INTERVAL must not be passed if
+ *     NL80211_ATTR_SCHED_SCAN_PLANS is defined.
+ *     If for some reason scheduled scan is aborted by the driver, all scan
+ *     plans are canceled (including scan plans that did not start yet).
  *     Like with normal scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS)
  *     are passed, they are used in the probe requests.  For
  *     broadcast, a broadcast SSID must be passed (ie. an empty
  * @NL80211_CMD_ASSOCIATE: association request and notification; like
  *     NL80211_CMD_AUTHENTICATE but for Association and Reassociation
  *     (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request,
- *     MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives).
+ *     MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives). The
+ *     %NL80211_ATTR_PREV_BSSID attribute is used to specify whether the
+ *     request is for the initial association to an ESS (that attribute not
+ *     included) or for reassociation within the ESS (that attribute is
+ *     included).
  * @NL80211_CMD_DEAUTHENTICATE: deauthentication request and notification; like
  *     NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to
  *     MLME-DEAUTHENTICATION.request and MLME-DEAUTHENTICATE.indication
  *     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).
+ *     %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.
  *     Background scan period can optionally be
  *     specified in %NL80211_ATTR_BG_SCAN_PERIOD,
  *     if not specified default background scan configuration
  *     This attribute is ignored if driver does not support roam scan.
  *     It is also sent as an event, with the BSSID and response IEs when the
  *     connection is established or failed to be established. This can be
- *     determined by the STATUS_CODE attribute.
+ *     determined by the %NL80211_ATTR_STATUS_CODE attribute (0 = success,
+ *     non-zero = failure). If %NL80211_ATTR_TIMED_OUT is included in the
+ *     event, the connection attempt failed due to not being able to initiate
+ *     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.
  * @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
  *     sent as an event when the card/driver roamed by itself.
  * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
  *     as an event to indicate changes for devices with wiphy-specific regdom
  *     management.
  *
+ * @NL80211_CMD_ABORT_SCAN: Stop an ongoing scan. Returns -ENOENT if a scan is
+ *     not running. The driver indicates the status of the scan through
+ *     cfg80211_scan_done().
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -997,6 +1024,8 @@ enum nl80211_commands {
 
        NL80211_CMD_WIPHY_REG_CHANGE,
 
+       NL80211_CMD_ABORT_SCAN,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -1270,8 +1299,11 @@ enum nl80211_commands {
  * @NL80211_ATTR_RESP_IE: (Re)association response information elements as
  *     sent by peer, for ROAM and successful CONNECT events.
  *
- * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE
- *     commands to specify using a reassociate frame
+ * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used in ASSOCIATE and CONNECT
+ *     commands to specify a request to reassociate within an ESS, i.e., to use
+ *     Reassociate Request frame (with the value of this attribute in the
+ *     Current AP address field) instead of Association Request frame which is
+ *     used for the initial association to an ESS.
  *
  * @NL80211_ATTR_KEY: key information in a nested attribute with
  *     %NL80211_KEY_* sub-attributes
@@ -1712,6 +1744,8 @@ enum nl80211_commands {
  *     underlying device supports these minimal RRM features:
  *             %NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES,
  *             %NL80211_FEATURE_QUIET,
+ *     Or, if global RRM is supported, see:
+ *             %NL80211_EXT_FEATURE_RRM
  *     If this flag is used, driver must add the Power Capabilities IE to the
  *     association request. In addition, it must also set the RRM capability
  *     flag in the association request's Capability Info field.
@@ -1754,12 +1788,85 @@ enum nl80211_commands {
  *     should be contained in the result as the sum of the respective counters
  *     over all channels.
  *
- * @NL80211_ATTR_SCHED_SCAN_DELAY: delay before a scheduled scan (or a
- *     WoWLAN net-detect scan) is started, u32 in seconds.
+ * @NL80211_ATTR_SCHED_SCAN_DELAY: delay before the first cycle of a
+ *     scheduled scan is started.  Or the delay before a WoWLAN
+ *     net-detect scan is started, counting from the moment the
+ *     system is suspended.  This value is a u32, in seconds.
 
  * @NL80211_ATTR_REG_INDOOR: flag attribute, if set indicates that the device
  *      is operating in an indoor environment.
  *
+ * @NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS: maximum number of scan plans for
+ *     scheduled scan supported by the device (u32), a wiphy attribute.
+ * @NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL: maximum interval (in seconds) for
+ *     a scan plan (u32), a wiphy attribute.
+ * @NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS: maximum number of iterations in
+ *     a scan plan (u32), a wiphy attribute.
+ * @NL80211_ATTR_SCHED_SCAN_PLANS: a list of scan plans for scheduled scan.
+ *     Each scan plan defines the number of scan iterations and the interval
+ *     between scans. The last scan plan will always run infinitely,
+ *     thus it must not specify the number of iterations, only the interval
+ *     between scans. The scan plans are executed sequentially.
+ *     Each scan plan is a nested attribute of &enum nl80211_sched_scan_plan.
+ * @NL80211_ATTR_PBSS: flag attribute. If set it means operate
+ *     in a PBSS. Specified in %NL80211_CMD_CONNECT to request
+ *     connecting to a PCP, and in %NL80211_CMD_START_AP to start
+ *     a PCP instead of AP. Relevant for DMG networks only.
+ * @NL80211_ATTR_BSS_SELECT: nested attribute for driver supporting the
+ *     BSS selection feature. When used with %NL80211_CMD_GET_WIPHY it contains
+ *     attributes according &enum nl80211_bss_select_attr to indicate what
+ *     BSS selection behaviours are supported. When used with %NL80211_CMD_CONNECT
+ *     it contains the behaviour-specific attribute containing the parameters for
+ *     BSS selection to be done by driver and/or firmware.
+ *
+ * @NL80211_ATTR_STA_SUPPORT_P2P_PS: whether P2P PS mechanism supported
+ *     or not. u8, one of the values of &enum nl80211_sta_p2p_ps_status
+ *
+ * @NL80211_ATTR_PAD: attribute used for padding for 64-bit alignment
+ *
+ * @NL80211_ATTR_IFTYPE_EXT_CAPA: Nested attribute of the following attributes:
+ *     %NL80211_ATTR_IFTYPE, %NL80211_ATTR_EXT_CAPA,
+ *     %NL80211_ATTR_EXT_CAPA_MASK, to specify the extended capabilities per
+ *     interface type.
+ *
+ * @NL80211_ATTR_MU_MIMO_GROUP_DATA: array of 24 bytes that defines a MU-MIMO
+ *     groupID for monitor mode.
+ *     The first 8 bytes are a mask that defines the membership in each
+ *     group (there are 64 groups, group 0 and 63 are reserved),
+ *     each bit represents a group and set to 1 for being a member in
+ *     that group and 0 for not being a member.
+ *     The remaining 16 bytes define the position in each group: 2 bits for
+ *     each group.
+ *     (smaller group numbers represented on most significant bits and bigger
+ *     group numbers on least significant bits.)
+ *     This attribute is used only if all interfaces are in monitor mode.
+ *     Set this attribute in order to monitor packets using the given MU-MIMO
+ *     groupID data.
+ *     to turn off that feature set all the bits of the groupID to zero.
+ * @NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR: mac address for the sniffer to follow
+ *     when using MU-MIMO air sniffer.
+ *     to turn that feature off set an invalid mac address
+ *     (e.g. FF:FF:FF:FF:FF:FF)
+ *
+ * @NL80211_ATTR_SCAN_START_TIME_TSF: The time at which the scan was actually
+ *     started (u64). The time is the TSF of the BSS the interface that
+ *     requested the scan is connected to (if available, otherwise this
+ *     attribute must not be included).
+ * @NL80211_ATTR_SCAN_START_TIME_TSF_BSSID: The BSS according to which
+ *     %NL80211_ATTR_SCAN_START_TIME_TSF is set.
+ * @NL80211_ATTR_MEASUREMENT_DURATION: measurement duration in TUs (u16). If
+ *     %NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY is not set, this is the
+ *     maximum measurement duration allowed. This attribute is used with
+ *     measurement requests. It can also be used with %NL80211_CMD_TRIGGER_SCAN
+ *     if the scan is used for beacon report radio measurement.
+ * @NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY: flag attribute that indicates
+ *     that the duration specified with %NL80211_ATTR_MEASUREMENT_DURATION is
+ *     mandatory. If this flag is not set, the duration is the maximum duration
+ *     and the actual measurement duration may be shorter.
+ *
+ * @NL80211_ATTR_MESH_PEER_AID: Association ID for the mesh peer (u16). This is
+ *     used to pull the stored data for mesh peer in power save state.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2129,6 +2236,31 @@ enum nl80211_attrs {
 
        NL80211_ATTR_REG_INDOOR,
 
+       NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
+       NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
+       NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
+       NL80211_ATTR_SCHED_SCAN_PLANS,
+
+       NL80211_ATTR_PBSS,
+
+       NL80211_ATTR_BSS_SELECT,
+
+       NL80211_ATTR_STA_SUPPORT_P2P_PS,
+
+       NL80211_ATTR_PAD,
+
+       NL80211_ATTR_IFTYPE_EXT_CAPA,
+
+       NL80211_ATTR_MU_MIMO_GROUP_DATA,
+       NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR,
+
+       NL80211_ATTR_SCAN_START_TIME_TSF,
+       NL80211_ATTR_SCAN_START_TIME_TSF_BSSID,
+       NL80211_ATTR_MEASUREMENT_DURATION,
+       NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY,
+
+       NL80211_ATTR_MESH_PEER_AID,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -2272,6 +2404,20 @@ enum nl80211_sta_flags {
        NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
 };
 
+/**
+ * enum nl80211_sta_p2p_ps_status - station support of P2P PS
+ *
+ * @NL80211_P2P_PS_UNSUPPORTED: station doesn't support P2P PS mechanism
+ * @@NL80211_P2P_PS_SUPPORTED: station supports P2P PS mechanism
+ * @NUM_NL80211_P2P_PS_STATUS: number of values
+ */
+enum nl80211_sta_p2p_ps_status {
+       NL80211_P2P_PS_UNSUPPORTED = 0,
+       NL80211_P2P_PS_SUPPORTED,
+
+       NUM_NL80211_P2P_PS_STATUS,
+};
+
 #define NL80211_STA_FLAG_MAX_OLD_API   NL80211_STA_FLAG_TDLS_PEER
 
 /**
@@ -2429,6 +2575,9 @@ enum nl80211_sta_bss_param {
  *     TID+1 and the special TID 16 (i.e. value 17) is used for non-QoS frames;
  *     each one of those is again nested with &enum nl80211_tid_stats
  *     attributes carrying the actual values.
+ * @NL80211_STA_INFO_RX_DURATION: aggregate PPDU duration for all frames
+ *     received from the station (u64, usec)
+ * @NL80211_STA_INFO_PAD: attribute used for padding for 64-bit alignment
  * @__NL80211_STA_INFO_AFTER_LAST: internal
  * @NL80211_STA_INFO_MAX: highest possible station info attribute
  */
@@ -2465,6 +2614,8 @@ enum nl80211_sta_info {
        NL80211_STA_INFO_BEACON_RX,
        NL80211_STA_INFO_BEACON_SIGNAL_AVG,
        NL80211_STA_INFO_TID_STATS,
+       NL80211_STA_INFO_RX_DURATION,
+       NL80211_STA_INFO_PAD,
 
        /* keep last */
        __NL80211_STA_INFO_AFTER_LAST,
@@ -2481,6 +2632,7 @@ enum nl80211_sta_info {
  *     transmitted MSDUs (not counting the first attempt; u64)
  * @NL80211_TID_STATS_TX_MSDU_FAILED: number of failed transmitted
  *     MSDUs (u64)
+ * @NL80211_TID_STATS_PAD: attribute used for padding for 64-bit alignment
  * @NUM_NL80211_TID_STATS: number of attributes here
  * @NL80211_TID_STATS_MAX: highest numbered attribute here
  */
@@ -2490,6 +2642,7 @@ enum nl80211_tid_stats {
        NL80211_TID_STATS_TX_MSDU,
        NL80211_TID_STATS_TX_MSDU_RETRIES,
        NL80211_TID_STATS_TX_MSDU_FAILED,
+       NL80211_TID_STATS_PAD,
 
        /* keep last */
        NUM_NL80211_TID_STATS,
@@ -2619,16 +2772,17 @@ enum nl80211_band_attr {
  *     an indoor surroundings, i.e., it is connected to AC power (and not
  *     through portable DC inverters) or is under the control of a master
  *     that is acting as an AP and is connected to AC power.
- * @NL80211_FREQUENCY_ATTR_GO_CONCURRENT: GO operation is allowed on this
+ * @NL80211_FREQUENCY_ATTR_IR_CONCURRENT: IR operation is allowed on this
  *     channel if it's connected concurrently to a BSS on the same channel on
  *     the 2 GHz band or to a channel in the same UNII band (on the 5 GHz
- *     band), and IEEE80211_CHAN_RADAR is not set. Instantiating a GO on a
- *     channel that has the GO_CONCURRENT attribute set can be done when there
- *     is a clear assessment that the device is operating under the guidance of
- *     an authorized master, i.e., setting up a GO while the device is also
- *     connected to an AP with DFS and radar detection on the UNII band (it is
- *     up to user-space, i.e., wpa_supplicant to perform the required
- *     verifications)
+ *     band), and IEEE80211_CHAN_RADAR is not set. Instantiating a GO or TDLS
+ *     off-channel on a channel that has the IR_CONCURRENT attribute set can be
+ *     done when there is a clear assessment that the device is operating under
+ *     the guidance of an authorized master, i.e., setting up a GO or TDLS
+ *     off-channel while the device is also connected to an AP with DFS and
+ *     radar detection on the UNII band (it is up to user-space, i.e.,
+ *     wpa_supplicant to perform the required verifications). Using this
+ *     attribute for IR is disallowed for master interfaces (IBSS, AP).
  * @NL80211_FREQUENCY_ATTR_NO_20MHZ: 20 MHz operation is not allowed
  *     on this channel in current regulatory domain.
  * @NL80211_FREQUENCY_ATTR_NO_10MHZ: 10 MHz operation is not allowed
@@ -2640,7 +2794,7 @@ enum nl80211_band_attr {
  * See https://apps.fcc.gov/eas/comments/GetPublishedDocument.html?id=327&tn=528122
  * for more information on the FCC description of the relaxations allowed
  * by NL80211_FREQUENCY_ATTR_INDOOR_ONLY and
- * NL80211_FREQUENCY_ATTR_GO_CONCURRENT.
+ * NL80211_FREQUENCY_ATTR_IR_CONCURRENT.
  */
 enum nl80211_frequency_attr {
        __NL80211_FREQUENCY_ATTR_INVALID,
@@ -2658,7 +2812,7 @@ enum nl80211_frequency_attr {
        NL80211_FREQUENCY_ATTR_NO_160MHZ,
        NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
        NL80211_FREQUENCY_ATTR_INDOOR_ONLY,
-       NL80211_FREQUENCY_ATTR_GO_CONCURRENT,
+       NL80211_FREQUENCY_ATTR_IR_CONCURRENT,
        NL80211_FREQUENCY_ATTR_NO_20MHZ,
        NL80211_FREQUENCY_ATTR_NO_10MHZ,
 
@@ -2671,6 +2825,8 @@ enum nl80211_frequency_attr {
 #define NL80211_FREQUENCY_ATTR_PASSIVE_SCAN    NL80211_FREQUENCY_ATTR_NO_IR
 #define NL80211_FREQUENCY_ATTR_NO_IBSS         NL80211_FREQUENCY_ATTR_NO_IR
 #define NL80211_FREQUENCY_ATTR_NO_IR           NL80211_FREQUENCY_ATTR_NO_IR
+#define NL80211_FREQUENCY_ATTR_GO_CONCURRENT \
+                                       NL80211_FREQUENCY_ATTR_IR_CONCURRENT
 
 /**
  * enum nl80211_bitrate_attr - bitrate attributes
@@ -2829,7 +2985,7 @@ enum nl80211_sched_scan_match_attr {
  * @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated
  *     base on contiguous rules and wider channels will be allowed to cross
  *     multiple contiguous/overlapping frequency ranges.
- * @NL80211_RRF_GO_CONCURRENT: See &NL80211_FREQUENCY_ATTR_GO_CONCURRENT
+ * @NL80211_RRF_IR_CONCURRENT: See &NL80211_FREQUENCY_ATTR_IR_CONCURRENT
  * @NL80211_RRF_NO_HT40MINUS: channels can't be used in HT40- operation
  * @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation
  * @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
@@ -2846,7 +3002,7 @@ enum nl80211_reg_rule_flags {
        NL80211_RRF_NO_IR               = 1<<7,
        __NL80211_RRF_NO_IBSS           = 1<<8,
        NL80211_RRF_AUTO_BW             = 1<<11,
-       NL80211_RRF_GO_CONCURRENT       = 1<<12,
+       NL80211_RRF_IR_CONCURRENT       = 1<<12,
        NL80211_RRF_NO_HT40MINUS        = 1<<13,
        NL80211_RRF_NO_HT40PLUS         = 1<<14,
        NL80211_RRF_NO_80MHZ            = 1<<15,
@@ -2858,6 +3014,7 @@ enum nl80211_reg_rule_flags {
 #define NL80211_RRF_NO_IR              NL80211_RRF_NO_IR
 #define NL80211_RRF_NO_HT40            (NL80211_RRF_NO_HT40MINUS |\
                                         NL80211_RRF_NO_HT40PLUS)
+#define NL80211_RRF_GO_CONCURRENT      NL80211_RRF_IR_CONCURRENT
 
 /* For backport compatibility with older userspace */
 #define NL80211_RRF_NO_IR_ALL          (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS)
@@ -2922,6 +3079,7 @@ enum nl80211_user_reg_hint_type {
  *     transmitting data (on channel or globally)
  * @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_MAX: highest survey info attribute number
  *     currently defined
  * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
@@ -2937,6 +3095,7 @@ enum nl80211_survey_info {
        NL80211_SURVEY_INFO_TIME_RX,
        NL80211_SURVEY_INFO_TIME_TX,
        NL80211_SURVEY_INFO_TIME_SCAN,
+       NL80211_SURVEY_INFO_PAD,
 
        /* keep last */
        __NL80211_SURVEY_INFO_AFTER_LAST,
@@ -3359,6 +3518,16 @@ enum nl80211_bss_scan_width {
  *     (not present if no beacon frame has been received yet)
  * @NL80211_BSS_PRESP_DATA: the data in @NL80211_BSS_INFORMATION_ELEMENTS and
  *     @NL80211_BSS_TSF is known to be from a probe response (flag attribute)
+ * @NL80211_BSS_LAST_SEEN_BOOTTIME: CLOCK_BOOTTIME timestamp when this entry
+ *     was last updated by a received frame. The value is expected to be
+ *     accurate to about 10ms. (u64, nanoseconds)
+ * @NL80211_BSS_PAD: attribute used for padding for 64-bit alignment
+ * @NL80211_BSS_PARENT_TSF: the time at the start of reception of the first
+ *     octet of the timestamp field of the last beacon/probe received for
+ *     this BSS. The time is the TSF of the BSS specified by
+ *     @NL80211_BSS_PARENT_BSSID. (u64).
+ * @NL80211_BSS_PARENT_BSSID: the BSS according to which @NL80211_BSS_PARENT_TSF
+ *     is set.
  * @__NL80211_BSS_AFTER_LAST: internal
  * @NL80211_BSS_MAX: highest BSS attribute
  */
@@ -3378,6 +3547,10 @@ enum nl80211_bss {
        NL80211_BSS_CHAN_WIDTH,
        NL80211_BSS_BEACON_TSF,
        NL80211_BSS_PRESP_DATA,
+       NL80211_BSS_LAST_SEEN_BOOTTIME,
+       NL80211_BSS_PAD,
+       NL80211_BSS_PARENT_TSF,
+       NL80211_BSS_PARENT_BSSID,
 
        /* keep last */
        __NL80211_BSS_AFTER_LAST,
@@ -3563,11 +3736,15 @@ 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 - 64.80 GHz)
+ * @NUM_NL80211_BANDS: number of bands, avoid using this in userspace
+ *     since newer kernel versions may support more bands
  */
 enum nl80211_band {
        NL80211_BAND_2GHZ,
        NL80211_BAND_5GHZ,
        NL80211_BAND_60GHZ,
+
+       NUM_NL80211_BANDS,
 };
 
 /**
@@ -4353,12 +4530,38 @@ enum nl80211_feature_flags {
 /**
  * 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
+ *     %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.
+ * @NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER: This device supports MU-MIMO air
+ *     sniffer which means that it can be configured to hear packets from
+ *     certain groups which can be configured by the
+ *     %NL80211_ATTR_MU_MIMO_GROUP_DATA attribute,
+ *     or can be configured to follow a station by configuring the
+ *     %NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR attribute.
+ * @NL80211_EXT_FEATURE_SCAN_START_TIME: This driver includes the actual
+ *     time the scan started in scan results event. The time is the TSF of
+ *     the BSS that the interface that requested the scan is connected to
+ *     (if available).
+ * @NL80211_EXT_FEATURE_BSS_PARENT_TSF: Per BSS, this driver reports the
+ *     time the last beacon/probe was received. The time is the TSF of the
+ *     BSS that the interface that requested the scan is connected to
+ *     (if available).
+ * @NL80211_EXT_FEATURE_SET_SCAN_DWELL: This driver supports configuration of
+ *     channel dwell time.
  *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
  */
 enum nl80211_ext_feature_index {
        NL80211_EXT_FEATURE_VHT_IBSS,
+       NL80211_EXT_FEATURE_RRM,
+       NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER,
+       NL80211_EXT_FEATURE_SCAN_START_TIME,
+       NL80211_EXT_FEATURE_BSS_PARENT_TSF,
+       NL80211_EXT_FEATURE_SET_SCAN_DWELL,
 
        /* add new features before the definition below */
        NUM_NL80211_EXT_FEATURES,
@@ -4584,4 +4787,72 @@ enum nl80211_tdls_peer_capability {
        NL80211_TDLS_PEER_WMM = 1<<2,
 };
 
+/**
+ * enum nl80211_sched_scan_plan - scanning plan for scheduled scan
+ * @__NL80211_SCHED_SCAN_PLAN_INVALID: attribute number 0 is reserved
+ * @NL80211_SCHED_SCAN_PLAN_INTERVAL: interval between scan iterations. In
+ *     seconds (u32).
+ * @NL80211_SCHED_SCAN_PLAN_ITERATIONS: number of scan iterations in this
+ *     scan plan (u32). The last scan plan must not specify this attribute
+ *     because it will run infinitely. A value of zero is invalid as it will
+ *     make the scan plan meaningless.
+ * @NL80211_SCHED_SCAN_PLAN_MAX: highest scheduled scan plan attribute number
+ *     currently defined
+ * @__NL80211_SCHED_SCAN_PLAN_AFTER_LAST: internal use
+ */
+enum nl80211_sched_scan_plan {
+       __NL80211_SCHED_SCAN_PLAN_INVALID,
+       NL80211_SCHED_SCAN_PLAN_INTERVAL,
+       NL80211_SCHED_SCAN_PLAN_ITERATIONS,
+
+       /* keep last */
+       __NL80211_SCHED_SCAN_PLAN_AFTER_LAST,
+       NL80211_SCHED_SCAN_PLAN_MAX =
+               __NL80211_SCHED_SCAN_PLAN_AFTER_LAST - 1
+};
+
+/**
+ * struct nl80211_bss_select_rssi_adjust - RSSI adjustment parameters.
+ *
+ * @band: band of BSS that must match for RSSI value adjustment.
+ * @delta: value used to adjust the RSSI value of matching BSS.
+ */
+struct nl80211_bss_select_rssi_adjust {
+       __u8 band;
+       __s8 delta;
+} __attribute__((packed));
+
+/**
+ * enum nl80211_bss_select_attr - attributes for bss selection.
+ *
+ * @__NL80211_BSS_SELECT_ATTR_INVALID: reserved.
+ * @NL80211_BSS_SELECT_ATTR_RSSI: Flag indicating only RSSI-based BSS selection
+ *     is requested.
+ * @NL80211_BSS_SELECT_ATTR_BAND_PREF: attribute indicating BSS
+ *     selection should be done such that the specified band is preferred.
+ *     When there are multiple BSS-es in the preferred band, the driver
+ *     shall use RSSI-based BSS selection as a second step. The value of
+ *     this attribute is according to &enum nl80211_band (u32).
+ * @NL80211_BSS_SELECT_ATTR_RSSI_ADJUST: When present the RSSI level for
+ *     BSS-es in the specified band is to be adjusted before doing
+ *     RSSI-based BSS selection. The attribute value is a packed structure
+ *     value as specified by &struct nl80211_bss_select_rssi_adjust.
+ * @NL80211_BSS_SELECT_ATTR_MAX: highest bss select attribute number.
+ * @__NL80211_BSS_SELECT_ATTR_AFTER_LAST: internal use.
+ *
+ * One and only one of these attributes are found within %NL80211_ATTR_BSS_SELECT
+ * for %NL80211_CMD_CONNECT. It specifies the required BSS selection behaviour
+ * which the driver shall use.
+ */
+enum nl80211_bss_select_attr {
+       __NL80211_BSS_SELECT_ATTR_INVALID,
+       NL80211_BSS_SELECT_ATTR_RSSI,
+       NL80211_BSS_SELECT_ATTR_BAND_PREF,
+       NL80211_BSS_SELECT_ATTR_RSSI_ADJUST,
+
+       /* keep last */
+       __NL80211_BSS_SELECT_ATTR_AFTER_LAST,
+       NL80211_BSS_SELECT_ATTR_MAX = __NL80211_BSS_SELECT_ATTR_AFTER_LAST - 1
+};
+
 #endif /* __LINUX_NL80211_H */
index 45b26c4..4d4d1b4 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "includes.h"
 #include <fcntl.h>
+#include <limits.h>
 
 #include "utils/common.h"
 #include "utils/eloop.h"
@@ -47,6 +48,7 @@ struct rfkill_data {
        struct rfkill_config *cfg;
        int fd;
        int blocked;
+       uint32_t idx;
 };
 
 
@@ -69,12 +71,13 @@ static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx)
                           (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.op != RFKILL_OP_CHANGE || event.type != RFKILL_TYPE_WLAN)
-               return;
 
        if (event.hard) {
                wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
@@ -102,11 +105,23 @@ 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) {
@@ -136,13 +151,27 @@ struct rfkill_data * rfkill_init(struct rfkill_config *cfg)
                                   (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);
-               if (event.op != RFKILL_OP_ADD ||
-                   event.type != RFKILL_TYPE_WLAN)
-                       continue;
+
+               rfkill->idx = event.idx;
                if (event.hard) {
                        wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
                        rfkill->blocked = 1;
@@ -150,8 +179,13 @@ struct rfkill_data * rfkill_init(struct rfkill_config *cfg)
                        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;
@@ -160,6 +194,8 @@ fail2:
        close(rfkill->fd);
 fail:
        os_free(rfkill);
+       /* use standard free function to match realpath() */
+       free(phy);
        return NULL;
 }
 
index 4dfdb3f..6217468 100644 (file)
@@ -44,9 +44,7 @@ static int eap_eke_dhcomp_len(u8 dhgroup, u8 encr)
        int dhlen;
 
        dhlen = eap_eke_dh_len(dhgroup);
-       if (dhlen < 0)
-               return -1;
-       if (encr != EAP_EKE_ENCR_AES128_CBC)
+       if (dhlen < 0 || encr != EAP_EKE_ENCR_AES128_CBC)
                return -1;
        return AES_BLOCK_SIZE + dhlen;
 }
@@ -166,13 +164,10 @@ int eap_eke_dh_init(u8 group, u8 *ret_priv, u8 *ret_pub)
        size_t pub_len, i;
 
        generator = eap_eke_dh_generator(group);
-       if (generator < 0 || generator > 255)
-               return -1;
-       gen = generator;
-
        dh = eap_eke_dh_group(group);
-       if (dh == NULL)
+       if (generator < 0 || generator > 255 || !dh)
                return -1;
+       gen = generator;
 
        /* x = random number 2 .. p-1 */
        if (random_get_bytes(ret_priv, dh->prime_len))
@@ -411,11 +406,8 @@ int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key,
        size_t len;
        const struct dh_group *dh;
 
-       if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
-               return -1;
-
        dh = eap_eke_dh_group(sess->dhgroup);
-       if (dh == NULL)
+       if (sess->encr != EAP_EKE_ENCR_AES128_CBC || !dh)
                return -1;
 
        /* Decrypt peer DHComponent */
@@ -635,6 +627,7 @@ int eap_eke_prot(struct eap_eke_session *sess,
 
        if (*prot_len < block_size + data_len + pad + icv_len) {
                wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for Prot() data");
+               return -1;
        }
        pos = prot;
 
@@ -653,10 +646,8 @@ int eap_eke_prot(struct eap_eke_session *sess,
                pos += pad;
        }
 
-       if (aes_128_cbc_encrypt(sess->ke, iv, e, data_len + pad) < 0)
-               return -1;
-
-       if (eap_eke_mac(sess->mac, sess->ki, e, data_len + pad, pos) < 0)
+       if (aes_128_cbc_encrypt(sess->ke, iv, e, data_len + pad) < 0 ||
+           eap_eke_mac(sess->mac, sess->ki, e, data_len + pad, pos) < 0)
                return -1;
        pos += icv_len;
 
@@ -684,9 +675,8 @@ int eap_eke_decrypt_prot(struct eap_eke_session *sess,
        else
                return -1;
 
-       if (prot_len < 2 * block_size + icv_len)
-               return -1;
-       if ((prot_len - icv_len) % block_size)
+       if (prot_len < 2 * block_size + icv_len ||
+           (prot_len - icv_len) % block_size)
                return -1;
 
        if (eap_eke_mac(sess->mac, sess->ki, prot + block_size,
@@ -737,22 +727,14 @@ int eap_eke_session_init(struct eap_eke_session *sess, u8 dhgroup, u8 encr,
        sess->mac = mac;
 
        sess->prf_len = eap_eke_prf_len(prf);
-       if (sess->prf_len < 0)
-               return -1;
        sess->nonce_len = eap_eke_nonce_len(prf);
-       if (sess->nonce_len < 0)
-               return -1;
        sess->auth_len = eap_eke_auth_len(prf);
-       if (sess->auth_len < 0)
-               return -1;
        sess->dhcomp_len = eap_eke_dhcomp_len(sess->dhgroup, sess->encr);
-       if (sess->dhcomp_len < 0)
-               return -1;
        sess->pnonce_len = eap_eke_pnonce_len(sess->mac);
-       if (sess->pnonce_len < 0)
-               return -1;
        sess->pnonce_ps_len = eap_eke_pnonce_ps_len(sess->mac);
-       if (sess->pnonce_ps_len < 0)
+       if (sess->prf_len < 0 || sess->nonce_len < 0 || sess->auth_len < 0 ||
+           sess->dhcomp_len < 0 || sess->pnonce_len < 0 ||
+           sess->pnonce_ps_len < 0)
                return -1;
 
        return 0;
index 151cc78..9ef671c 100644 (file)
@@ -93,8 +93,7 @@ void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
 }
 
 
-u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
-                        const char *label, size_t len)
+u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, size_t len)
 {
        u8 *out;
 
@@ -102,7 +101,7 @@ u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
        if (out == NULL)
                return NULL;
 
-       if (tls_connection_prf(ssl_ctx, conn, label, 1, 1, out, len)) {
+       if (tls_connection_get_eap_fast_key(ssl_ctx, conn, out, len)) {
                os_free(out);
                return NULL;
        }
@@ -111,22 +110,24 @@ u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
 }
 
 
-void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk)
+int eap_fast_derive_eap_msk(const u8 *simck, u8 *msk)
 {
        /*
         * RFC 4851, Section 5.4: EAP Master Session Key Generation
         * MSK = T-PRF(S-IMCK[j], "Session Key Generating Function", 64)
         */
 
-       sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
-                  "Session Key Generating Function", (u8 *) "", 0,
-                  msk, EAP_FAST_KEY_LEN);
+       if (sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
+                      "Session Key Generating Function", (u8 *) "", 0,
+                      msk, EAP_FAST_KEY_LEN) < 0)
+               return -1;
        wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
                        msk, EAP_FAST_KEY_LEN);
+       return 0;
 }
 
 
-void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
+int eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
 {
        /*
         * RFC 4851, Section 5.4: EAP Master Session Key Genreration
@@ -134,11 +135,13 @@ void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
         *        "Extended Session Key Generating Function", 64)
         */
 
-       sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
-                  "Extended Session Key Generating Function", (u8 *) "", 0,
-                  emsk, EAP_EMSK_LEN);
+       if (sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
+                      "Extended Session Key Generating Function", (u8 *) "", 0,
+                      emsk, EAP_EMSK_LEN) < 0)
+               return -1;
        wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
                        emsk, EAP_EMSK_LEN);
+       return 0;
 }
 
 
index 6d547fb..40d8a42 100644 (file)
@@ -102,9 +102,9 @@ struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf);
 void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
                                   const u8 *client_random, u8 *master_secret);
 u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
-                        const char *label, size_t len);
-void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk);
-void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk);
+                        size_t len);
+int eap_fast_derive_eap_msk(const u8 *simck, u8 *msk);
+int eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk);
 int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
                       int tlv_type, u8 *pos, size_t len);
 
index 8c7ae27..b081879 100644 (file)
@@ -92,7 +92,8 @@ static int eap_gpsk_gkdf_sha256(const u8 *psk /* Y */,
        n = (len + hashlen - 1) / hashlen;
        for (i = 1; i <= n; i++) {
                WPA_PUT_BE16(ibuf, i);
-               hmac_sha256_vector(psk, 32, 2, addr, vlen, hash);
+               if (hmac_sha256_vector(psk, 32, 2, addr, vlen, hash))
+                       return -1;
                clen = left > hashlen ? hashlen : left;
                os_memcpy(opos, hash, clen);
                opos += clen;
@@ -534,8 +535,7 @@ int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
                break;
 #ifdef EAP_GPSK_SHA256
        case EAP_GPSK_CIPHER_SHA256:
-               hmac_sha256(sk, sk_len, data, len, mic);
-               ret = 0;
+               ret = hmac_sha256(sk, sk_len, data, len, mic);
                break;
 #endif /* EAP_GPSK_SHA256 */
        default:
@@ -545,5 +545,8 @@ int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
                break;
        }
 
+       if (ret)
+               wpa_printf(MSG_DEBUG, "EAP-GPSK: Could not compute MIC");
+
        return ret;
 }
index 0e80ef5..a11bce8 100644 (file)
@@ -57,7 +57,8 @@ int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
        left = output_len;
        for (counter = 1; counter <= (u8) num_blocks; counter++) {
                size_t clen = left > EAP_PAX_MAC_LEN ? EAP_PAX_MAC_LEN : left;
-               hmac_sha1_vector(key, key_len, 3, addr, len, mac);
+               if (hmac_sha1_vector(key, key_len, 3, addr, len, mac) < 0)
+                       return -1;
                os_memcpy(pos, mac, clen);
                pos += clen;
                left -= clen;
@@ -106,7 +107,8 @@ int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
        len[2] = data3_len;
 
        count = (data1 ? 1 : 0) + (data2 ? 1 : 0) + (data3 ? 1 : 0);
-       hmac_sha1_vector(key, key_len, count, addr, len, hash);
+       if (hmac_sha1_vector(key, key_len, count, addr, len, hash) < 0)
+               return -1;
        os_memcpy(mac, hash, EAP_PAX_MAC_LEN);
 
        return 0;
index 4d27623..67f8f70 100644 (file)
@@ -115,6 +115,26 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
         case 26:
                nid = NID_secp224r1;
                break;
+#ifdef NID_brainpoolP224r1
+       case 27:
+               nid = NID_brainpoolP224r1;
+               break;
+#endif /* NID_brainpoolP224r1 */
+#ifdef NID_brainpoolP256r1
+       case 28:
+               nid = NID_brainpoolP256r1;
+               break;
+#endif /* NID_brainpoolP256r1 */
+#ifdef NID_brainpoolP384r1
+       case 29:
+               nid = NID_brainpoolP384r1;
+               break;
+#endif /* NID_brainpoolP384r1 */
+#ifdef NID_brainpoolP512r1
+       case 30:
+               nid = NID_brainpoolP512r1;
+               break;
+#endif /* NID_brainpoolP512r1 */
         default:
                wpa_printf(MSG_INFO, "EAP-pwd: unsupported group %d", num);
                return -1;
index c22e43e..8819541 100644 (file)
@@ -121,7 +121,7 @@ static int eap_sake_parse_add_attr(struct eap_sake_parse_attr *attr,
                attr->next_tmpid_len = len;
                break;
        case EAP_SAKE_AT_MSK_LIFE:
-               wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV");
+               wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MSK_LIFE");
                if (len != 4) {
                        wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid "
                                   "AT_MSK_LIFE payload length %d", len);
index d60358c..90fb89e 100644 (file)
@@ -62,13 +62,15 @@ int ikev2_integ_hash(int alg, const u8 *key, size_t key_len, const u8 *data,
        case AUTH_HMAC_SHA1_96:
                if (key_len != 20)
                        return -1;
-               hmac_sha1(key, key_len, data, data_len, tmphash);
+               if (hmac_sha1(key, key_len, data, data_len, tmphash) < 0)
+                       return -1;
                os_memcpy(hash, tmphash, 12);
                break;
        case AUTH_HMAC_MD5_96:
                if (key_len != 16)
                        return -1;
-               hmac_md5(key, key_len, data, data_len, tmphash);
+               if (hmac_md5(key, key_len, data, data_len, tmphash) < 0)
+                       return -1;
                os_memcpy(hash, tmphash, 12);
                break;
        default:
@@ -98,16 +100,13 @@ int ikev2_prf_hash(int alg, const u8 *key, size_t key_len,
 {
        switch (alg) {
        case PRF_HMAC_SHA1:
-               hmac_sha1_vector(key, key_len, num_elem, addr, len, hash);
-               break;
+               return hmac_sha1_vector(key, key_len, num_elem, addr, len,
+                                       hash);
        case PRF_HMAC_MD5:
-               hmac_md5_vector(key, key_len, num_elem, addr, len, hash);
-               break;
+               return hmac_md5_vector(key, key_len, num_elem, addr, len, hash);
        default:
                return -1;
        }
-
-       return 0;
 }
 
 
index 56c24b5..9110ca5 100644 (file)
@@ -48,6 +48,8 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req);
 static const char * eap_sm_method_state_txt(EapMethodState state);
 static const char * eap_sm_decision_txt(EapDecision decision);
 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
+                          const char *msg, size_t msglen);
 
 
 
@@ -188,6 +190,14 @@ SM_STATE(EAP, INITIALIZE)
         */
        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
+        * value here to avoid issues if a previous authentication attempt
+        * failed with ignore=TRUE being left behind in the last
+        * m.check(eapReqData) operation.
+        */
+       sm->ignore = 0;
        sm->num_rounds = 0;
        sm->prev_failure = 0;
        sm->expected_failure = 0;
@@ -312,11 +322,14 @@ SM_STATE(EAP, GET_METHOD)
        wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: "
                   "vendor %u method %u (%s)",
                   sm->reqVendor, method, sm->m->name);
-       if (reinit)
+       if (reinit) {
                sm->eap_method_priv = sm->m->init_for_reauth(
                        sm, sm->eap_method_priv);
-       else
+       } else {
+               sm->waiting_ext_cert_check = 0;
+               sm->ext_cert_check = 0;
                sm->eap_method_priv = sm->m->init(sm);
+       }
 
        if (sm->eap_method_priv == NULL) {
                struct eap_peer_config *config = eap_get_config(sm);
@@ -1373,13 +1386,10 @@ static int eap_sm_imsi_identity(struct eap_sm *sm,
        return 0;
 }
 
-#endif /* PCSC_FUNCS */
-
 
 static int eap_sm_set_scard_pin(struct eap_sm *sm,
                                struct eap_peer_config *conf)
 {
-#ifdef PCSC_FUNCS
        if (scard_set_pin(sm->scard_ctx, conf->pin)) {
                /*
                 * Make sure the same PIN is not tried again in order to avoid
@@ -1393,24 +1403,20 @@ static int eap_sm_set_scard_pin(struct eap_sm *sm,
                return -1;
        }
        return 0;
-#else /* PCSC_FUNCS */
-       return -1;
-#endif /* PCSC_FUNCS */
 }
 
+
 static int eap_sm_get_scard_identity(struct eap_sm *sm,
                                     struct eap_peer_config *conf)
 {
-#ifdef PCSC_FUNCS
        if (eap_sm_set_scard_pin(sm, conf))
                return -1;
 
        return eap_sm_imsi_identity(sm, conf);
-#else /* PCSC_FUNCS */
-       return -1;
-#endif /* PCSC_FUNCS */
 }
 
+#endif /* PCSC_FUNCS */
+
 
 /**
  * eap_sm_buildIdentity - Build EAP-Identity/Response for the current network
@@ -1453,23 +1459,27 @@ struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted)
                                  identity, identity_len);
        }
 
-       if (identity == NULL) {
-               wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity "
-                          "configuration was not available");
-               if (config->pcsc) {
+       if (config->pcsc) {
+#ifdef PCSC_FUNCS
+               if (!identity) {
                        if (eap_sm_get_scard_identity(sm, config) < 0)
                                return NULL;
                        identity = config->identity;
                        identity_len = config->identity_len;
-                       wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from "
-                                         "IMSI", identity, identity_len);
-               } else {
-                       eap_sm_request_identity(sm);
+                       wpa_hexdump_ascii(MSG_DEBUG,
+                                         "permanent identity from IMSI",
+                                         identity, identity_len);
+               } else if (eap_sm_set_scard_pin(sm, config) < 0) {
                        return NULL;
                }
-       } else if (config->pcsc) {
-               if (eap_sm_set_scard_pin(sm, config) < 0)
-                       return NULL;
+#else /* PCSC_FUNCS */
+               return NULL;
+#endif /* PCSC_FUNCS */
+       } else if (!identity) {
+               wpa_printf(MSG_WARNING,
+                       "EAP: buildIdentity: identity configuration was not available");
+               eap_sm_request_identity(sm);
+               return NULL;
        }
 
        resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, identity_len,
@@ -1510,15 +1520,9 @@ static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req)
 
 static struct wpabuf * eap_sm_buildNotify(int id)
 {
-       struct wpabuf *resp;
-
        wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification");
-       resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, 0,
-                            EAP_CODE_RESPONSE, id);
-       if (resp == NULL)
-               return NULL;
-
-       return resp;
+       return eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, 0,
+                       EAP_CODE_RESPONSE, id);
 }
 
 
@@ -1850,6 +1854,11 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
        case TLS_CERT_CHAIN_SUCCESS:
                eap_notify_status(sm, "remote certificate verification",
                                  "success");
+               if (sm->ext_cert_check) {
+                       sm->waiting_ext_cert_check = 1;
+                       eap_sm_request(sm, WPA_CTRL_REQ_EXT_CERT_CHECK,
+                                      NULL, 0);
+               }
                break;
        case TLS_CERT_CHAIN_FAILURE:
                wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
@@ -2172,10 +2181,10 @@ int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
 #endif /* CONFIG_CTRL_IFACE */
 
 
-#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
 static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
                           const char *msg, size_t msglen)
 {
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
        struct eap_peer_config *config;
        const char *txt = NULL;
        char *tmp;
@@ -2224,16 +2233,17 @@ static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
        case WPA_CTRL_REQ_SIM:
                txt = msg;
                break;
+       case WPA_CTRL_REQ_EXT_CERT_CHECK:
+               break;
        default:
                return;
        }
 
        if (sm->eapol_cb->eap_param_needed)
                sm->eapol_cb->eap_param_needed(sm->eapol_ctx, field, txt);
-}
-#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
-#define eap_sm_request(sm, type, msg, msglen) do { } while (0)
 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+}
+
 
 const char * eap_sm_get_method_name(struct eap_sm *sm)
 {
index dc9e8cc..0bac62d 100644 (file)
@@ -1492,7 +1492,6 @@ static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_aka_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
@@ -1511,10 +1510,7 @@ int eap_peer_aka_register(void)
        eap->get_identity = eap_aka_get_identity;
        eap->get_emsk = eap_aka_get_emsk;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
 
 
@@ -1522,7 +1518,6 @@ int eap_peer_aka_register(void)
 int eap_peer_aka_prime_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
@@ -1542,10 +1537,6 @@ int eap_peer_aka_prime_register(void)
        eap->get_identity = eap_aka_get_identity;
        eap->get_emsk = eap_aka_get_emsk;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-
-       return ret;
+       return eap_peer_method_register(eap);
 }
 #endif /* EAP_AKA_PRIME */
index 0dc8ea8..fca972f 100644 (file)
@@ -212,13 +212,13 @@ struct eap_peer_config {
         * subject_match - Constraint for server certificate subject
         *
         * This substring is matched against the subject of the authentication
-        * server certificate. If this string is set, the server sertificate is
+        * server certificate. If this string is set, the server certificate is
         * only accepted if it contains this string in the subject. The subject
         * string is in following format:
         *
         * /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@n.example.com
         *
-        * Note: Since this is a substring match, this cannot be used securily
+        * Note: Since this is a substring match, this cannot be used securely
         * to do a suffix match against a possible domain name in the CN entry.
         * For such a use case, domain_suffix_match should be used instead.
         */
@@ -229,7 +229,7 @@ struct eap_peer_config {
         *
         * Semicolon separated string of entries to be matched against the
         * alternative subject name of the authentication server certificate.
-        * If this string is set, the server sertificate is only accepted if it
+        * If this string is set, the server certificate is only accepted if it
         * contains one of the entries in an alternative subject name
         * extension.
         *
@@ -781,9 +781,23 @@ struct eap_peer_config {
         */
        int erp;
 
+       /**
+        * pending_ext_cert_check - External server certificate check status
+        *
+        * This field should not be set in configuration step. It is only used
+        * internally when control interface is used to request external
+        * validation of server certificate chain.
+        */
+       enum {
+               NO_CHECK = 0,
+               PENDING_CHECK,
+               EXT_CERT_CHECK_GOOD,
+               EXT_CERT_CHECK_BAD,
+       } pending_ext_cert_check;
+
     /**
-     * If non-null, specifies a callback method that can be used to
-     * override the validity of a peer certificate.
+     * server_cert_cb -- if non-null, specifies a callback method that can
+     * be used to override the validity of a peer (server/acceptor) certificate.
      */
     int (*server_cert_cb)(int ok_so_far, X509* cert, void *ca_ctx);
     void *server_cert_ctx;
index dfbda56..f899f65 100644 (file)
@@ -452,6 +452,7 @@ static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm,
        /* DHComponent_P = Encr(key, y_p) */
        rpos = wpabuf_put(resp, data->sess.dhcomp_len);
        if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) {
+               wpabuf_free(resp);
                wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_P");
                os_memset(key, 0, sizeof(key));
                return eap_eke_build_fail(data, ret, id,
@@ -770,7 +771,6 @@ static u8 * eap_eke_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_eke_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
@@ -785,8 +785,5 @@ int eap_peer_eke_register(void)
        eap->get_emsk = eap_eke_get_emsk;
        eap->getSessionId = eap_eke_get_session_id;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index 4cbe3ba..964ebe7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-FAST (RFC 4851)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -67,6 +67,7 @@ struct eap_fast_data {
        int simck_idx;
 
        struct wpabuf *pending_phase2_req;
+       struct wpabuf *pending_resp;
 };
 
 
@@ -112,8 +113,8 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
 }
 
 
-static int eap_fast_parse_phase1(struct eap_fast_data *data,
-                                const char *phase1)
+static void eap_fast_parse_phase1(struct eap_fast_data *data,
+                                 const char *phase1)
 {
        const char *pos;
 
@@ -139,8 +140,6 @@ static int eap_fast_parse_phase1(struct eap_fast_data *data,
                wpa_printf(MSG_DEBUG, "EAP-FAST: Using binary format for PAC "
                           "list");
        }
-
-       return 0;
 }
 
 
@@ -158,10 +157,8 @@ static void * eap_fast_init(struct eap_sm *sm)
        data->fast_version = EAP_FAST_VERSION;
        data->max_pac_list_len = 10;
 
-       if (config->phase1 && eap_fast_parse_phase1(data, config->phase1) < 0) {
-               eap_fast_deinit(sm, data);
-               return NULL;
-       }
+       if (config->phase1)
+               eap_fast_parse_phase1(data, config->phase1);
 
        if (eap_peer_select_phase2_methods(config, "auth=",
                                           &data->phase2_types,
@@ -254,14 +251,16 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv)
        os_memset(data->emsk, 0, EAP_EMSK_LEN);
        os_free(data->session_id);
        wpabuf_free(data->pending_phase2_req);
+       wpabuf_free(data->pending_resp);
        os_free(data);
 }
 
 
 static int eap_fast_derive_msk(struct eap_fast_data *data)
 {
-       eap_fast_derive_eap_msk(data->simck, data->key_data);
-       eap_fast_derive_eap_emsk(data->simck, data->emsk);
+       if (eap_fast_derive_eap_msk(data->simck, data->key_data) < 0 ||
+           eap_fast_derive_eap_emsk(data->simck, data->emsk) < 0)
+               return -1;
        data->success = 1;
        return 0;
 }
@@ -276,7 +275,7 @@ static int 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, "key expansion",
+       sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
                                  EAP_FAST_SKS_LEN);
        if (sks == NULL) {
                wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
@@ -304,7 +303,6 @@ static int 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,
-                                   "key expansion",
                                    sizeof(*data->key_block_p));
        if (data->key_block_p == NULL) {
                wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
@@ -711,9 +709,10 @@ static int eap_fast_get_cmk(struct eap_sm *sm, struct eap_fast_data *data,
        if (eap_fast_get_phase2_key(sm, data, isk, sizeof(isk)) < 0)
                return -1;
        wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[j]", isk, sizeof(isk));
-       sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
-                  "Inner Methods Compound Keys",
-                  isk, sizeof(isk), imck, sizeof(imck));
+       if (sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
+                      "Inner Methods Compound Keys",
+                      isk, sizeof(isk), imck, sizeof(imck)) < 0)
+               return -1;
        data->simck_idx++;
        os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
        wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
@@ -1096,7 +1095,7 @@ static int eap_fast_parse_decrypted(struct wpabuf *decrypted,
        /* Parse TLVs from the decrypted Phase 2 data */
        pos = wpabuf_mhead(decrypted);
        end = pos + wpabuf_len(decrypted);
-       while (pos + 4 < end) {
+       while (end - pos > 4) {
                mandatory = pos[0] & 0x80;
                tlv_type = WPA_GET_BE16(pos) & 0x3fff;
                pos += 2;
@@ -1443,7 +1442,7 @@ static int eap_fast_clear_pac_opaque_ext(struct eap_sm *sm,
 static int eap_fast_set_provisioning_ciphers(struct eap_sm *sm,
                                             struct eap_fast_data *data)
 {
-       u8 ciphers[5];
+       u8 ciphers[7];
        int count = 0;
 
        if (data->provisioning_allowed & EAP_FAST_PROV_UNAUTH) {
@@ -1455,7 +1454,9 @@ static int eap_fast_set_provisioning_ciphers(struct eap_sm *sm,
        if (data->provisioning_allowed & EAP_FAST_PROV_AUTH) {
                wpa_printf(MSG_DEBUG, "EAP-FAST: Enabling authenticated "
                           "provisioning TLS cipher suites");
+               ciphers[count++] = TLS_CIPHER_RSA_DHE_AES256_SHA;
                ciphers[count++] = TLS_CIPHER_RSA_DHE_AES128_SHA;
+               ciphers[count++] = TLS_CIPHER_AES256_SHA;
                ciphers[count++] = TLS_CIPHER_AES128_SHA;
                ciphers[count++] = TLS_CIPHER_RC4_SHA;
        }
@@ -1567,6 +1568,34 @@ static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
                        res = 1;
                }
        } else {
+               if (sm->waiting_ext_cert_check && data->pending_resp) {
+                       struct eap_peer_config *config = eap_get_config(sm);
+
+                       if (config->pending_ext_cert_check ==
+                           EXT_CERT_CHECK_GOOD) {
+                               wpa_printf(MSG_DEBUG,
+                                          "EAP-FAST: External certificate check succeeded - continue handshake");
+                               resp = data->pending_resp;
+                               data->pending_resp = NULL;
+                               sm->waiting_ext_cert_check = 0;
+                               return resp;
+                       }
+
+                       if (config->pending_ext_cert_check ==
+                           EXT_CERT_CHECK_BAD) {
+                               wpa_printf(MSG_DEBUG,
+                                          "EAP-FAST: External certificate check failed - force authentication failure");
+                               ret->methodState = METHOD_DONE;
+                               ret->decision = DECISION_FAIL;
+                               sm->waiting_ext_cert_check = 0;
+                               return NULL;
+                       }
+
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-FAST: Continuing to wait external server certificate validation");
+                       return NULL;
+               }
+
                /* Continue processing TLS handshake (phase 1). */
                res = eap_peer_tls_process_helper(sm, &data->ssl,
                                                  EAP_TYPE_FAST,
@@ -1580,6 +1609,14 @@ static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
                        return resp;
                }
 
+               if (sm->waiting_ext_cert_check) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-FAST: Waiting external server certificate validation");
+                       wpabuf_free(data->pending_resp);
+                       data->pending_resp = resp;
+                       return NULL;
+               }
+
                if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
                        char cipher[80];
                        wpa_printf(MSG_DEBUG,
@@ -1644,6 +1681,8 @@ static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv)
        data->key_block_p = NULL;
        wpabuf_free(data->pending_phase2_req);
        data->pending_phase2_req = NULL;
+       wpabuf_free(data->pending_resp);
+       data->pending_resp = NULL;
 }
 
 
@@ -1721,7 +1760,7 @@ static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
        struct eap_fast_data *data = priv;
        u8 *id;
 
-       if (!data->success)
+       if (!data->success || !data->session_id)
                return NULL;
 
        id = os_malloc(data->id_len);
@@ -1757,7 +1796,6 @@ static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_fast_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST");
@@ -1778,8 +1816,5 @@ int eap_peer_fast_register(void)
 #endif
        eap->get_emsk = eap_fast_get_emsk;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index 89e604e..c815860 100644 (file)
@@ -455,7 +455,8 @@ int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root,
        }
 
        if (pac) {
-               err = "PAC block not terminated with END";
+               if (!err)
+                       err = "PAC block not terminated with END";
                eap_fast_free_pac(pac);
        }
 
@@ -709,7 +710,7 @@ static void eap_fast_pac_get_a_id(struct eap_fast_pac *pac)
        pos = pac->pac_info;
        end = pos + pac->pac_info_len;
 
-       while (pos + 4 < end) {
+       while (end - pos > 4) {
                type = WPA_GET_BE16(pos);
                pos += 2;
                len = WPA_GET_BE16(pos);
@@ -801,8 +802,10 @@ int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root,
        while (pos < end) {
                u16 val;
 
-               if (end - pos < 2 + EAP_FAST_PAC_KEY_LEN + 2 + 2)
+               if (end - pos < 2 + EAP_FAST_PAC_KEY_LEN + 2 + 2) {
+                       pac = NULL;
                        goto parse_fail;
+               }
 
                pac = os_zalloc(sizeof(*pac));
                if (pac == NULL)
index 902b4ba..177cbcc 100644 (file)
@@ -771,7 +771,6 @@ static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_gpsk_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
@@ -786,8 +785,5 @@ int eap_peer_gpsk_register(void)
        eap->get_emsk = eap_gpsk_get_emsk;
        eap->getSessionId = eap_gpsk_get_session_id;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index 9f3cfbd..a519a78 100644 (file)
@@ -127,7 +127,6 @@ static struct wpabuf * eap_gtc_process(struct eap_sm *sm, void *priv,
 int eap_peer_gtc_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC");
@@ -138,8 +137,5 @@ int eap_peer_gtc_register(void)
        eap->deinit = eap_gtc_deinit;
        eap->process = eap_gtc_process;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index 5d915fa..f1f5d55 100644 (file)
@@ -370,6 +370,8 @@ struct eap_sm {
        int external_sim;
 
        unsigned int expected_failure:1;
+       unsigned int ext_cert_check:1;
+       unsigned int waiting_ext_cert_check:1;
 
        struct dl_list erp_keys; /* struct eap_erp_key */
 };
index b5ef71b..390f0ec 100644 (file)
@@ -513,7 +513,6 @@ static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_ikev2_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_IKEV2,
@@ -529,8 +528,5 @@ int eap_peer_ikev2_register(void)
        eap->get_emsk = eap_ikev2_get_emsk;
        eap->getSessionId = eap_ikev2_get_session_id;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index e0f8bcf..ff6fa4a 100644 (file)
@@ -393,7 +393,6 @@ static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_leap_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_LEAP, "LEAP");
@@ -406,8 +405,5 @@ int eap_peer_leap_register(void)
        eap->isKeyAvailable = eap_leap_isKeyAvailable;
        eap->getKey = eap_leap_getKey;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index d06befa..efae8de 100644 (file)
@@ -102,7 +102,6 @@ static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv,
 int eap_peer_md5_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5");
@@ -113,8 +112,5 @@ int eap_peer_md5_register(void)
        eap->deinit = eap_md5_deinit;
        eap->process = eap_md5_process;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index 1bdd81e..9747954 100644 (file)
@@ -18,6 +18,8 @@
 
 static struct eap_method *eap_methods = NULL;
 
+static void eap_peer_method_free(struct eap_method *method);
+
 
 /**
  * eap_peer_get_eap_method - Get EAP method based on type number
@@ -295,7 +297,7 @@ struct eap_method * eap_peer_method_alloc(int version, int vendor,
  * eap_peer_method_free - Free EAP peer method structure
  * @method: Method structure allocated with eap_peer_method_alloc()
  */
-void eap_peer_method_free(struct eap_method *method)
+static void eap_peer_method_free(struct eap_method *method)
 {
        os_free(method);
 }
@@ -303,26 +305,31 @@ void eap_peer_method_free(struct eap_method *method)
 
 /**
  * eap_peer_method_register - Register an EAP peer method
- * @method: EAP method to register
+ * @method: EAP method to register from eap_peer_method_alloc()
  * Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method
  * has already been registered
  *
  * Each EAP peer method needs to call this function to register itself as a
- * supported EAP method.
+ * supported EAP method. The caller must not free the allocated method data
+ * regardless of the return value.
  */
 int eap_peer_method_register(struct eap_method *method)
 {
        struct eap_method *m, *last = NULL;
 
        if (method == NULL || method->name == NULL ||
-           method->version != EAP_PEER_METHOD_INTERFACE_VERSION)
+           method->version != EAP_PEER_METHOD_INTERFACE_VERSION) {
+               eap_peer_method_free(method);
                return -1;
+       }
 
        for (m = eap_methods; m; m = m->next) {
                if ((m->vendor == method->vendor &&
                     m->method == method->method) ||
-                   os_strcmp(m->name, method->name) == 0)
+                   os_strcmp(m->name, method->name) == 0) {
+                       eap_peer_method_free(method);
                        return -2;
+               }
                last = m;
        }
 
index 11c3278..ee4a1f5 100644 (file)
@@ -20,7 +20,6 @@ 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);
-void eap_peer_method_free(struct eap_method *method);
 int eap_peer_method_register(struct eap_method *method);
 
 
index 6acf1e8..ce2227d 100644 (file)
@@ -880,7 +880,6 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_mschapv2_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
@@ -894,8 +893,5 @@ int eap_peer_mschapv2_register(void)
        eap->isKeyAvailable = eap_mschapv2_isKeyAvailable;
        eap->getKey = eap_mschapv2_getKey;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index 9ac744a..0ab4c79 100644 (file)
@@ -83,7 +83,6 @@ static struct wpabuf * eap_otp_process(struct eap_sm *sm, void *priv,
 int eap_peer_otp_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_OTP, "OTP");
@@ -94,8 +93,5 @@ int eap_peer_otp_register(void)
        eap->deinit = eap_otp_deinit;
        eap->process = eap_otp_process;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index c920bcd..a7012d2 100644 (file)
@@ -276,9 +276,16 @@ static struct wpabuf * eap_pax_process_std_3(struct eap_pax_data *data,
        left -= 2;
        wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
                    pos, EAP_PAX_MAC_LEN);
-       eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
-                   data->rand.r.y, EAP_PAX_RAND_LEN,
-                   (u8 *) data->cid, data->cid_len, NULL, 0, mac);
+       if (eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
+                       data->rand.r.y, EAP_PAX_RAND_LEN,
+                       (u8 *) data->cid, data->cid_len, NULL, 0, mac) < 0) {
+               wpa_printf(MSG_INFO,
+                          "EAP-PAX: Could not derive MAC_CK(B, CID)");
+               ret->methodState = METHOD_DONE;
+               ret->decision = DECISION_FAIL;
+               return NULL;
+       }
+
        if (os_memcmp_const(pos, mac, EAP_PAX_MAC_LEN) != 0) {
                wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(B, CID) "
                           "received");
@@ -306,9 +313,12 @@ static struct wpabuf * eap_pax_process_std_3(struct eap_pax_data *data,
        /* Optional ADE could be added here, if needed */
 
        rpos = wpabuf_put(resp, EAP_PAX_ICV_LEN);
-       eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
-                   wpabuf_head(resp), wpabuf_len(resp) - EAP_PAX_ICV_LEN,
-                   NULL, 0, NULL, 0, rpos);
+       if (eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
+                       wpabuf_head(resp), wpabuf_len(resp) - EAP_PAX_ICV_LEN,
+                       NULL, 0, NULL, 0, rpos) < 0) {
+               wpabuf_free(resp);
+               return NULL;
+       }
        wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", rpos, EAP_PAX_ICV_LEN);
 
        data->state = PAX_DONE;
@@ -472,9 +482,13 @@ static u8 * eap_pax_getKey(struct eap_sm *sm, void *priv, size_t *len)
                return NULL;
 
        *len = EAP_MSK_LEN;
-       eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
-                   "Master Session Key", data->rand.e, 2 * EAP_PAX_RAND_LEN,
-                   EAP_MSK_LEN, key);
+       if (eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
+                       "Master Session Key",
+                       data->rand.e, 2 * EAP_PAX_RAND_LEN,
+                       EAP_MSK_LEN, key) < 0) {
+               os_free(key);
+               return NULL;
+       }
 
        return key;
 }
@@ -493,10 +507,13 @@ static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
                return NULL;
 
        *len = EAP_EMSK_LEN;
-       eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
-                   "Extended Master Session Key",
-                   data->rand.e, 2 * EAP_PAX_RAND_LEN,
-                   EAP_EMSK_LEN, key);
+       if (eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
+                       "Extended Master Session Key",
+                       data->rand.e, 2 * EAP_PAX_RAND_LEN,
+                       EAP_EMSK_LEN, key) < 0) {
+               os_free(key);
+               return NULL;
+       }
 
        return key;
 }
@@ -525,7 +542,6 @@ static u8 * eap_pax_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_pax_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_PAX, "PAX");
@@ -540,8 +556,5 @@ int eap_peer_pax_register(void)
        eap->get_emsk = eap_pax_get_emsk;
        eap->getSessionId = eap_pax_get_session_id;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index 98a48a6..45ba381 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -59,6 +59,7 @@ struct eap_peap_data {
        size_t id_len;
 
        struct wpabuf *pending_phase2_req;
+       struct wpabuf *pending_resp;
        enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
        int crypto_binding_used;
        u8 binding_nonce[32];
@@ -69,8 +70,8 @@ struct eap_peap_data {
 };
 
 
-static int eap_peap_parse_phase1(struct eap_peap_data *data,
-                                const char *phase1)
+static void eap_peap_parse_phase1(struct eap_peap_data *data,
+                                 const char *phase1)
 {
        const char *pos;
 
@@ -125,8 +126,6 @@ static int eap_peap_parse_phase1(struct eap_peap_data *data,
                wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
        }
 #endif /* EAP_TNC */
-
-       return 0;
 }
 
 
@@ -144,11 +143,8 @@ static void * eap_peap_init(struct eap_sm *sm)
        data->peap_outer_success = 2;
        data->crypto_binding = OPTIONAL_BINDING;
 
-       if (config && config->phase1 &&
-           eap_peap_parse_phase1(data, config->phase1) < 0) {
-               eap_peap_deinit(sm, data);
-               return NULL;
-       }
+       if (config && config->phase1)
+               eap_peap_parse_phase1(data, config->phase1);
 
        if (eap_peer_select_phase2_methods(config, "auth=",
                                           &data->phase2_types,
@@ -191,6 +187,7 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv)
        eap_peap_free_key(data);
        os_free(data->session_id);
        wpabuf_free(data->pending_phase2_req);
+       wpabuf_free(data->pending_resp);
        os_free(data);
 }
 
@@ -256,6 +253,7 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
 {
        u8 *tk;
        u8 isk[32], imck[60];
+       int resumed;
 
        /*
         * Tunnel key (TK) is the first 60 octets of the key generated by
@@ -266,8 +264,12 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
                return -1;
        wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
 
-       if (data->reauth &&
-           tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
+       resumed = tls_connection_resumed(sm->ssl_ctx, data->ssl.conn);
+       wpa_printf(MSG_DEBUG,
+                  "EAP-PEAP: CMK derivation - reauth=%d resumed=%d phase2_eap_started=%d phase2_success=%d",
+                  data->reauth, resumed, data->phase2_eap_started,
+                  data->phase2_success);
+       if (data->reauth && !data->phase2_eap_started && resumed) {
                /* Fast-connect: IPMK|CMK = TK */
                os_memcpy(data->ipmk, tk, 40);
                wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK",
@@ -337,7 +339,8 @@ static int eap_tlv_add_cryptobinding(struct eap_sm *sm,
                    addr[0], len[0]);
        wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
                    addr[1], len[1]);
-       hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
+       if (hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac) < 0)
+               return -1;
        wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN);
        data->crypto_binding_used = 1;
 
@@ -648,6 +651,7 @@ static int eap_peap_phase2_request(struct eap_sm *sm,
                                        if (*resp == NULL) {
                                                ret->methodState = METHOD_DONE;
                                                ret->decision = DECISION_FAIL;
+                                               wpabuf_free(buf);
                                                return -1;
                                        }
                                        wpabuf_put_buf(*resp, buf);
@@ -1006,6 +1010,34 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
            !data->resuming) {
                res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp);
        } else {
+               if (sm->waiting_ext_cert_check && data->pending_resp) {
+                       struct eap_peer_config *config = eap_get_config(sm);
+
+                       if (config->pending_ext_cert_check ==
+                           EXT_CERT_CHECK_GOOD) {
+                               wpa_printf(MSG_DEBUG,
+                                          "EAP-PEAP: External certificate check succeeded - continue handshake");
+                               resp = data->pending_resp;
+                               data->pending_resp = NULL;
+                               sm->waiting_ext_cert_check = 0;
+                               return resp;
+                       }
+
+                       if (config->pending_ext_cert_check ==
+                           EXT_CERT_CHECK_BAD) {
+                               wpa_printf(MSG_DEBUG,
+                                          "EAP-PEAP: External certificate check failed - force authentication failure");
+                               ret->methodState = METHOD_DONE;
+                               ret->decision = DECISION_FAIL;
+                               sm->waiting_ext_cert_check = 0;
+                               return NULL;
+                       }
+
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-PEAP: Continuing to wait external server certificate validation");
+                       return NULL;
+               }
+
                res = eap_peer_tls_process_helper(sm, &data->ssl,
                                                  EAP_TYPE_PEAP,
                                                  data->peap_version, id, &msg,
@@ -1018,6 +1050,16 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
                        ret->decision = DECISION_FAIL;
                        return resp;
                }
+
+
+               if (sm->waiting_ext_cert_check) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-PEAP: Waiting external server certificate validation");
+                       wpabuf_free(data->pending_resp);
+                       data->pending_resp = resp;
+                       return NULL;
+               }
+
                if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
                        char *label;
                        wpa_printf(MSG_DEBUG,
@@ -1123,6 +1165,8 @@ static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
        struct eap_peap_data *data = priv;
        wpabuf_free(data->pending_phase2_req);
        data->pending_phase2_req = NULL;
+       wpabuf_free(data->pending_resp);
+       data->pending_resp = NULL;
        data->crypto_binding_used = 0;
 }
 
@@ -1237,7 +1281,6 @@ static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_peap_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
@@ -1255,8 +1298,5 @@ int eap_peer_peap_register(void)
        eap->init_for_reauth = eap_peap_init_for_reauth;
        eap->getSessionId = eap_peap_get_session_id;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index f012663..ac18c15 100644 (file)
@@ -480,7 +480,6 @@ static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_psk_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK");
@@ -495,8 +494,5 @@ int eap_peer_psk_register(void)
        eap->getSessionId = eap_psk_get_session_id;
        eap->get_emsk = eap_psk_get_emsk;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index 1f78544..d2bc981 100644 (file)
@@ -418,7 +418,6 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
                wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail");
                goto fin;
        }
-       BN_clear_free(mask);
 
        if (((x = BN_new()) == NULL) ||
            ((y = BN_new()) == NULL)) {
@@ -555,6 +554,7 @@ fin:
        os_free(element);
        BN_clear_free(x);
        BN_clear_free(y);
+       BN_clear_free(mask);
        BN_clear_free(cofactor);
        EC_POINT_clear_free(K);
        EC_POINT_clear_free(point);
@@ -774,7 +774,8 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
        wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
 
 fin:
-       bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
+       if (data->grp)
+               bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
        BN_clear_free(x);
        BN_clear_free(y);
        if (data->outbuf == NULL) {
@@ -903,7 +904,7 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
        /*
         * buffer and ACK the fragment
         */
-       if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
+       if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) {
                data->in_frag_pos += len;
                if (data->in_frag_pos > wpabuf_size(data->inbuf)) {
                        wpa_printf(MSG_INFO, "EAP-pwd: Buffer overflow attack "
@@ -916,7 +917,8 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
                        return NULL;
                }
                wpabuf_put_data(data->inbuf, pos, len);
-
+       }
+       if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
                resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
                                     EAP_PWD_HDR_SIZE,
                                     EAP_CODE_RESPONSE, eap_get_id(reqData));
@@ -930,10 +932,8 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
         * we're buffering and this is the last fragment
         */
        if (data->in_frag_pos) {
-               wpabuf_put_data(data->inbuf, pos, len);
                wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes",
                           (int) len);
-               data->in_frag_pos += len;
                pos = wpabuf_head_u8(data->inbuf);
                len = data->in_frag_pos;
        }
@@ -1054,7 +1054,6 @@ static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_pwd_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_PWD, "PWD");
@@ -1069,8 +1068,5 @@ int eap_peer_pwd_register(void)
        eap->getSessionId = eap_pwd_get_session_id;
        eap->get_emsk = eap_pwd_get_emsk;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index c4f9843..330febb 100644 (file)
@@ -309,11 +309,20 @@ static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm,
                return NULL;
        }
 
-       eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
-                            data->serverid, data->serverid_len,
-                            data->peerid, data->peerid_len, 0,
-                            wpabuf_head(reqData), wpabuf_len(reqData),
-                            attr.mic_s, mic_s);
+       if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+                                data->serverid, data->serverid_len,
+                                data->peerid, data->peerid_len, 0,
+                                wpabuf_head(reqData), wpabuf_len(reqData),
+                                attr.mic_s, mic_s)) {
+               wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
+               eap_sake_state(data, FAILURE);
+               ret->methodState = METHOD_DONE;
+               ret->decision = DECISION_FAIL;
+               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);
+       }
        if (os_memcmp_const(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) {
                wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S");
                eap_sake_state(data, FAILURE);
@@ -494,7 +503,6 @@ static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_sake_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
@@ -509,8 +517,5 @@ int eap_peer_sake_register(void)
        eap->getSessionId = eap_sake_get_session_id;
        eap->get_emsk = eap_sake_get_emsk;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index 99a2816..b97c95d 100644 (file)
@@ -249,6 +249,7 @@ static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
                        return eap_sim_ext_sim_req(sm, data);
        }
 
+#ifdef PCSC_FUNCS
        if (conf->pcsc) {
                if (scard_gsm_auth(sm->scard_ctx, data->rand[0],
                                   data->sres[0], data->kc[0]) ||
@@ -263,6 +264,7 @@ static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
                }
                return 0;
        }
+#endif /* PCSC_FUNCS */
 
 #ifdef CONFIG_SIM_SIMULATOR
        if (conf->password) {
@@ -1135,7 +1137,7 @@ static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv)
        if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
                wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
                           "for NONCE_MT");
-               os_free(data);
+               eap_sim_deinit(sm, data);
                return NULL;
        }
        data->num_id_req = 0;
@@ -1235,7 +1237,6 @@ static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_sim_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
@@ -1254,8 +1255,5 @@ int eap_peer_sim_register(void)
        eap->get_identity = eap_sim_get_identity;
        eap->get_emsk = eap_sim_get_emsk;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index 66a027a..ca2354f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -25,6 +25,7 @@ struct eap_tls_data {
        size_t id_len;
        void *ssl_ctx;
        u8 eap_type;
+       struct wpabuf *pending_resp;
 };
 
 
@@ -142,6 +143,7 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv)
        eap_peer_tls_ssl_deinit(sm, &data->ssl);
        eap_tls_free_key(data);
        os_free(data->session_id);
+       wpabuf_free(data->pending_resp);
        os_free(data);
 }
 
@@ -216,6 +218,32 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
        struct eap_tls_data *data = priv;
        struct wpabuf msg;
 
+       if (sm->waiting_ext_cert_check && data->pending_resp) {
+               struct eap_peer_config *config = eap_get_config(sm);
+
+               if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-TLS: External certificate check succeeded - continue handshake");
+                       resp = data->pending_resp;
+                       data->pending_resp = NULL;
+                       sm->waiting_ext_cert_check = 0;
+                       return resp;
+               }
+
+               if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-TLS: External certificate check failed - force authentication failure");
+                       ret->methodState = METHOD_DONE;
+                       ret->decision = DECISION_FAIL;
+                       sm->waiting_ext_cert_check = 0;
+                       return NULL;
+               }
+
+               wpa_printf(MSG_DEBUG,
+                          "EAP-TLS: Continuing to wait external server certificate validation");
+               return NULL;
+       }
+
        pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret,
                                        reqData, &left, &flags);
        if (pos == NULL)
@@ -237,6 +265,14 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
                return eap_tls_failure(sm, data, ret, res, resp, id);
        }
 
+       if (sm->waiting_ext_cert_check) {
+               wpa_printf(MSG_DEBUG,
+                          "EAP-TLS: Waiting external server certificate validation");
+               wpabuf_free(data->pending_resp);
+               data->pending_resp = resp;
+               return NULL;
+       }
+
        if (tls_connection_established(data->ssl_ctx, data->ssl.conn))
                eap_tls_success(sm, data, ret);
 
@@ -258,6 +294,10 @@ static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
 
 static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
 {
+       struct eap_tls_data *data = priv;
+
+       wpabuf_free(data->pending_resp);
+       data->pending_resp = NULL;
 }
 
 
@@ -350,7 +390,6 @@ static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_tls_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
@@ -369,10 +408,7 @@ int eap_peer_tls_register(void)
        eap->init_for_reauth = eap_tls_init_for_reauth;
        eap->get_emsk = eap_tls_get_emsk;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
 
 
@@ -380,7 +416,6 @@ int eap_peer_tls_register(void)
 int eap_peer_unauth_tls_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_UNAUTH_TLS,
@@ -399,10 +434,7 @@ int eap_peer_unauth_tls_register(void)
        eap->init_for_reauth = eap_tls_init_for_reauth;
        eap->get_emsk = eap_tls_get_emsk;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
 #endif /* EAP_UNAUTH_TLS */
 
@@ -411,7 +443,6 @@ int eap_peer_unauth_tls_register(void)
 int eap_peer_wfa_unauth_tls_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_WFA_NEW,
@@ -431,9 +462,6 @@ int eap_peer_wfa_unauth_tls_register(void)
        eap->init_for_reauth = eap_tls_init_for_reauth;
        eap->get_emsk = eap_tls_get_emsk;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
 #endif /* CONFIG_HS20 */
index bc4482a..0d17122 100644 (file)
@@ -80,6 +80,10 @@ static void eap_tls_params_flags(struct tls_connection_params *params,
                params->flags |= TLS_CONN_DISABLE_TLSv1_2;
        if (os_strstr(txt, "tls_disable_tlsv1_2=0"))
                params->flags &= ~TLS_CONN_DISABLE_TLSv1_2;
+       if (os_strstr(txt, "tls_ext_cert_check=1"))
+               params->flags |= TLS_CONN_EXT_CERT_CHECK;
+       if (os_strstr(txt, "tls_ext_cert_check=0"))
+               params->flags &= ~TLS_CONN_EXT_CERT_CHECK;
 }
 
 
@@ -181,6 +185,8 @@ static int eap_tls_params_from_conf(struct eap_sm *sm,
 
        params->openssl_ciphers = config->openssl_ciphers;
 
+       sm->ext_cert_check = !!(params->flags & TLS_CONN_EXT_CERT_CHECK);
+
        return 0;
 }
 
@@ -194,8 +200,10 @@ static int eap_tls_init_connection(struct eap_sm *sm,
 
        if (config->ocsp)
                params->flags |= TLS_CONN_REQUEST_OCSP;
-       if (config->ocsp == 2)
+       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 "
@@ -324,8 +332,8 @@ u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
        if (out == NULL)
                return NULL;
 
-       if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, 0,
-                              out, len)) {
+       if (tls_connection_export_key(data->ssl_ctx, data->conn, label, out,
+                                     len)) {
                os_free(out);
                return NULL;
        }
@@ -354,10 +362,8 @@ u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
        struct tls_random keys;
        u8 *out;
 
-       if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys))
-               return NULL;
-
-       if (keys.client_random == NULL || keys.server_random == NULL)
+       if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys) ||
+           keys.client_random == NULL || keys.server_random == NULL)
                return NULL;
 
        *len = 1 + keys.client_random_len + keys.server_random_len;
@@ -1042,6 +1048,9 @@ int eap_peer_select_phase2_methods(struct eap_peer_config *config,
                if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) {
                        wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP "
                                   "method '%s'", start);
+                       os_free(methods);
+                       os_free(buf);
+                       return -1;
                } else {
                        num_methods++;
                        _methods = os_realloc_array(methods, num_methods,
index 25b9f12..726221e 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "common.h"
 #include "eap_i.h"
+#include "eap_config.h"
 #include "tncc.h"
 
 
@@ -35,12 +36,16 @@ struct eap_tnc_data {
 static void * eap_tnc_init(struct eap_sm *sm)
 {
        struct eap_tnc_data *data;
+       struct eap_peer_config *config = eap_get_config(sm);
 
        data = os_zalloc(sizeof(*data));
        if (data == NULL)
                return NULL;
        data->state = WAIT_START;
-       data->fragment_size = 1300;
+       if (config && config->fragment_size)
+               data->fragment_size = config->fragment_size;
+       else
+               data->fragment_size = 1300;
        data->tncc = tncc_init();
        if (data->tncc == NULL) {
                os_free(data);
@@ -345,11 +350,6 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
        ret->decision = DECISION_UNCOND_SUCC;
        ret->allowNotifications = TRUE;
 
-       if (data->out_buf) {
-               data->state = PROC_MSG;
-               return eap_tnc_build_msg(data, ret, id);
-       }
-
        if (tncs_done) {
                resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1,
                                     EAP_CODE_RESPONSE, eap_get_id(reqData));
@@ -410,7 +410,6 @@ fail:
 int eap_peer_tnc_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC");
@@ -421,8 +420,5 @@ int eap_peer_tnc_register(void)
        eap->deinit = eap_tnc_deinit;
        eap->process = eap_tnc_process;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index c174fe5..12ea169 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -36,6 +36,7 @@ struct eap_ttls_data {
        void *phase2_priv;
        int phase2_success;
        int phase2_start;
+       EapDecision decision_succ;
 
        enum phase2_types {
                EAP_TTLS_PHASE2_EAP,
@@ -59,9 +60,10 @@ struct eap_ttls_data {
        size_t id_len;
 
        struct wpabuf *pending_phase2_req;
+       struct wpabuf *pending_resp;
        int chbind_req_sent; /* channel binding request was sent */
        int done_butfor_cb; /*we turned METHOD_DONE into METHOD_MAY_CONT to receive cb*/
-  EapDecision cbDecision;
+       EapDecision cbDecision;
 #ifdef EAP_TNC
        int ready_for_tnc;
        int tnc_started;
@@ -90,6 +92,7 @@ static void * eap_ttls_init(struct eap_sm *sm)
 {
        struct eap_ttls_data *data;
        struct eap_peer_config *config = eap_get_config(sm);
+       int selected_non_eap;
        char *selected;
 
        data = os_zalloc(sizeof(*data));
@@ -97,26 +100,67 @@ static void * eap_ttls_init(struct eap_sm *sm)
                return NULL;
        data->ttls_version = EAP_TTLS_VERSION;
        selected = "EAP";
+       selected_non_eap = 0;
        data->phase2_type = EAP_TTLS_PHASE2_EAP;
 
+       /*
+        * Either one auth= type or one or more autheap= methods can be
+        * specified.
+        */
        if (config && config->phase2) {
+               const char *token, *last = NULL;
+
+               while ((token = cstr_token(config->phase2, " \t", &last))) {
+                       if (os_strncmp(token, "auth=", 5) != 0)
+                               continue;
+                       token += 5;
+
+                       if (last - token == 8 &&
+                           os_strncmp(token, "MSCHAPV2", 8) == 0) {
+                               selected = "MSCHAPV2";
+                               data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2;
+                       } else if (last - token == 6 &&
+                                  os_strncmp(token, "MSCHAP", 6) == 0) {
+                               selected = "MSCHAP";
+                               data->phase2_type = EAP_TTLS_PHASE2_MSCHAP;
+                       } else if (last - token == 3 &&
+                                  os_strncmp(token, "PAP", 3) == 0) {
+                               selected = "PAP";
+                               data->phase2_type = EAP_TTLS_PHASE2_PAP;
+                       } else if (last - token == 4 &&
+                                  os_strncmp(token, "CHAP", 4) == 0) {
+                               selected = "CHAP";
+                               data->phase2_type = EAP_TTLS_PHASE2_CHAP;
+                       } else {
+                               wpa_printf(MSG_ERROR,
+                                          "EAP-TTLS: Unsupported Phase2 type '%s'",
+                                          token);
+                               eap_ttls_deinit(sm, data);
+                               return NULL;
+                       }
+
+                       if (selected_non_eap) {
+                               wpa_printf(MSG_ERROR,
+                                          "EAP-TTLS: Only one Phase2 type can be specified");
+                               eap_ttls_deinit(sm, data);
+                               return NULL;
+                       }
+
+                       selected_non_eap = 1;
+               }
+
                if (os_strstr(config->phase2, "autheap=")) {
+                       if (selected_non_eap) {
+                               wpa_printf(MSG_ERROR,
+                                          "EAP-TTLS: Both auth= and autheap= params cannot be specified");
+                               eap_ttls_deinit(sm, data);
+                               return NULL;
+                       }
                        selected = "EAP";
                        data->phase2_type = EAP_TTLS_PHASE2_EAP;
-               } else if (os_strstr(config->phase2, "auth=MSCHAPV2")) {
-                       selected = "MSCHAPV2";
-                       data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2;
-               } else if (os_strstr(config->phase2, "auth=MSCHAP")) {
-                       selected = "MSCHAP";
-                       data->phase2_type = EAP_TTLS_PHASE2_MSCHAP;
-               } else if (os_strstr(config->phase2, "auth=PAP")) {
-                       selected = "PAP";
-                       data->phase2_type = EAP_TTLS_PHASE2_PAP;
-               } else if (os_strstr(config->phase2, "auth=CHAP")) {
-                       selected = "CHAP";
-                       data->phase2_type = EAP_TTLS_PHASE2_CHAP;
                }
        }
+
        wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected);
 
        if (data->phase2_type == EAP_TTLS_PHASE2_EAP) {
@@ -173,6 +217,7 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
        eap_ttls_free_key(data);
        os_free(data->session_id);
        wpabuf_free(data->pending_phase2_req);
+       wpabuf_free(data->pending_resp);
        os_free(data);
 }
 
@@ -1643,6 +1688,32 @@ static int eap_ttls_process_handshake(struct eap_sm *sm,
 {
        int res;
 
+       if (sm->waiting_ext_cert_check && data->pending_resp) {
+               struct eap_peer_config *config = eap_get_config(sm);
+
+               if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-TTLS: External certificate check succeeded - continue handshake");
+                       *out_data = data->pending_resp;
+                       data->pending_resp = NULL;
+                       sm->waiting_ext_cert_check = 0;
+                       return 0;
+               }
+
+               if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-TTLS: External certificate check failed - force authentication failure");
+                       ret->methodState = METHOD_DONE;
+                       ret->decision = DECISION_FAIL;
+                       sm->waiting_ext_cert_check = 0;
+                       return 0;
+               }
+
+               wpa_printf(MSG_DEBUG,
+                          "EAP-TTLS: Continuing to wait external server certificate validation");
+               return 0;
+       }
+
        res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS,
                                          data->ttls_version, identifier,
                                          in_data, out_data);
@@ -1653,6 +1724,15 @@ static int eap_ttls_process_handshake(struct eap_sm *sm,
                return -1;
        }
 
+       if (sm->waiting_ext_cert_check) {
+               wpa_printf(MSG_DEBUG,
+                          "EAP-TTLS: Waiting external server certificate validation");
+               wpabuf_free(data->pending_resp);
+               data->pending_resp = *out_data;
+               *out_data = NULL;
+               return 0;
+       }
+
        if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
                wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to "
                           "Phase 2");
@@ -1703,6 +1783,7 @@ static void eap_ttls_check_auth_status(struct eap_sm *sm,
                        wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
                                   "completed successfully");
                        data->phase2_success = 1;
+                       data->decision_succ = ret->decision;
 #ifdef EAP_TNC
                        if (!data->ready_for_tnc && !data->tnc_started) {
                                /*
@@ -1720,6 +1801,18 @@ static void eap_ttls_check_auth_status(struct eap_sm *sm,
                        wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
                                   "completed successfully (MAY_CONT)");
                        data->phase2_success = 1;
+                       data->decision_succ = ret->decision;
+       } else if (data->decision_succ != DECISION_FAIL &&
+                  data->phase2_success &&
+                  !data->ssl.tls_out) {
+               /*
+                * This is needed to cover the case where the final Phase 2
+                * message gets fragmented since fragmentation clears
+                * decision back to FAIL.
+                */
+               wpa_printf(MSG_DEBUG,
+                          "EAP-TTLS: Restore success decision after fragmented frame sent completely");
+               ret->decision = data->decision_succ;
        }
 }
 
@@ -1792,6 +1885,9 @@ static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv)
        struct eap_ttls_data *data = priv;
        wpabuf_free(data->pending_phase2_req);
        data->pending_phase2_req = NULL;
+       wpabuf_free(data->pending_resp);
+       data->pending_resp = NULL;
+       data->decision_succ = DECISION_FAIL;
 #ifdef EAP_TNC
        data->ready_for_tnc = 0;
        data->tnc_started = 0;
@@ -1930,7 +2026,6 @@ static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_ttls_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS");
@@ -1949,8 +2044,5 @@ int eap_peer_ttls_register(void)
        eap->init_for_reauth = eap_ttls_init_for_reauth;
        eap->get_emsk = eap_ttls_get_emsk;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index b61057e..16e3c39 100644 (file)
@@ -169,7 +169,6 @@ static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_vendor_test_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_ID, EAP_VENDOR_TYPE,
@@ -183,8 +182,5 @@ int eap_peer_vendor_test_register(void)
        eap->isKeyAvailable = eap_vendor_test_isKeyAvailable;
        eap->getKey = eap_vendor_test_getKey;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index 7ac99c7..d140c88 100644 (file)
@@ -17,7 +17,7 @@
 
 
 struct eap_wsc_data {
-       enum { WAIT_START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
+       enum { WAIT_START, MESG, WAIT_FRAG_ACK, FAIL } state;
        int registrar;
        struct wpabuf *in_buf;
        struct wpabuf *out_buf;
@@ -36,12 +36,8 @@ static const char * eap_wsc_state_txt(int state)
                return "WAIT_START";
        case MESG:
                return "MESG";
-       case FRAG_ACK:
-               return "FRAG_ACK";
        case WAIT_FRAG_ACK:
                return "WAIT_FRAG_ACK";
-       case DONE:
-               return "DONE";
        case FAIL:
                return "FAIL";
        default:
@@ -579,7 +575,6 @@ send_msg:
 int eap_peer_wsc_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
@@ -591,8 +586,5 @@ int eap_peer_wsc_register(void)
        eap->deinit = eap_wsc_deinit;
        eap->process = eap_wsc_process;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }
index 55ab72a..ca6502e 100644 (file)
@@ -128,7 +128,7 @@ static int ikev2_parse_transform(struct ikev2_proposal_data *prop,
 
        t = (const struct ikev2_transform *) pos;
        transform_len = WPA_GET_BE16(t->transform_length);
-       if (transform_len < (int) sizeof(*t) || pos + transform_len > end) {
+       if (transform_len < (int) sizeof(*t) || transform_len > end - pos) {
                wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d",
                           transform_len);
                return -1;
@@ -248,7 +248,7 @@ static int ikev2_parse_proposal(struct ikev2_proposal_data *prop,
 
        ppos = (const u8 *) (p + 1);
        pend = pos + proposal_len;
-       if (ppos + p->spi_size > pend) {
+       if (p->spi_size > pend - ppos) {
                wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI "
                           "in proposal");
                return -1;
index 7ca956e..0c5caa7 100644 (file)
@@ -104,7 +104,7 @@ static struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL };
 
 /* TNCC functions that IMCs can call */
 
-TNC_Result TNC_TNCC_ReportMessageTypes(
+static TNC_Result TNC_TNCC_ReportMessageTypes(
        TNC_IMCID imcID,
        TNC_MessageTypeList supportedTypes,
        TNC_UInt32 typeCount)
@@ -138,7 +138,7 @@ TNC_Result TNC_TNCC_ReportMessageTypes(
 }
 
 
-TNC_Result TNC_TNCC_SendMessage(
+static TNC_Result TNC_TNCC_SendMessage(
        TNC_IMCID imcID,
        TNC_ConnectionID connectionID,
        TNC_BufferReference message,
@@ -183,7 +183,7 @@ TNC_Result TNC_TNCC_SendMessage(
 }
 
 
-TNC_Result TNC_TNCC_RequestHandshakeRetry(
+static TNC_Result TNC_TNCC_RequestHandshakeRetry(
        TNC_IMCID imcID,
        TNC_ConnectionID connectionID,
        TNC_RetryReason reason)
@@ -203,8 +203,8 @@ TNC_Result TNC_TNCC_RequestHandshakeRetry(
 }
 
 
-TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
-                              const char *message)
+static TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
+                                     const char *message)
 {
        wpa_printf(MSG_DEBUG, "TNC: TNC_9048_LogMessage(imcID=%lu "
                   "severity==%lu message='%s')",
@@ -213,8 +213,9 @@ TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
 }
 
 
-TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID, TNC_ConnectionID connectionID,
-                               const char *message)
+static TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID,
+                                      TNC_ConnectionID connectionID,
+                                      const char *message)
 {
        wpa_printf(MSG_DEBUG, "TNC: TNC_9048_UserMessage(imcID=%lu "
                   "connectionID==%lu message='%s')",
@@ -223,7 +224,7 @@ TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID, TNC_ConnectionID connectionID,
 }
 
 
-TNC_Result TNC_TNCC_BindFunction(
+static TNC_Result TNC_TNCC_BindFunction(
        TNC_IMCID imcID,
        char *functionName,
        void **pOutfunctionPointer)
@@ -694,6 +695,8 @@ enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
        enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
        int recommendation_msg = 0;
 
+       wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Received IF-TNCCS message",
+                         msg, len);
        buf = dup_binstr(msg, len);
        if (buf == NULL)
                return TNCCS_PROCESS_ERROR;
index 0baa327..3bf1495 100644 (file)
@@ -15,7 +15,6 @@ const struct eap_method * eap_server_get_eap_method(int vendor,
                                                    EapType method);
 struct eap_method * eap_server_method_alloc(int version, int vendor,
                                            EapType method, const char *name);
-void eap_server_method_free(struct eap_method *method);
 int eap_server_method_register(struct eap_method *method);
 
 EapType eap_server_get_type(const char *name, int *vendor);
index db9b6aa..a8bb5ea 100644 (file)
@@ -1319,7 +1319,6 @@ static u8 * eap_aka_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_server_aka_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
@@ -1337,10 +1336,7 @@ int eap_server_aka_register(void)
        eap->get_emsk = eap_aka_get_emsk;
        eap->getSessionId = eap_aka_get_session_id;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
 
 
@@ -1348,7 +1344,6 @@ int eap_server_aka_register(void)
 int eap_server_aka_prime_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
@@ -1367,10 +1362,6 @@ int eap_server_aka_prime_register(void)
        eap->get_emsk = eap_aka_get_emsk;
        eap->getSessionId = eap_aka_get_session_id;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-
-       return ret;
+       return eap_server_method_register(eap);
 }
 #endif /* EAP_SERVER_AKA_PRIME */
index ba82be9..1eba8f5 100644 (file)
@@ -792,7 +792,6 @@ static u8 * eap_eke_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_server_eke_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
@@ -810,8 +809,5 @@ int eap_server_eke_register(void)
        eap->get_emsk = eap_eke_get_emsk;
        eap->getSessionId = eap_eke_get_session_id;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
index bd9018e..2049172 100644 (file)
@@ -180,42 +180,47 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
                        buf, end - buf);
 
        pos = buf;
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
+       while (end - pos > 1) {
+               u8 id, elen;
+
+               id = *pos++;
+               elen = *pos++;
+               if (elen > end - pos)
                        break;
 
-               switch (*pos) {
+               switch (id) {
                case PAC_OPAQUE_TYPE_PAD:
                        goto done;
                case PAC_OPAQUE_TYPE_KEY:
-                       if (pos[1] != EAP_FAST_PAC_KEY_LEN) {
-                               wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
-                                          "PAC-Key length %d", pos[1]);
+                       if (elen != EAP_FAST_PAC_KEY_LEN) {
+                               wpa_printf(MSG_DEBUG,
+                                          "EAP-FAST: Invalid PAC-Key length %d",
+                                          elen);
                                os_free(buf);
                                return -1;
                        }
-                       pac_key = pos + 2;
+                       pac_key = pos;
                        wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key from "
                                        "decrypted PAC-Opaque",
                                        pac_key, EAP_FAST_PAC_KEY_LEN);
                        break;
                case PAC_OPAQUE_TYPE_LIFETIME:
-                       if (pos[1] != 4) {
+                       if (elen != 4) {
                                wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
                                           "PAC-Key lifetime length %d",
-                                          pos[1]);
+                                          elen);
                                os_free(buf);
                                return -1;
                        }
-                       lifetime = WPA_GET_BE32(pos + 2);
+                       lifetime = WPA_GET_BE32(pos);
                        break;
                case PAC_OPAQUE_TYPE_IDENTITY:
-                       identity = pos + 2;
-                       identity_len = pos[1];
+                       identity = pos;
+                       identity_len = elen;
                        break;
                }
 
-               pos += 2 + pos[1];
+               pos += elen;
        }
 done:
 
@@ -273,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, "key expansion",
+       sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
                                  EAP_FAST_SKS_LEN);
        if (sks == NULL) {
                wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
@@ -300,7 +305,6 @@ 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,
-                                   "key expansion",
                                    sizeof(*data->key_block_p));
        if (data->key_block_p == NULL) {
                wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
@@ -407,11 +411,13 @@ static int eap_fast_update_icmk(struct eap_sm *sm, struct eap_fast_data *data)
 static void * eap_fast_init(struct eap_sm *sm)
 {
        struct eap_fast_data *data;
-       u8 ciphers[5] = {
+       u8 ciphers[7] = {
                TLS_CIPHER_ANON_DH_AES128_SHA,
                TLS_CIPHER_AES128_SHA,
                TLS_CIPHER_RSA_DHE_AES128_SHA,
                TLS_CIPHER_RC4_SHA,
+               TLS_CIPHER_RSA_DHE_AES256_SHA,
+               TLS_CIPHER_AES256_SHA,
                TLS_CIPHER_NONE
        };
 
@@ -1134,7 +1140,7 @@ static int eap_fast_parse_tlvs(struct wpabuf *data,
 
        pos = wpabuf_mhead(data);
        end = pos + wpabuf_len(data);
-       while (pos + 4 < end) {
+       while (end - pos > 4) {
                mandatory = pos[0] & 0x80;
                tlv_type = WPA_GET_BE16(pos) & 0x3fff;
                pos += 2;
@@ -1559,7 +1565,10 @@ static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
        if (eapKeyData == NULL)
                return NULL;
 
-       eap_fast_derive_eap_msk(data->simck, eapKeyData);
+       if (eap_fast_derive_eap_msk(data->simck, eapKeyData) < 0) {
+               os_free(eapKeyData);
+               return NULL;
+       }
        *len = EAP_FAST_KEY_LEN;
 
        return eapKeyData;
@@ -1578,7 +1587,10 @@ static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
        if (eapKeyData == NULL)
                return NULL;
 
-       eap_fast_derive_eap_emsk(data->simck, eapKeyData);
+       if (eap_fast_derive_eap_emsk(data->simck, eapKeyData) < 0) {
+               os_free(eapKeyData);
+               return NULL;
+       }
        *len = EAP_EMSK_LEN;
 
        return eapKeyData;
@@ -1607,7 +1619,6 @@ static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_server_fast_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST");
@@ -1625,8 +1636,5 @@ int eap_server_fast_register(void)
        eap->isSuccess = eap_fast_isSuccess;
        eap->getSessionId = eap_fast_get_session_id;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
index 50f15c3..94e74ec 100644 (file)
@@ -631,7 +631,6 @@ static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_server_gpsk_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
@@ -649,8 +648,5 @@ int eap_server_gpsk_register(void)
        eap->get_emsk = eap_gpsk_get_emsk;
        eap->getSessionId = eap_gpsk_get_session_id;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
index 98ac3c6..193a851 100644 (file)
@@ -202,7 +202,6 @@ static Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv)
 int eap_server_gtc_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC");
@@ -217,8 +216,5 @@ int eap_server_gtc_register(void)
        eap->isDone = eap_gtc_isDone;
        eap->isSuccess = eap_gtc_isSuccess;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
index 4501533..1b1db53 100644 (file)
@@ -157,7 +157,6 @@ static Boolean eap_identity_isSuccess(struct eap_sm *sm, void *priv)
 int eap_server_identity_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
@@ -174,8 +173,5 @@ int eap_server_identity_register(void)
        eap->isDone = eap_identity_isDone;
        eap->isSuccess = eap_identity_isSuccess;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
index 16e6276..3a249d1 100644 (file)
@@ -550,7 +550,6 @@ static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_server_ikev2_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_IKEV2,
@@ -569,8 +568,5 @@ int eap_server_ikev2_register(void)
        eap->get_emsk = eap_ikev2_get_emsk;
        eap->getSessionId = eap_ikev2_get_session_id;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
index 71e8d59..cf5ceb1 100644 (file)
@@ -153,7 +153,6 @@ static Boolean eap_md5_isSuccess(struct eap_sm *sm, void *priv)
 int eap_server_md5_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5");
@@ -168,8 +167,5 @@ int eap_server_md5_register(void)
        eap->isDone = eap_md5_isDone;
        eap->isSuccess = eap_md5_isSuccess;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
index 9e9dc93..79ed344 100644 (file)
@@ -87,7 +87,7 @@ struct eap_method * eap_server_method_alloc(int version, int vendor,
  * eap_server_method_free - Free EAP server method structure
  * @method: Method structure allocated with eap_server_method_alloc()
  */
-void eap_server_method_free(struct eap_method *method)
+static void eap_server_method_free(struct eap_method *method)
 {
        os_free(method);
 }
@@ -95,26 +95,31 @@ void eap_server_method_free(struct eap_method *method)
 
 /**
  * eap_server_method_register - Register an EAP server method
- * @method: EAP method to register
+ * @method: EAP method to register from eap_server_method_alloc()
  * Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method
  * has already been registered
  *
  * Each EAP server method needs to call this function to register itself as a
- * supported EAP method.
+ * supported EAP method. The caller must not free the allocated method data
+ * regardless of the return value.
  */
 int eap_server_method_register(struct eap_method *method)
 {
        struct eap_method *m, *last = NULL;
 
        if (method == NULL || method->name == NULL ||
-           method->version != EAP_SERVER_METHOD_INTERFACE_VERSION)
+           method->version != EAP_SERVER_METHOD_INTERFACE_VERSION) {
+               eap_server_method_free(method);
                return -1;
+       }
 
        for (m = eap_methods; m; m = m->next) {
                if ((m->vendor == method->vendor &&
                     m->method == method->method) ||
-                   os_strcmp(m->name, method->name) == 0)
+                   os_strcmp(m->name, method->name) == 0) {
+                       eap_server_method_free(method);
                        return -2;
+               }
                last = m;
        }
 
index 98d74e0..460cd9c 100644 (file)
@@ -571,7 +571,6 @@ static Boolean eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv)
 int eap_server_mschapv2_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
@@ -588,8 +587,5 @@ int eap_server_mschapv2_register(void)
        eap->getKey = eap_mschapv2_getKey;
        eap->isSuccess = eap_mschapv2_isSuccess;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
index 0e6b4a0..782b8c3 100644 (file)
@@ -565,7 +565,6 @@ static u8 * eap_pax_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_server_pax_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_PAX, "PAX");
@@ -583,8 +582,5 @@ int eap_server_pax_register(void)
        eap->get_emsk = eap_pax_get_emsk;
        eap->getSessionId = eap_pax_get_session_id;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
index 51062b0..18d31b5 100644 (file)
@@ -335,6 +335,18 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
                return -1;
        wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
 
+       if (tls_connection_resumed(sm->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",
+                               data->ipmk, 40);
+               os_memcpy(data->cmk, tk + 40, 20);
+               wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK",
+                               data->cmk, 20);
+               os_free(tk);
+               return 0;
+       }
+
        eap_peap_get_isk(data, isk, sizeof(isk));
        wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
 
@@ -357,7 +369,6 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
 
        os_free(tk);
 
-       /* TODO: fast-connect: IPMK|CMK = TK */
        os_memcpy(data->ipmk, imck, 40);
        wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
        os_memcpy(data->cmk, imck + 40, 20);
@@ -1267,8 +1278,9 @@ static void eap_peap_process(struct eap_sm *sm, void *priv,
 
        wpa_printf(MSG_DEBUG,
                   "EAP-PEAP: Resuming previous session - skip Phase2");
-       eap_peap_state(data, SUCCESS_REQ);
-       tls_connection_set_success_data_resumed(data->ssl.conn);
+       eap_peap_req_success(sm, data);
+       if (data->state == SUCCESS_REQ)
+               tls_connection_set_success_data_resumed(data->ssl.conn);
 }
 
 
@@ -1351,7 +1363,6 @@ static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_server_peap_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
@@ -1368,8 +1379,5 @@ int eap_server_peap_register(void)
        eap->isSuccess = eap_peap_isSuccess;
        eap->getSessionId = eap_peap_get_session_id;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
index 12b5d25..857d421 100644 (file)
@@ -510,7 +510,6 @@ static u8 * eap_psk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_server_psk_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK");
@@ -528,8 +527,5 @@ int eap_server_psk_register(void)
        eap->get_emsk = eap_psk_get_emsk;
        eap->getSessionId = eap_psk_get_session_id;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
index cb83ff7..64bf708 100644 (file)
@@ -178,8 +178,13 @@ static void eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data,
                return;
        }
 
-       /* an lfsr is good enough to generate unpredictable tokens */
-       data->token = os_random();
+       if (os_get_random((u8 *) &data->token, sizeof(data->token)) < 0) {
+               wpabuf_free(data->outbuf);
+               data->outbuf = NULL;
+               eap_pwd_state(data, FAILURE);
+               return;
+       }
+
        wpabuf_put_be16(data->outbuf, data->group_num);
        wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC);
        wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF);
@@ -970,7 +975,7 @@ static void eap_pwd_process(struct eap_sm *sm, void *priv,
        /*
         * the first and all intermediate fragments have the M bit set
         */
-       if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
+       if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) {
                if ((data->in_frag_pos + len) > wpabuf_size(data->inbuf)) {
                        wpa_printf(MSG_DEBUG, "EAP-pwd: Buffer overflow "
                                   "attack detected! (%d+%d > %d)",
@@ -981,6 +986,8 @@ static void eap_pwd_process(struct eap_sm *sm, void *priv,
                }
                wpabuf_put_data(data->inbuf, pos, len);
                data->in_frag_pos += len;
+       }
+       if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
                wpa_printf(MSG_DEBUG, "EAP-pwd: Got a %d byte fragment",
                           (int) len);
                return;
@@ -990,8 +997,6 @@ static void eap_pwd_process(struct eap_sm *sm, void *priv,
         * buffering fragments so that's how we know it's the last)
         */
        if (data->in_frag_pos) {
-               wpabuf_put_data(data->inbuf, pos, len);
-               data->in_frag_pos += len;
                pos = wpabuf_head_u8(data->inbuf);
                len = data->in_frag_pos;
                wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes",
@@ -1094,7 +1099,6 @@ static u8 * eap_pwd_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_server_pwd_register(void)
 {
        struct eap_method *eap;
-       int ret;
        struct timeval tp;
        struct timezone tz;
        u32 sr;
@@ -1121,9 +1125,6 @@ int eap_server_pwd_register(void)
        eap->isSuccess = eap_pwd_is_success;
        eap->getSessionId = eap_pwd_get_session_id;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
 
index de70777..84d0e0b 100644 (file)
@@ -520,7 +520,6 @@ static u8 * eap_sake_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_server_sake_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
@@ -538,8 +537,5 @@ int eap_server_sake_register(void)
        eap->get_emsk = eap_sake_get_emsk;
        eap->getSessionId = eap_sake_get_session_id;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
index ddfb71c..3a6ed79 100644 (file)
@@ -846,7 +846,6 @@ static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_server_sim_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
@@ -864,8 +863,5 @@ int eap_server_sim_register(void)
        eap->get_emsk = eap_sim_get_emsk;
        eap->getSessionId = eap_sim_get_session_id;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
index bd18a4b..7249858 100644 (file)
@@ -375,7 +375,6 @@ static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_server_tls_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
@@ -393,10 +392,7 @@ int eap_server_tls_register(void)
        eap->get_emsk = eap_tls_get_emsk;
        eap->getSessionId = eap_tls_get_session_id;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
 
 
@@ -404,7 +400,6 @@ int eap_server_tls_register(void)
 int eap_server_unauth_tls_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_UNAUTH_TLS,
@@ -423,10 +418,7 @@ int eap_server_unauth_tls_register(void)
        eap->isSuccess = eap_tls_isSuccess;
        eap->get_emsk = eap_tls_get_emsk;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
 #endif /* EAP_SERVER_UNAUTH_TLS */
 
@@ -435,7 +427,6 @@ int eap_server_unauth_tls_register(void)
 int eap_server_wfa_unauth_tls_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_WFA_NEW,
@@ -454,9 +445,6 @@ int eap_server_wfa_unauth_tls_register(void)
        eap->isSuccess = eap_tls_isSuccess;
        eap->get_emsk = eap_tls_get_emsk;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
 #endif /* CONFIG_HS20 */
index 05677b7..6909695 100644 (file)
@@ -115,8 +115,8 @@ u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
        if (out == NULL)
                return NULL;
 
-       if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, 0,
-                              out, len)) {
+       if (tls_connection_export_key(sm->ssl_ctx, data->conn, label, out,
+                                     len)) {
                os_free(out);
                return NULL;
        }
index 21bd26f..b568558 100644 (file)
@@ -554,7 +554,6 @@ static Boolean eap_tnc_isSuccess(struct eap_sm *sm, void *priv)
 int eap_server_tnc_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC");
@@ -569,8 +568,5 @@ int eap_server_tnc_register(void)
        eap->isDone = eap_tnc_isDone;
        eap->isSuccess = eap_tnc_isSuccess;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
index 53ffa1e..a53633f 100644 (file)
@@ -1335,7 +1335,6 @@ static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 int eap_server_ttls_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS");
@@ -1353,8 +1352,5 @@ int eap_server_ttls_register(void)
        eap->getSessionId = eap_ttls_get_session_id;
        eap->get_emsk = eap_ttls_get_emsk;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
index 30f600d..9639977 100644 (file)
@@ -168,7 +168,6 @@ static Boolean eap_vendor_test_isSuccess(struct eap_sm *sm, void *priv)
 int eap_server_vendor_test_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_ID, EAP_VENDOR_TYPE,
@@ -185,8 +184,5 @@ int eap_server_vendor_test_register(void)
        eap->getKey = eap_vendor_test_getKey;
        eap->isSuccess = eap_vendor_test_isSuccess;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
index 9d9c28d..7d9d285 100644 (file)
@@ -488,7 +488,6 @@ static int eap_wsc_getTimeout(struct eap_sm *sm, void *priv)
 int eap_server_wsc_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
@@ -505,8 +504,5 @@ int eap_server_wsc_register(void)
        eap->isSuccess = eap_wsc_isSuccess;
        eap->getTimeout = eap_wsc_getTimeout;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }
index acf5435..d84c3d2 100644 (file)
@@ -66,6 +66,7 @@ struct eap_sim_db_data {
        struct eap_sim_pseudonym *pseudonyms;
        struct eap_sim_reauth *reauths;
        struct eap_sim_db_pending *pending;
+       unsigned int eap_sim_db_timeout;
 #ifdef CONFIG_SQLITE
        sqlite3 *sqlite_db;
        char db_tmp_identity[100];
@@ -76,6 +77,10 @@ struct eap_sim_db_data {
 };
 
 
+static void eap_sim_db_del_timeout(void *eloop_ctx, void *user_ctx);
+static void eap_sim_db_query_timeout(void *eloop_ctx, void *user_ctx);
+
+
 #ifdef CONFIG_SQLITE
 
 static int db_table_exists(sqlite3 *db, const char *name)
@@ -397,6 +402,57 @@ static void eap_sim_db_add_pending(struct eap_sim_db_data *data,
 }
 
 
+static void eap_sim_db_free_pending(struct eap_sim_db_data *data,
+                                   struct eap_sim_db_pending *entry)
+{
+       eloop_cancel_timeout(eap_sim_db_query_timeout, data, entry);
+       eloop_cancel_timeout(eap_sim_db_del_timeout, data, entry);
+       os_free(entry);
+}
+
+
+static void eap_sim_db_del_pending(struct eap_sim_db_data *data,
+                                  struct eap_sim_db_pending *entry)
+{
+       struct eap_sim_db_pending **pp = &data->pending;
+
+       while (*pp != NULL) {
+               if (*pp == entry) {
+                       *pp = entry->next;
+                       eap_sim_db_free_pending(data, entry);
+                       return;
+               }
+               pp = &(*pp)->next;
+       }
+}
+
+
+static void eap_sim_db_del_timeout(void *eloop_ctx, void *user_ctx)
+{
+       struct eap_sim_db_data *data = eloop_ctx;
+       struct eap_sim_db_pending *entry = user_ctx;
+
+       wpa_printf(MSG_DEBUG, "EAP-SIM DB: Delete query timeout for %p", entry);
+       eap_sim_db_del_pending(data, entry);
+}
+
+
+static void eap_sim_db_query_timeout(void *eloop_ctx, void *user_ctx)
+{
+       struct eap_sim_db_data *data = eloop_ctx;
+       struct eap_sim_db_pending *entry = user_ctx;
+
+       /*
+        * Report failure and allow some time for EAP server to process it
+        * before deleting the query.
+        */
+       wpa_printf(MSG_DEBUG, "EAP-SIM DB: Query timeout for %p", entry);
+       entry->state = FAILURE;
+       data->get_complete_cb(data->ctx, entry->cb_session_ctx);
+       eloop_register_timeout(1, 0, eap_sim_db_del_timeout, data, entry);
+}
+
+
 static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
                                     const char *imsi, char *buf)
 {
@@ -472,7 +528,7 @@ static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
 
 parse_fail:
        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
-       os_free(entry);
+       eap_sim_db_free_pending(data, entry);
 }
 
 
@@ -563,7 +619,7 @@ static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data,
 
 parse_fail:
        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
-       os_free(entry);
+       eap_sim_db_free_pending(data, entry);
 }
 
 
@@ -690,12 +746,13 @@ static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
 /**
  * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface
  * @config: Configuration data (e.g., file name)
+ * @db_timeout: Database lookup timeout
  * @get_complete_cb: Callback function for reporting availability of triplets
  * @ctx: Context pointer for get_complete_cb
  * Returns: Pointer to a private data structure or %NULL on failure
  */
 struct eap_sim_db_data *
-eap_sim_db_init(const char *config,
+eap_sim_db_init(const char *config, unsigned int db_timeout,
                void (*get_complete_cb)(void *ctx, void *session_ctx),
                void *ctx)
 {
@@ -709,6 +766,7 @@ eap_sim_db_init(const char *config,
        data->sock = -1;
        data->get_complete_cb = get_complete_cb;
        data->ctx = ctx;
+       data->eap_sim_db_timeout = db_timeout;
        data->fname = os_strdup(config);
        if (data->fname == NULL)
                goto fail;
@@ -796,7 +854,7 @@ void eap_sim_db_deinit(void *priv)
        while (pending) {
                prev_pending = pending;
                pending = pending->next;
-               os_free(prev_pending);
+               eap_sim_db_free_pending(data, prev_pending);
        }
 
        os_free(data);
@@ -833,11 +891,11 @@ static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
 }
 
 
-static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
+static void eap_sim_db_expire_pending(struct eap_sim_db_data *data,
+                                     struct eap_sim_db_pending *entry)
 {
-       /* TODO: add limit for maximum length for pending list; remove latest
-        * (i.e., last) entry from the list if the limit is reached; could also
-        * use timeout to expire pending entries */
+       eloop_register_timeout(data->eap_sim_db_timeout, 0,
+                              eap_sim_db_query_timeout, data, entry);
 }
 
 
@@ -891,7 +949,7 @@ int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
                if (entry->state == FAILURE) {
                        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
                                   "failure");
-                       os_free(entry);
+                       eap_sim_db_free_pending(data, entry);
                        return EAP_SIM_DB_FAILURE;
                }
 
@@ -911,7 +969,7 @@ int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
                os_memcpy(sres, entry->u.sim.sres,
                          num_chal * EAP_SIM_SRES_LEN);
                os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN);
-               os_free(entry);
+               eap_sim_db_free_pending(data, entry);
                return num_chal;
        }
 
@@ -945,7 +1003,8 @@ int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
        entry->cb_session_ctx = cb_session_ctx;
        entry->state = PENDING;
        eap_sim_db_add_pending(data, entry);
-       eap_sim_db_expire_pending(data);
+       eap_sim_db_expire_pending(data, entry);
+       wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added query %p", entry);
 
        return EAP_SIM_DB_PENDING;
 }
@@ -1356,7 +1415,7 @@ int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
        entry = eap_sim_db_get_pending(data, imsi, 1);
        if (entry) {
                if (entry->state == FAILURE) {
-                       os_free(entry);
+                       eap_sim_db_free_pending(data, entry);
                        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
                        return EAP_SIM_DB_FAILURE;
                }
@@ -1375,7 +1434,7 @@ int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
                os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN);
                os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN);
                *res_len = entry->u.aka.res_len;
-               os_free(entry);
+               eap_sim_db_free_pending(data, entry);
                return 0;
        }
 
@@ -1406,7 +1465,8 @@ int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
        entry->cb_session_ctx = cb_session_ctx;
        entry->state = PENDING;
        eap_sim_db_add_pending(data, entry);
-       eap_sim_db_expire_pending(data);
+       eap_sim_db_expire_pending(data, entry);
+       wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added query %p", entry);
 
        return EAP_SIM_DB_PENDING;
 }
index 53a1a7c..ca900b9 100644 (file)
@@ -31,7 +31,7 @@ enum eap_sim_db_method {
 struct eap_sim_db_data;
 
 struct eap_sim_db_data *
-eap_sim_db_init(const char *config,
+eap_sim_db_init(const char *config, unsigned int db_timeout,
                void (*get_complete_cb)(void *ctx, void *session_ctx),
                void *ctx);
 
index 632598f..5385cd8 100644 (file)
@@ -133,7 +133,7 @@ static int ikev2_parse_transform(struct ikev2_initiator_data *data,
 
        t = (const struct ikev2_transform *) pos;
        transform_len = WPA_GET_BE16(t->transform_length);
-       if (transform_len < (int) sizeof(*t) || pos + transform_len > end) {
+       if (transform_len < (int) sizeof(*t) || transform_len > end - pos) {
                wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d",
                           transform_len);
                return -1;
@@ -221,7 +221,7 @@ static int ikev2_parse_proposal(struct ikev2_initiator_data *data,
 
        p = (const struct ikev2_proposal *) pos;
        proposal_len = WPA_GET_BE16(p->proposal_length);
-       if (proposal_len < (int) sizeof(*p) || pos + proposal_len > end) {
+       if (proposal_len < (int) sizeof(*p) || proposal_len > end - pos) {
                wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d",
                           proposal_len);
                return -1;
@@ -256,7 +256,7 @@ static int ikev2_parse_proposal(struct ikev2_initiator_data *data,
 
        ppos = (const u8 *) (p + 1);
        pend = pos + proposal_len;
-       if (ppos + p->spi_size > pend) {
+       if (p->spi_size > pend - ppos) {
                wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI "
                           "in proposal");
                return -1;
index dc6f689..cfcbd3e 100644 (file)
@@ -140,7 +140,7 @@ static struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID)
 
 
 /* TNCS functions that IMVs can call */
-TNC_Result TNC_TNCS_ReportMessageTypes(
+static TNC_Result TNC_TNCS_ReportMessageTypes(
        TNC_IMVID imvID,
        TNC_MessageTypeList supportedTypes,
        TNC_UInt32 typeCount)
@@ -173,7 +173,7 @@ TNC_Result TNC_TNCS_ReportMessageTypes(
 }
 
 
-TNC_Result TNC_TNCS_SendMessage(
+static TNC_Result TNC_TNCS_SendMessage(
        TNC_IMVID imvID,
        TNC_ConnectionID connectionID,
        TNC_BufferReference message,
@@ -222,7 +222,7 @@ TNC_Result TNC_TNCS_SendMessage(
 }
 
 
-TNC_Result TNC_TNCS_RequestHandshakeRetry(
+static TNC_Result TNC_TNCS_RequestHandshakeRetry(
        TNC_IMVID imvID,
        TNC_ConnectionID connectionID,
        TNC_RetryReason reason)
@@ -233,7 +233,7 @@ TNC_Result TNC_TNCS_RequestHandshakeRetry(
 }
 
 
-TNC_Result TNC_TNCS_ProvideRecommendation(
+static TNC_Result TNC_TNCS_ProvideRecommendation(
        TNC_IMVID imvID,
        TNC_ConnectionID connectionID,
        TNC_IMV_Action_Recommendation recommendation,
@@ -260,7 +260,7 @@ TNC_Result TNC_TNCS_ProvideRecommendation(
 }
 
 
-TNC_Result TNC_TNCS_GetAttribute(
+static TNC_Result TNC_TNCS_GetAttribute(
        TNC_IMVID imvID,
        TNC_ConnectionID connectionID,
        TNC_AttributeID attribureID,
@@ -274,7 +274,7 @@ TNC_Result TNC_TNCS_GetAttribute(
 }
 
 
-TNC_Result TNC_TNCS_SetAttribute(
+static TNC_Result TNC_TNCS_SetAttribute(
        TNC_IMVID imvID,
        TNC_ConnectionID connectionID,
        TNC_AttributeID attribureID,
@@ -287,7 +287,7 @@ TNC_Result TNC_TNCS_SetAttribute(
 }
 
 
-TNC_Result TNC_TNCS_BindFunction(
+static TNC_Result TNC_TNCS_BindFunction(
        TNC_IMVID imvID,
        char *functionName,
        void **pOutFunctionPointer)
index ff33d28..ff673bb 100644 (file)
@@ -866,10 +866,13 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
                sm->radius_cui = wpabuf_alloc_copy(radius_cui,
                                                   os_strlen(radius_cui));
 
-       sm->acct_multi_session_id_lo = eapol->acct_multi_session_id_lo++;
-       if (eapol->acct_multi_session_id_lo == 0)
-               eapol->acct_multi_session_id_hi++;
-       sm->acct_multi_session_id_hi = eapol->acct_multi_session_id_hi;
+#ifndef CONFIG_NO_RADIUS
+       if (radius_gen_session_id((u8 *) &sm->acct_multi_session_id,
+                                 sizeof(sm->acct_multi_session_id)) < 0) {
+               eapol_auth_free(sm);
+               return NULL;
+       }
+#endif /* CONFIG_NO_RADIUS */
 
        return sm;
 }
@@ -884,6 +887,9 @@ void eapol_auth_free(struct eapol_state_machine *sm)
        eloop_cancel_timeout(eapol_sm_step_cb, sm, NULL);
        if (sm->eap)
                eap_server_sm_deinit(sm->eap);
+
+       wpabuf_free(sm->radius_cui);
+       os_free(sm->identity);
        os_free(sm);
 }
 
@@ -1271,7 +1277,6 @@ struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
                                             struct eapol_auth_cb *cb)
 {
        struct eapol_authenticator *eapol;
-       struct os_time now;
 
        eapol = os_zalloc(sizeof(*eapol));
        if (eapol == NULL)
@@ -1300,12 +1305,6 @@ struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
        eapol->cb.erp_get_key = cb->erp_get_key;
        eapol->cb.erp_add_key = cb->erp_add_key;
 
-       /* Acct-Multi-Session-Id should be unique over reboots. If reliable
-        * clock is not available, this could be replaced with reboot counter,
-        * etc. */
-       os_get_time(&now);
-       eapol->acct_multi_session_id_hi = now.sec;
-
        return eapol;
 }
 
index a29b49c..04386b2 100644 (file)
@@ -30,9 +30,6 @@ struct eapol_authenticator {
 
        u8 *default_wep_key;
        u8 default_wep_key_idx;
-
-       u32 acct_multi_session_id_hi;
-       u32 acct_multi_session_id_lo;
 };
 
 
@@ -162,12 +159,6 @@ struct eapol_state_machine {
        struct radius_class_data radius_class;
        struct wpabuf *radius_cui; /* Chargeable-User-Identity */
 
-       /* Keys for encrypting and signing EAPOL-Key frames */
-       u8 *eapol_key_sign;
-       size_t eapol_key_sign_len;
-       u8 *eapol_key_crypt;
-       size_t eapol_key_crypt_len;
-
        struct eap_sm *eap;
 
        Boolean initializing; /* in process of initializing state machines */
@@ -179,8 +170,7 @@ struct eapol_state_machine {
 
        int remediation;
 
-       u32 acct_multi_session_id_hi;
-       u32 acct_multi_session_id_lo;
+       u64 acct_multi_session_id;
 };
 
 #endif /* EAPOL_AUTH_SM_I_H */
index 09cf4f6..65460fc 100644 (file)
@@ -314,6 +314,16 @@ SM_STATE(SUPP_PAE, RESTART)
 {
        SM_ENTRY(SUPP_PAE, RESTART);
        sm->eapRestart = TRUE;
+       if (sm->altAccept) {
+               /*
+                * Prevent EAP peer state machine from failing due to prior
+                * 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;
+       }
 }
 
 
index 2880870..32cd941 100644 (file)
@@ -15,6 +15,7 @@
 #include "fst/fst_defs.h"
 #include "fst/fst_ctrl_iface.h"
 
+static int fst_global_initialized = 0;
 struct dl_list fst_global_ctrls_list;
 
 
@@ -106,6 +107,7 @@ int fst_global_init(void)
        dl_list_init(&fst_global_groups_list);
        dl_list_init(&fst_global_ctrls_list);
        fst_session_global_init();
+       fst_global_initialized = 1;
        return 0;
 }
 
@@ -115,6 +117,9 @@ void fst_global_deinit(void)
        struct fst_group *group;
        struct fst_ctrl_handle *h;
 
+       if (!fst_global_initialized)
+               return;
+
        fst_session_global_deinit();
        while ((group = fst_first_group()) != NULL)
                fst_group_delete(group);
@@ -122,6 +127,7 @@ void fst_global_deinit(void)
                                  struct fst_ctrl_handle,
                                  global_ctrls_lentry)))
                fst_global_del_ctrl(h);
+       fst_global_initialized = 0;
 }
 
 
@@ -160,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))
+       if (fst_iface_is_connected(iface, mgmt->sa, FALSE))
                fst_session_on_action_rx(iface, mgmt, len);
        else
                wpa_printf(MSG_DEBUG,
index dc7b2a7..b632827 100644 (file)
 
 
 static const char *session_event_names[] = {
-       [EVENT_FST_ESTABLISHED] FST_PVAL_EVT_TYPE_ESTABLISHED,
-       [EVENT_FST_SETUP] FST_PVAL_EVT_TYPE_SETUP,
-       [EVENT_FST_SESSION_STATE_CHANGED] FST_PVAL_EVT_TYPE_SESSION_STATE,
+       [EVENT_FST_ESTABLISHED] FST_PVAL_EVT_TYPE_ESTABLISHED,
+       [EVENT_FST_SETUP] FST_PVAL_EVT_TYPE_SETUP,
+       [EVENT_FST_SESSION_STATE_CHANGED] FST_PVAL_EVT_TYPE_SESSION_STATE,
 };
 
 static const char *reason_names[] = {
-       [REASON_TEARDOWN] FST_CS_PVAL_REASON_TEARDOWN,
-       [REASON_SETUP] FST_CS_PVAL_REASON_SETUP,
-       [REASON_SWITCH] FST_CS_PVAL_REASON_SWITCH,
-       [REASON_STT] FST_CS_PVAL_REASON_STT,
-       [REASON_REJECT] FST_CS_PVAL_REASON_REJECT,
-       [REASON_ERROR_PARAMS] FST_CS_PVAL_REASON_ERROR_PARAMS,
-       [REASON_RESET] FST_CS_PVAL_REASON_RESET,
-       [REASON_DETACH_IFACE] FST_CS_PVAL_REASON_DETACH_IFACE,
+       [REASON_TEARDOWN] FST_CS_PVAL_REASON_TEARDOWN,
+       [REASON_SETUP] FST_CS_PVAL_REASON_SETUP,
+       [REASON_SWITCH] FST_CS_PVAL_REASON_SWITCH,
+       [REASON_STT] FST_CS_PVAL_REASON_STT,
+       [REASON_REJECT] FST_CS_PVAL_REASON_REJECT,
+       [REASON_ERROR_PARAMS] FST_CS_PVAL_REASON_ERROR_PARAMS,
+       [REASON_RESET] FST_CS_PVAL_REASON_RESET,
+       [REASON_DETACH_IFACE] FST_CS_PVAL_REASON_DETACH_IFACE,
 };
 
 static const char *session_state_names[] = {
-       [FST_SESSION_STATE_INITIAL] FST_CS_PVAL_STATE_INITIAL,
-       [FST_SESSION_STATE_SETUP_COMPLETION] FST_CS_PVAL_STATE_SETUP_COMPLETION,
-       [FST_SESSION_STATE_TRANSITION_DONE] FST_CS_PVAL_STATE_TRANSITION_DONE,
-       [FST_SESSION_STATE_TRANSITION_CONFIRMED]
+       [FST_SESSION_STATE_INITIAL] = FST_CS_PVAL_STATE_INITIAL,
+       [FST_SESSION_STATE_SETUP_COMPLETION] =
+       FST_CS_PVAL_STATE_SETUP_COMPLETION,
+       [FST_SESSION_STATE_TRANSITION_DONE] = FST_CS_PVAL_STATE_TRANSITION_DONE,
+       [FST_SESSION_STATE_TRANSITION_CONFIRMED] =
        FST_CS_PVAL_STATE_TRANSITION_CONFIRMED,
 };
 
index d090718..7820e58 100644 (file)
@@ -648,9 +648,9 @@ static int list_groups(const char *cmd, char *buf, size_t buflen)
 static const char * band_freq(enum mb_band_id band)
 {
        static const char *band_names[] = {
-               [MB_BAND_ID_WIFI_2_4GHZ] "2.4GHZ",
-               [MB_BAND_ID_WIFI_5GHZ] "5GHZ",
-               [MB_BAND_ID_WIFI_60GHZ] "60GHZ",
+               [MB_BAND_ID_WIFI_2_4GHZ] "2.4GHZ",
+               [MB_BAND_ID_WIFI_5GHZ] "5GHZ",
+               [MB_BAND_ID_WIFI_60GHZ] "60GHZ",
        };
 
        return fst_get_str_name(band, band_names, ARRAY_SIZE(band_names));
@@ -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)) {
+                       if (fst_iface_is_connected(f, addr, TRUE)) {
                                ret += print_band(num++, f, addr,
                                                  buf + ret, buflen - ret);
                        }
index 8ddcc61..5859f6f 100644 (file)
@@ -34,7 +34,7 @@ enum session_type {
 struct session_transition_ie {
        u8 element_id;
        u8 length;
-       u32 fsts_id;
+       le32 fsts_id;
        u8 session_control;
        u8 new_band_id;
        u8 new_band_setup;
@@ -47,7 +47,7 @@ struct session_transition_ie {
 struct fst_setup_req {
        u8 action;
        u8 dialog_token;
-       u32 llt;
+       le32 llt;
        struct session_transition_ie stie;
        /* Multi-band (optional) */
        /* Wakeup Schedule (optional) */
@@ -70,18 +70,18 @@ struct fst_setup_res {
 struct fst_ack_req {
        u8 action;
        u8 dialog_token;
-       u32 fsts_id;
+       le32 fsts_id;
 } STRUCT_PACKED;
 
 struct fst_ack_res {
        u8 action;
        u8 dialog_token;
-       u32 fsts_id;
+       le32 fsts_id;
 } STRUCT_PACKED;
 
 struct fst_tear_down {
        u8 action;
-       u32 fsts_id;
+       le32 fsts_id;
 } STRUCT_PACKED;
 
 #endif /* IEEE_80211_FST_DEFS_H */
index f6c7be9..321d40d 100644 (file)
 
 struct dl_list fst_global_groups_list;
 
-#ifndef HOSTAPD
-static Boolean fst_has_fst_peer(struct fst_iface *iface, Boolean *has_peer)
-{
-       const u8 *bssid;
-
-       bssid = fst_iface_get_bssid(iface);
-       if (!bssid) {
-               *has_peer = FALSE;
-               return FALSE;
-       }
-
-       *has_peer = TRUE;
-       return fst_iface_get_peer_mb_ie(iface, bssid) != NULL;
-}
-#endif /* HOSTAPD */
-
 
 static void fst_dump_mb_ies(const char *group_id, const char *ifname,
                            struct wpabuf *mbies)
@@ -147,16 +131,6 @@ static struct wpabuf * fst_group_create_mb_ie(struct fst_group *g,
        struct fst_iface *f;
        unsigned int nof_mbies = 0;
        unsigned int nof_ifaces_added = 0;
-#ifndef HOSTAPD
-       Boolean has_peer;
-       Boolean has_fst_peer;
-
-       foreach_fst_group_iface(g, f) {
-               has_fst_peer = fst_has_fst_peer(f, &has_peer);
-               if (has_peer && !has_fst_peer)
-                       return NULL;
-       }
-#endif /* HOSTAPD */
 
        foreach_fst_group_iface(g, f) {
                if (f == i)
@@ -222,43 +196,35 @@ static const u8 * fst_mbie_get_peer_addr(const struct multi_band_ie *mbie)
 }
 
 
-static struct fst_iface *
-fst_group_get_new_iface_by_mbie_and_band_id(struct fst_group *g,
-                                           const u8 *mb_ies_buff,
-                                           size_t mb_ies_size,
-                                           u8 band_id,
-                                           u8 *iface_peer_addr)
+static const u8 * fst_mbie_get_peer_addr_for_band(const struct wpabuf *mbies,
+                                                 u8 band_id)
 {
-       while (mb_ies_size >= 2) {
-               const struct multi_band_ie *mbie =
-                       (const struct multi_band_ie *) mb_ies_buff;
-
-               if (mbie->eid != WLAN_EID_MULTI_BAND ||
-                   (size_t) 2 + mbie->len < sizeof(*mbie))
-                       break;
+       const u8 *p = wpabuf_head(mbies);
+       size_t s = wpabuf_len(mbies);
 
-               if (mbie->band_id == band_id) {
-                       struct fst_iface *iface;
+       while (s >= 2) {
+               const struct multi_band_ie *mbie =
+                       (const struct multi_band_ie *) p;
 
-                       foreach_fst_group_iface(g, iface) {
-                               const u8 *peer_addr =
-                                       fst_mbie_get_peer_addr(mbie);
+               if (mbie->eid != WLAN_EID_MULTI_BAND) {
+                       fst_printf(MSG_INFO, "unexpected eid %d", mbie->eid);
+                       return NULL;
+               }
 
-                               if (peer_addr &&
-                                   fst_iface_is_connected(iface, peer_addr) &&
-                                   band_id == fst_iface_get_band_id(iface)) {
-                                       os_memcpy(iface_peer_addr, peer_addr,
-                                                 ETH_ALEN);
-                                       return iface;
-                               }
-                       }
-                       break;
+               if (mbie->len < sizeof(*mbie) - 2 || mbie->len > s - 2) {
+                       fst_printf(MSG_INFO, "invalid mbie len %d",
+                                  mbie->len);
+                       return NULL;
                }
 
-               mb_ies_buff += 2 + mbie->len;
-               mb_ies_size -= 2 + mbie->len;
+               if (mbie->band_id == band_id)
+                       return fst_mbie_get_peer_addr(mbie);
+
+               p += 2 + mbie->len;
+               s -= 2 + mbie->len;
        }
 
+       fst_printf(MSG_INFO, "mbie doesn't contain band %d", band_id);
        return NULL;
 }
 
@@ -295,78 +261,172 @@ u32 fst_group_assign_fsts_id(struct fst_group *g)
 }
 
 
-static Boolean
-fst_group_does_iface_appear_in_other_mbies(struct fst_group *g,
-                                          struct fst_iface *iface,
-                                          struct fst_iface *other,
-                                          u8 *peer_addr)
+/**
+ * fst_group_get_peer_other_connection_1 - Find peer's "other" connection
+ * (iface, MAC tuple) by using peer's MB IE on iface.
+ *
+ * @iface: iface on which FST Setup Request was received
+ * @peer_addr: Peer address on iface
+ * @band_id: "other" connection band id
+ * @other_peer_addr (out): Peer's MAC address on the "other" connection (on the
+ *   "other" iface)
+ *
+ * This function parses peer's MB IE on iface. It looks for peer's MAC address
+ * on band_id (tmp_peer_addr). Next all interfaces are iterated to find an
+ * interface which correlates with band_id. If such interface is found, peer
+ * database is iterated to see if tmp_peer_addr is connected over it.
+ */
+static struct fst_iface *
+fst_group_get_peer_other_connection_1(struct fst_iface *iface,
+                                     const u8 *peer_addr, u8 band_id,
+                                     u8 *other_peer_addr)
 {
-       struct fst_get_peer_ctx *ctx;
-       const u8 *addr;
-       const u8 *iface_addr;
-       enum mb_band_id  iface_band_id;
+       const struct wpabuf *mbies;
+       struct fst_iface *other_iface;
+       const u8 *tmp_peer_addr;
 
-       WPA_ASSERT(g == fst_iface_get_group(iface));
-       WPA_ASSERT(g == fst_iface_get_group(other));
+       /* Get peer's MB IEs on iface */
+       mbies = fst_iface_get_peer_mb_ie(iface, peer_addr);
+       if (!mbies)
+               return NULL;
 
-       iface_addr = fst_iface_get_addr(iface);
-       iface_band_id = fst_iface_get_band_id(iface);
+       /* Get peer's MAC address on the "other" interface */
+       tmp_peer_addr = fst_mbie_get_peer_addr_for_band(mbies, band_id);
+       if (!tmp_peer_addr) {
+               fst_printf(MSG_INFO,
+                          "couldn't extract other peer addr from mbies");
+               return NULL;
+       }
 
-       addr = fst_iface_get_peer_first(other, &ctx, TRUE);
-       for (; addr; addr = fst_iface_get_peer_next(other, &ctx, TRUE)) {
-               const struct wpabuf *mbies;
-               u8 other_iface_peer_addr[ETH_ALEN];
-               struct fst_iface *other_new_iface;
+       fst_printf(MSG_DEBUG, "found other peer addr from mbies: " MACSTR,
+                  MAC2STR(tmp_peer_addr));
 
-               mbies = fst_iface_get_peer_mb_ie(other, addr);
-               if (!mbies)
+       foreach_fst_group_iface(fst_iface_get_group(iface), other_iface) {
+               if (other_iface == iface ||
+                   band_id != fst_iface_get_band_id(other_iface))
                        continue;
-
-               other_new_iface = fst_group_get_new_iface_by_mbie_and_band_id(
-                       g, wpabuf_head(mbies), wpabuf_len(mbies),
-                       iface_band_id, other_iface_peer_addr);
-               if (other_new_iface == iface &&
-                   os_memcmp(iface_addr, other_iface_peer_addr,
-                             ETH_ALEN) != 0) {
-                       os_memcpy(peer_addr, addr, ETH_ALEN);
-                       return TRUE;
+               if (fst_iface_is_connected(other_iface, tmp_peer_addr, FALSE)) {
+                       os_memcpy(other_peer_addr, tmp_peer_addr, ETH_ALEN);
+                       return other_iface;
                }
        }
 
-       return FALSE;
+       return NULL;
 }
 
 
-struct fst_iface *
-fst_group_find_new_iface_by_stie(struct fst_group *g,
-                                struct fst_iface *iface,
-                                const u8 *peer_addr,
-                                const struct session_transition_ie *stie,
-                                u8 *iface_peer_addr)
+/**
+ * fst_group_get_peer_other_connection_2 - Find peer's "other" connection
+ * (iface, MAC tuple) by using MB IEs of other peers.
+ *
+ * @iface: iface on which FST Setup Request was received
+ * @peer_addr: Peer address on iface
+ * @band_id: "other" connection band id
+ * @other_peer_addr (out): Peer's MAC address on the "other" connection (on the
+ *   "other" iface)
+ *
+ * This function iterates all connection (other_iface, cur_peer_addr tuples).
+ * For each connection, MB IE (of cur_peer_addr on other_iface) is parsed and
+ * MAC address on iface's band_id is extracted (this_peer_addr).
+ * this_peer_addr is then compared to peer_addr. A match indicates we have
+ * found the "other" connection.
+ */
+static struct fst_iface *
+fst_group_get_peer_other_connection_2(struct fst_iface *iface,
+                                     const u8 *peer_addr, u8 band_id,
+                                     u8 *other_peer_addr)
 {
-       struct fst_iface *i;
+       u8 this_band_id = fst_iface_get_band_id(iface);
+       const u8 *cur_peer_addr, *this_peer_addr;
+       struct fst_get_peer_ctx *ctx;
+       struct fst_iface *other_iface;
+       const struct wpabuf *cur_mbie;
 
-       foreach_fst_group_iface(g, i) {
-               if (i == iface ||
-                   stie->new_band_id != fst_iface_get_band_id(i))
+       foreach_fst_group_iface(fst_iface_get_group(iface), other_iface) {
+               if (other_iface == iface ||
+                   band_id != fst_iface_get_band_id(other_iface))
                        continue;
-               if (fst_group_does_iface_appear_in_other_mbies(g, iface, i,
-                       iface_peer_addr))
-                       return i;
-               break;
+               cur_peer_addr = fst_iface_get_peer_first(other_iface, &ctx,
+                                                        TRUE);
+               for (; cur_peer_addr;
+                    cur_peer_addr = fst_iface_get_peer_next(other_iface, &ctx,
+                                                            TRUE)) {
+                       cur_mbie = fst_iface_get_peer_mb_ie(other_iface,
+                                                           cur_peer_addr);
+                       if (!cur_mbie)
+                               continue;
+                       this_peer_addr = fst_mbie_get_peer_addr_for_band(
+                               cur_mbie, this_band_id);
+                       if (!this_peer_addr)
+                               continue;
+                       if (os_memcmp(this_peer_addr, peer_addr, ETH_ALEN) ==
+                           0) {
+                               os_memcpy(other_peer_addr, cur_peer_addr,
+                                         ETH_ALEN);
+                               return other_iface;
+                       }
+               }
        }
+
        return NULL;
 }
 
 
+/**
+ * fst_group_get_peer_other_connection - Find peer's "other" connection (iface,
+ * MAC tuple).
+ *
+ * @iface: iface on which FST Setup Request was received
+ * @peer_addr: Peer address on iface
+ * @band_id: "other" connection band id
+ * @other_peer_addr (out): Peer's MAC address on the "other" connection (on the
+ *   "other" iface)
+ *
+ * This function is called upon receiving FST Setup Request from some peer who
+ * has peer_addr on iface. It searches for another connection of the same peer
+ * on different interface which correlates with band_id. MB IEs received from
+ * peer (on the two different interfaces) are used to identify same peer.
+ */
 struct fst_iface *
-fst_group_get_new_iface_by_stie_and_mbie(
-       struct fst_group *g, const u8 *mb_ies_buff, size_t mb_ies_size,
-       const struct session_transition_ie *stie, u8 *iface_peer_addr)
+fst_group_get_peer_other_connection(struct fst_iface *iface,
+                                   const u8 *peer_addr, u8 band_id,
+                                   u8 *other_peer_addr)
 {
-       return fst_group_get_new_iface_by_mbie_and_band_id(
-               g, mb_ies_buff, mb_ies_size, stie->new_band_id,
-               iface_peer_addr);
+       struct fst_iface *other_iface;
+
+       fst_printf(MSG_DEBUG, "%s: %s:" MACSTR ", %d", __func__,
+                  fst_iface_get_name(iface), MAC2STR(peer_addr), band_id);
+
+       /*
+        * Two search methods are used:
+        * 1. Use peer's MB IE on iface to extract peer's MAC address on
+        *    "other" connection. Then check if such "other" connection exists.
+        * 2. Iterate peer database, examine each MB IE to see if it points to
+        *    (iface, peer_addr) tuple
+        */
+
+       other_iface = fst_group_get_peer_other_connection_1(iface, peer_addr,
+                                                           band_id,
+                                                           other_peer_addr);
+       if (other_iface) {
+               fst_printf(MSG_DEBUG, "found by method #1. %s:" MACSTR,
+                          fst_iface_get_name(other_iface),
+                          MAC2STR(other_peer_addr));
+               return other_iface;
+       }
+
+       other_iface = fst_group_get_peer_other_connection_2(iface, peer_addr,
+                                                           band_id,
+                                                           other_peer_addr);
+       if (other_iface) {
+               fst_printf(MSG_DEBUG, "found by method #2. %s:" MACSTR,
+                          fst_iface_get_name(other_iface),
+                          MAC2STR(other_peer_addr));
+               return other_iface;
+       }
+
+       fst_printf(MSG_INFO, "%s: other connection not found", __func__);
+       return NULL;
 }
 
 
index 3a87c0b..00aee9c 100644 (file)
@@ -48,15 +48,9 @@ Boolean 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 *
-fst_group_find_new_iface_by_stie(struct fst_group *g,
-                                struct fst_iface *iface,
-                                const u8 *peer_addr,
-                                const struct session_transition_ie *stie,
-                                u8 *iface_peer_addr);
-struct fst_iface *
-fst_group_get_new_iface_by_stie_and_mbie(
-       struct fst_group *g, const u8 *mb_ies_buff, size_t mb_ies_size,
-       const struct session_transition_ie *stie, u8 *iface_peer_addr);
+fst_group_get_peer_other_connection(struct fst_iface *iface,
+                                   const u8 *peer_addr, u8 band_id,
+                                   u8 *other_peer_addr);
 u8  fst_group_assign_dialog_token(struct fst_group *g);
 u32 fst_group_assign_fsts_id(struct fst_group *g);
 
index 5a92d2c..35e83cb 100644 (file)
@@ -49,12 +49,13 @@ void fst_iface_delete(struct fst_iface *i)
 }
 
 
-Boolean fst_iface_is_connected(struct fst_iface *iface, const u8 *addr)
+Boolean fst_iface_is_connected(struct fst_iface *iface, const u8 *addr,
+                              Boolean mb_only)
 {
        struct fst_get_peer_ctx *ctx;
-       const u8 *a = fst_iface_get_peer_first(iface, &ctx, TRUE);
+       const u8 *a = fst_iface_get_peer_first(iface, &ctx, mb_only);
 
-       for (; a != NULL; a = fst_iface_get_peer_next(iface, &ctx, TRUE))
+       for (; a != NULL; a = fst_iface_get_peer_next(iface, &ctx, mb_only))
                if (os_memcmp(addr, a, ETH_ALEN) == 0)
                        return TRUE;
 
index 4670d89..0eb2732 100644 (file)
@@ -123,7 +123,8 @@ static inline const u8 * fst_iface_get_peer_next(struct fst_iface *i,
        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 fst_iface_is_connected(struct fst_iface *iface, const u8 *addr,
+                              Boolean 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);
 
index 55fa694..76e2c78 100644 (file)
@@ -44,7 +44,7 @@
 #define FST_LLT_MS_DEFAULT 50
 #define FST_ACTION_MAX_SUPPORTED   FST_ACTION_ON_CHANNEL_TUNNEL
 
-const char * const fst_action_names[] = {
+static const char * const fst_action_names[] = {
        [FST_ACTION_SETUP_REQUEST]     = "Setup Request",
        [FST_ACTION_SETUP_RESPONSE]    = "Setup Response",
        [FST_ACTION_TEAR_DOWN]         = "Tear Down",
@@ -181,7 +181,8 @@ static void fst_session_timeout_handler(void *eloop_data, void *user_ctx)
 
 static void fst_session_stt_arm(struct fst_session *s)
 {
-       eloop_register_timeout(0, TU_TO_US(FST_DEFAULT_SESSION_TIMEOUT_TU),
+       /* 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;
 }
@@ -363,7 +364,6 @@ static void fst_session_handle_setup_request(struct fst_iface *iface,
        struct fst_iface *new_iface = NULL;
        struct fst_group *g;
        u8 new_iface_peer_addr[ETH_ALEN];
-       const struct wpabuf *peer_mbies;
        size_t plen;
 
        if (frame_len < IEEE80211_HDRLEN + 1 + sizeof(*req))  {
@@ -399,36 +399,18 @@ static void fst_session_handle_setup_request(struct fst_iface *iface,
                                 MAC2STR(mgmt->sa));
        }
 
-       peer_mbies = fst_iface_get_peer_mb_ie(iface, mgmt->sa);
-       if (peer_mbies) {
-               new_iface = fst_group_get_new_iface_by_stie_and_mbie(
-                       g, wpabuf_head(peer_mbies), wpabuf_len(peer_mbies),
-                       &req->stie, new_iface_peer_addr);
-               if (new_iface)
-                       fst_printf_iface(iface, MSG_INFO,
-                                        "FST Request: new iface (%s:" MACSTR
-                                        ") found by MB IEs",
-                                        fst_iface_get_name(new_iface),
-                                        MAC2STR(new_iface_peer_addr));
-       }
-
-       if (!new_iface) {
-               new_iface = fst_group_find_new_iface_by_stie(
-                       g, iface, mgmt->sa, &req->stie,
-                       new_iface_peer_addr);
-               if (new_iface)
-                       fst_printf_iface(iface, MSG_INFO,
-                                        "FST Request: new iface (%s:" MACSTR
-                                        ") found by others",
-                                        fst_iface_get_name(new_iface),
-                                        MAC2STR(new_iface_peer_addr));
-       }
-
+       new_iface = fst_group_get_peer_other_connection(iface, mgmt->sa,
+                                                       req->stie.new_band_id,
+                                                       new_iface_peer_addr);
        if (!new_iface) {
                fst_printf_iface(iface, MSG_WARNING,
                                 "FST Request dropped: new iface not found");
                return;
        }
+       fst_printf_iface(iface, MSG_INFO,
+                        "FST Request: new iface (%s:" MACSTR ") found",
+                        fst_iface_get_name(new_iface),
+                        MAC2STR(new_iface_peer_addr));
 
        s = fst_find_session_in_progress(mgmt->sa, g);
        if (s) {
@@ -447,7 +429,9 @@ static void fst_session_handle_setup_request(struct fst_iface *iface,
                 * the initiator’s MAC address, in which case, the responder
                 * shall delete the received FST Setup Request.
                 */
-               if (os_memcmp(mgmt->da, mgmt->sa, ETH_ALEN) > 0) {
+               if (fst_session_is_ready_pending(s) &&
+                   /* waiting for Setup Response */
+                   os_memcmp(mgmt->da, mgmt->sa, ETH_ALEN) > 0) {
                        fst_printf_session(s, MSG_WARNING,
                                           "FST Request dropped due to MAC comparison (our MAC is "
                                           MACSTR ")",
@@ -455,23 +439,26 @@ static void fst_session_handle_setup_request(struct fst_iface *iface,
                        return;
                }
 
-               if (!fst_session_is_ready_pending(s)) {
-                       fst_printf_session(s, MSG_WARNING,
-                                          "FST Request from " MACSTR
-                                          " dropped due to inappropriate state %s",
-                                          MAC2STR(mgmt->da),
-                                          fst_session_state_name(s->state));
-                       return;
-               }
+               /*
+                * State is SETUP_COMPLETION (either in transition or not) or
+                * TRANSITION_DONE (in transition).
+                * Setup Request arriving in this state could mean:
+                * 1. peer sent it before receiving our Setup Request (race
+                *    condition)
+                * 2. peer didn't receive our Setup Response. Peer is retrying
+                *    after STT timeout
+                * 3. peer's FST state machines are out of sync due to some
+                *    other reason
+                *
+                * We will reset our session and create a new one instead.
+                */
 
+               fst_printf_session(s, MSG_WARNING,
+                       "resetting due to FST request");
 
                /*
                 * If FST Setup Request arrived with the same FSTS ID as one we
-                * initialized before, it means the other side either didn't
-                * receive our FST Request or skipped it for some reason (for
-                * example, due to numerical MAC comparison).
-                *
-                * In this case, there's no need to tear down the session.
+                * initialized before, there's no need to tear down the session.
                 * Moreover, as FSTS ID is the same, the other side will
                 * associate this tear down with the session it initiated that
                 * will break the sync.
@@ -483,7 +470,6 @@ static void fst_session_handle_setup_request(struct fst_iface *iface,
                                           "Skipping TearDown as the FST request has the same FSTS ID as initiated");
                fst_session_set_state(s, FST_SESSION_STATE_INITIAL, &evext);
                fst_session_stt_disarm(s);
-               fst_printf_session(s, MSG_WARNING, "reset due to FST request");
        }
 
        s = fst_session_create(g);
@@ -521,7 +507,9 @@ static void fst_session_handle_setup_response(struct fst_session *s,
        enum hostapd_hw_mode hw_mode;
        u8 channel;
        union fst_session_state_switch_extra evext = {
-               .to_initial = {0},
+               .to_initial = {
+                       .reject_code = 0,
+               },
        };
 
        if (iface != s->data.old_iface) {
@@ -863,13 +851,15 @@ int fst_session_initiate_setup(struct fst_session *s)
                return -EINVAL;
        }
 
-       if (!fst_iface_is_connected(s->data.old_iface, s->data.old_peer_addr)) {
+       if (!fst_iface_is_connected(s->data.old_iface, s->data.old_peer_addr,
+                                   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)) {
+       if (!fst_iface_is_connected(s->data.new_iface, s->data.new_peer_addr,
+                                   FALSE)) {
                fst_printf_session(s, MSG_ERROR,
                                   "The preset new peer address is not connected");
                return -EINVAL;
@@ -966,7 +956,8 @@ int fst_session_respond(struct fst_session *s, u8 status_code)
                return -EINVAL;
        }
 
-       if (!fst_iface_is_connected(s->data.old_iface, s->data.old_peer_addr)) {
+       if (!fst_iface_is_connected(s->data.old_iface,
+                                   s->data.old_peer_addr, FALSE)) {
                fst_printf_session(s, MSG_ERROR,
                                   "The preset peer address is not in the peer list");
                return -EINVAL;
@@ -984,7 +975,7 @@ int fst_session_respond(struct fst_session *s, u8 status_code)
        res.stie.length = sizeof(res.stie) - 2;
 
        if (status_code == WLAN_STATUS_SUCCESS) {
-               res.stie.fsts_id = s->data.fsts_id;
+               res.stie.fsts_id = host_to_le32(s->data.fsts_id);
                res.stie.session_control = SESSION_CONTROL(SESSION_TYPE_BSS, 0);
 
                fst_iface_get_channel_info(s->data.new_iface, &hw_mode,
@@ -1458,7 +1449,7 @@ int fst_test_req_send_fst_response(const char *params)
        res.stie.length = sizeof(res.stie) - 2;
 
        if (res.status_code == WLAN_STATUS_SUCCESS) {
-               res.stie.fsts_id = fsts_id;
+               res.stie.fsts_id = host_to_le32(fsts_id);
                res.stie.session_control = SESSION_CONTROL(SESSION_TYPE_BSS, 0);
 
                fst_iface_get_channel_info(s.data.new_iface, &hw_mode,
@@ -1507,7 +1498,7 @@ int fst_test_req_send_ack_request(const char *params)
        os_memset(&req, 0, sizeof(req));
        req.action = FST_ACTION_ACK_REQUEST;
        req.dialog_token = g->dialog_token;
-       req.fsts_id = fsts_id;
+       req.fsts_id = host_to_le32(fsts_id);
 
        return fst_session_send_action(&s, FALSE, &req, sizeof(req), NULL);
 }
@@ -1535,7 +1526,7 @@ int fst_test_req_send_ack_response(const char *params)
        os_memset(&res, 0, sizeof(res));
        res.action = FST_ACTION_ACK_RESPONSE;
        res.dialog_token = g->dialog_token;
-       res.fsts_id = fsts_id;
+       res.fsts_id = host_to_le32(fsts_id);
 
        return fst_session_send_action(&s, FALSE, &res, sizeof(res), NULL);
 }
@@ -1562,7 +1553,7 @@ int fst_test_req_send_tear_down(const char *params)
 
        os_memset(&td, 0, sizeof(td));
        td.action = FST_ACTION_TEAR_DOWN;
-       td.fsts_id = fsts_id;
+       td.fsts_id = host_to_le32(fsts_id);
 
        return fst_session_send_action(&s, TRUE, &td, sizeof(td), NULL);
 }
index 41de2f8..a7a300e 100644 (file)
@@ -30,11 +30,14 @@ struct l2_packet_data {
        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;
+       int last_from_br, last_from_br_prev;
        u8 last_hash[SHA1_MAC_LEN];
-       unsigned int num_rx, num_rx_br;
+       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
@@ -127,7 +130,6 @@ static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
        struct sockaddr_ll ll;
        socklen_t fromlen;
 
-       l2->num_rx++;
        os_memset(&ll, 0, sizeof(ll));
        fromlen = sizeof(ll);
        res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll,
@@ -141,6 +143,7 @@ static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
        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];
@@ -169,14 +172,24 @@ static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
                                   __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;
@@ -202,6 +215,11 @@ static void l2_packet_receive_br(int sock, void *eloop_ctx, void *sock_ctx)
        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);
@@ -210,10 +228,18 @@ static void l2_packet_receive_br(int sock, void *eloop_ctx, void *sock_ctx)
                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(
@@ -233,7 +259,9 @@ struct l2_packet_data * l2_packet_init(
        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));
@@ -289,6 +317,7 @@ struct l2_packet_data * l2_packet_init_bridge(
        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),
@@ -304,12 +333,14 @@ struct l2_packet_data * l2_packet_init_bridge(
                .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
@@ -357,6 +388,7 @@ struct l2_packet_data * l2_packet_init_bridge(
        }
 
        eloop_register_read_sock(l2->fd_br_rx, l2_packet_receive_br, l2, NULL);
+#endif /* CONFIG_NO_LINUX_PACKET_SOCKET_WAR */
 
        return l2;
 }
@@ -372,10 +404,12 @@ void l2_packet_deinit(struct l2_packet_data *l2)
                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);
 }
index bb4f4a3..423c099 100644 (file)
@@ -312,6 +312,18 @@ struct l2_packet_data * l2_packet_init(
 }
 
 
+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)
index 767706c..996b4e8 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "common.h"
 #include "eloop.h"
+#include "common/defs.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
@@ -445,8 +446,9 @@ static struct p2p_device * p2p_create_device(struct p2p_data *p2p,
 static void p2p_copy_client_info(struct p2p_device *dev,
                                 struct p2p_client_info *cli)
 {
-       os_memcpy(dev->info.device_name, cli->dev_name, cli->dev_name_len);
-       dev->info.device_name[cli->dev_name_len] = '\0';
+       p2p_copy_filter_devname(dev->info.device_name,
+                               sizeof(dev->info.device_name),
+                               cli->dev_name, cli->dev_name_len);
        dev->info.dev_capab = cli->dev_capab;
        dev->info.config_methods = cli->config_methods;
        os_memcpy(dev->info.pri_dev_type, cli->pri_dev_type, 8);
@@ -636,11 +638,11 @@ static void p2p_update_peer_vendor_elems(struct p2p_device *dev, const u8 *ies,
 
        end = ies + ies_len;
 
-       for (pos = ies; pos + 1 < end; pos += len) {
+       for (pos = ies; end - pos > 1; pos += len) {
                id = *pos++;
                len = *pos++;
 
-               if (pos + len > end)
+               if (len > end - pos)
                        break;
 
                if (id != WLAN_EID_VENDOR_SPECIFIC || len < 3)
@@ -786,11 +788,11 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
                dev->oper_ssid_len = msg.ssid[1];
        }
 
-       if (msg.adv_service_instance && msg.adv_service_instance_len) {
-               wpabuf_free(dev->info.p2ps_instance);
+       wpabuf_free(dev->info.p2ps_instance);
+       dev->info.p2ps_instance = NULL;
+       if (msg.adv_service_instance && msg.adv_service_instance_len)
                dev->info.p2ps_instance = wpabuf_alloc_copy(
                        msg.adv_service_instance, msg.adv_service_instance_len);
-       }
 
        if (freq >= 2412 && freq <= 2484 && msg.ds_params &&
            *msg.ds_params >= 1 && *msg.ds_params <= 14) {
@@ -1220,9 +1222,14 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
 
        p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
        p2p_clear_timeout(p2p);
+       if (p2p->pending_listen_freq) {
+               p2p_dbg(p2p, "Clear pending_listen_freq for p2p_find");
+               p2p->pending_listen_freq = 0;
+       }
        p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
        p2p->find_type = type;
        p2p_device_clear_reported(p2p);
+       os_memset(p2p->sd_query_no_ack, 0, ETH_ALEN);
        p2p_set_state(p2p, P2P_SEARCH);
        p2p->search_delay = search_delay;
        p2p->in_search_delay = 0;
@@ -1459,7 +1466,7 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
 
 
 /**
- * p2p_prepare_channel - Select operating channel for GO Negotiation
+ * p2p_prepare_channel - Select operating channel for GO Negotiation or P2PS PD
  * @p2p: P2P module context from p2p_init()
  * @dev: Selected peer device
  * @force_freq: Forced frequency in MHz or 0 if not forced
@@ -1468,9 +1475,9 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
  * Returns: 0 on success, -1 on failure (channel not supported for P2P)
  *
  * This function is used to do initial operating channel selection for GO
- * Negotiation prior to having received peer information. The selected channel
- * may be further optimized in p2p_reselect_channel() once the peer information
- * is available.
+ * Negotiation prior to having received peer information or for P2PS PD
+ * signalling. The selected channel may be further optimized in
+ * p2p_reselect_channel() once the peer information is available.
  */
 int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
                        unsigned int force_freq, unsigned int pref_freq, int go)
@@ -2028,8 +2035,23 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr,
 
        dev = p2p_get_device(p2p, addr);
        if (dev) {
-               if (dev->country[0] == 0 && msg.listen_channel)
-                       os_memcpy(dev->country, msg.listen_channel, 3);
+               if (msg.listen_channel) {
+                       int freq;
+
+                       if (dev->country[0] == 0)
+                               os_memcpy(dev->country, msg.listen_channel, 3);
+
+                       freq = p2p_channel_to_freq(msg.listen_channel[3],
+                                                  msg.listen_channel[4]);
+
+                       if (freq > 0 && dev->listen_freq != freq) {
+                               p2p_dbg(p2p,
+                                       "Updated peer " MACSTR " Listen channel (Probe Request): %d -> %d MHz",
+                                       MAC2STR(addr), dev->listen_freq, freq);
+                               dev->listen_freq = freq;
+                       }
+               }
+
                os_get_reltime(&dev->last_seen);
                p2p_parse_free(&msg);
                return; /* already known */
@@ -2212,6 +2234,58 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p,
        return buf;
 }
 
+static int p2p_build_probe_resp_buf(struct p2p_data *p2p, struct wpabuf *buf,
+                                   struct wpabuf *ies,
+                                   const u8 *addr, int rx_freq)
+{
+       struct ieee80211_mgmt *resp;
+       u8 channel, op_class;
+
+       resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
+                                       u.probe_resp.variable));
+
+       resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+                                          (WLAN_FC_STYPE_PROBE_RESP << 4));
+       os_memcpy(resp->da, addr, ETH_ALEN);
+       os_memcpy(resp->sa, p2p->cfg->dev_addr, ETH_ALEN);
+       os_memcpy(resp->bssid, p2p->cfg->dev_addr, ETH_ALEN);
+       resp->u.probe_resp.beacon_int = host_to_le16(100);
+       /* hardware or low-level driver will setup seq_ctrl and timestamp */
+       resp->u.probe_resp.capab_info =
+           host_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE |
+                    WLAN_CAPABILITY_PRIVACY |
+                    WLAN_CAPABILITY_SHORT_SLOT_TIME);
+
+       wpabuf_put_u8(buf, WLAN_EID_SSID);
+       wpabuf_put_u8(buf, P2P_WILDCARD_SSID_LEN);
+       wpabuf_put_data(buf, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
+
+       wpabuf_put_u8(buf, WLAN_EID_SUPP_RATES);
+       wpabuf_put_u8(buf, 8);
+       wpabuf_put_u8(buf, (60 / 5) | 0x80);
+       wpabuf_put_u8(buf, 90 / 5);
+       wpabuf_put_u8(buf, (120 / 5) | 0x80);
+       wpabuf_put_u8(buf, 180 / 5);
+       wpabuf_put_u8(buf, (240 / 5) | 0x80);
+       wpabuf_put_u8(buf, 360 / 5);
+       wpabuf_put_u8(buf, 480 / 5);
+       wpabuf_put_u8(buf, 540 / 5);
+
+       if (!rx_freq) {
+               channel = p2p->cfg->channel;
+       } else if (p2p_freq_to_channel(rx_freq, &op_class, &channel)) {
+               p2p_err(p2p, "Failed to convert freq to channel");
+               return -1;
+       }
+
+       wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS);
+       wpabuf_put_u8(buf, 1);
+       wpabuf_put_u8(buf, channel);
+
+       wpabuf_put_buf(buf, ies);
+
+       return 0;
+}
 
 static int p2p_service_find_asp(struct p2p_data *p2p, const u8 *hash)
 {
@@ -2245,10 +2319,8 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
 {
        struct ieee802_11_elems elems;
        struct wpabuf *buf;
-       struct ieee80211_mgmt *resp;
        struct p2p_message msg;
        struct wpabuf *ies;
-       u8 channel, op_class;
 
        if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
            ParseFailed) {
@@ -2392,49 +2464,12 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
                return P2P_PREQ_NOT_PROCESSED;
        }
 
-       resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
-                                       u.probe_resp.variable));
-
-       resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
-                                          (WLAN_FC_STYPE_PROBE_RESP << 4));
-       os_memcpy(resp->da, addr, ETH_ALEN);
-       os_memcpy(resp->sa, p2p->cfg->dev_addr, ETH_ALEN);
-       os_memcpy(resp->bssid, p2p->cfg->dev_addr, ETH_ALEN);
-       resp->u.probe_resp.beacon_int = host_to_le16(100);
-       /* hardware or low-level driver will setup seq_ctrl and timestamp */
-       resp->u.probe_resp.capab_info =
-               host_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE |
-                            WLAN_CAPABILITY_PRIVACY |
-                            WLAN_CAPABILITY_SHORT_SLOT_TIME);
-
-       wpabuf_put_u8(buf, WLAN_EID_SSID);
-       wpabuf_put_u8(buf, P2P_WILDCARD_SSID_LEN);
-       wpabuf_put_data(buf, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
-
-       wpabuf_put_u8(buf, WLAN_EID_SUPP_RATES);
-       wpabuf_put_u8(buf, 8);
-       wpabuf_put_u8(buf, (60 / 5) | 0x80);
-       wpabuf_put_u8(buf, 90 / 5);
-       wpabuf_put_u8(buf, (120 / 5) | 0x80);
-       wpabuf_put_u8(buf, 180 / 5);
-       wpabuf_put_u8(buf, (240 / 5) | 0x80);
-       wpabuf_put_u8(buf, 360 / 5);
-       wpabuf_put_u8(buf, 480 / 5);
-       wpabuf_put_u8(buf, 540 / 5);
-
-       if (!rx_freq) {
-               channel = p2p->cfg->channel;
-       } else if (p2p_freq_to_channel(rx_freq, &op_class, &channel)) {
+       if (p2p_build_probe_resp_buf(p2p, buf, ies, addr, rx_freq)) {
                wpabuf_free(ies);
                wpabuf_free(buf);
                return P2P_PREQ_NOT_PROCESSED;
        }
 
-       wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS);
-       wpabuf_put_u8(buf, 1);
-       wpabuf_put_u8(buf, channel);
-
-       wpabuf_put_buf(buf, ies);
        wpabuf_free(ies);
 
        p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf, rx_freq);
@@ -2448,12 +2483,18 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
 enum p2p_probe_req_status
 p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
                 const u8 *bssid, const u8 *ie, size_t ie_len,
-                unsigned int rx_freq)
+                unsigned int rx_freq, int p2p_lo_started)
 {
        enum p2p_probe_req_status res;
 
        p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
 
+       if (p2p_lo_started) {
+               p2p_dbg(p2p,
+                       "Probe Response is offloaded, do not reply Probe Request");
+               return P2P_PREQ_PROCESSED;
+       }
+
        res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len, rx_freq);
        if (res != P2P_PREQ_PROCESSED && res != P2P_PREQ_NOT_PROCESSED)
                return res;
@@ -2944,7 +2985,6 @@ void p2p_deinit(struct p2p_data *p2p)
        wpabuf_free(p2p->wfd_coupled_sink_info);
 #endif /* CONFIG_WIFI_DISPLAY */
 
-       eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
        eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
        eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
        eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
@@ -2959,7 +2999,6 @@ void p2p_deinit(struct p2p_data *p2p)
        os_free(p2p->groups);
        p2ps_prov_free(p2p);
        wpabuf_free(p2p->sd_resp);
-       os_free(p2p->after_scan_tx);
        p2p_remove_wps_vendor_extensions(p2p);
        os_free(p2p->no_go_freq.range);
        p2p_service_flush_asp(p2p);
@@ -2971,6 +3010,8 @@ void p2p_deinit(struct p2p_data *p2p)
 void p2p_flush(struct p2p_data *p2p)
 {
        struct p2p_device *dev, *prev;
+
+       p2p_ext_listen(p2p, 0, 0);
        p2p_stop_find(p2p);
        dl_list_for_each_safe(dev, prev, &p2p->devices, struct p2p_device,
                              list) {
@@ -3157,13 +3198,18 @@ int p2p_set_country(struct p2p_data *p2p, const char *country)
 
 static int p2p_pre_find_operation(struct p2p_data *p2p, struct p2p_device *dev)
 {
+       int res;
+
        if (dev->sd_pending_bcast_queries == 0) {
                /* Initialize with total number of registered broadcast
                 * SD queries. */
                dev->sd_pending_bcast_queries = p2p->num_p2p_sd_queries;
        }
 
-       if (p2p_start_sd(p2p, dev) == 0)
+       res = p2p_start_sd(p2p, dev);
+       if (res == -2)
+               return -2;
+       if (res == 0)
                return 1;
 
        if (dev->req_config_methods &&
@@ -3183,7 +3229,7 @@ static int p2p_pre_find_operation(struct p2p_data *p2p, struct p2p_device *dev)
 void p2p_continue_find(struct p2p_data *p2p)
 {
        struct p2p_device *dev;
-       int found;
+       int found, res;
 
        p2p_set_state(p2p, P2P_SEARCH);
 
@@ -3196,10 +3242,13 @@ void p2p_continue_find(struct p2p_data *p2p)
                }
                if (!found)
                        continue;
-               if (p2p_pre_find_operation(p2p, dev) > 0) {
+               res = p2p_pre_find_operation(p2p, dev);
+               if (res > 0) {
                        p2p->last_p2p_find_oper = dev;
                        return;
                }
+               if (res == -2)
+                       goto skip_sd;
        }
 
        /*
@@ -3207,14 +3256,19 @@ void p2p_continue_find(struct p2p_data *p2p)
         * iteration device.
         */
        dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
-               if (p2p_pre_find_operation(p2p, dev) > 0) {
+               res = p2p_pre_find_operation(p2p, dev);
+               if (res > 0) {
                        p2p->last_p2p_find_oper = dev;
                        return;
                }
+               if (res == -2)
+                       goto skip_sd;
                if (dev == p2p->last_p2p_find_oper)
                        break;
        }
 
+skip_sd:
+       os_memset(p2p->sd_query_no_ack, 0, ETH_ALEN);
        p2p_listen_in_find(p2p, 1);
 }
 
@@ -3226,8 +3280,17 @@ static void p2p_sd_cb(struct p2p_data *p2p, int success)
        p2p->pending_action_state = P2P_NO_PENDING_ACTION;
 
        if (!success) {
-               if (p2p->sd_peer)
+               if (p2p->sd_peer) {
+                       if (is_zero_ether_addr(p2p->sd_query_no_ack)) {
+                               os_memcpy(p2p->sd_query_no_ack,
+                                         p2p->sd_peer->info.p2p_device_addr,
+                                         ETH_ALEN);
+                               p2p_dbg(p2p,
+                                       "First SD Query no-ACK in this search iteration: "
+                                       MACSTR, MAC2STR(p2p->sd_query_no_ack));
+                       }
                        p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+               }
                p2p->sd_peer = NULL;
                if (p2p->state != P2P_IDLE)
                        p2p_continue_find(p2p);
@@ -3326,6 +3389,43 @@ static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
        }
 
        /*
+        * If after PD Request the peer doesn't expect to receive PD Response
+        * the PD Request ACK indicates a completion of the current PD. This
+        * happens only on the advertiser side sending the follow-on PD Request
+        * with the status different than 12 (Success: accepted by user).
+        */
+       if (p2p->p2ps_prov && !p2p->p2ps_prov->pd_seeker &&
+           p2p->p2ps_prov->status != P2P_SC_SUCCESS_DEFERRED) {
+               p2p_dbg(p2p, "P2PS PD completion on Follow-on PD Request ACK");
+
+               if (p2p->send_action_in_progress) {
+                       p2p->send_action_in_progress = 0;
+                       p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+               }
+
+               p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
+               if (p2p->cfg->p2ps_prov_complete) {
+                       p2p->cfg->p2ps_prov_complete(
+                               p2p->cfg->cb_ctx,
+                               p2p->p2ps_prov->status,
+                               p2p->p2ps_prov->adv_mac,
+                               p2p->p2ps_prov->adv_mac,
+                               p2p->p2ps_prov->session_mac,
+                               NULL, p2p->p2ps_prov->adv_id,
+                               p2p->p2ps_prov->session_id,
+                               0, 0, NULL, 0, 0, 0,
+                               NULL, NULL, 0, 0, NULL, 0);
+               }
+
+               if (p2p->user_initiated_pd)
+                       p2p_reset_pending_pd(p2p);
+
+               p2ps_prov_free(p2p);
+               return;
+       }
+
+       /*
         * This postponing, of resetting pending_action_state, needs to be
         * done only for user initiated PD requests and not internal ones.
         */
@@ -3399,9 +3499,11 @@ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
                 * operation was started.
                 */
                p2p_dbg(p2p, "Ignore old scan result for " MACSTR
-                       " (rx_time=%u.%06u)",
+                       " (rx_time=%u.%06u find_start=%u.%06u)",
                        MAC2STR(bssid), (unsigned int) rx_time->sec,
-                       (unsigned int) rx_time->usec);
+                       (unsigned int) rx_time->usec,
+                       (unsigned int) p2p->find_start.sec,
+                       (unsigned int) p2p->find_start.usec);
                return 0;
        }
 
@@ -3426,7 +3528,8 @@ void p2p_scan_res_handled(struct p2p_data *p2p)
 }
 
 
-void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
+void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id,
+                unsigned int bands)
 {
        u8 dev_capab;
        u8 *len;
@@ -3460,6 +3563,9 @@ void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
                p2p_buf_add_ext_listen_timing(ies, p2p->ext_listen_period,
                                              p2p->ext_listen_interval);
 
+       if (bands & BAND_60_GHZ)
+               p2p_buf_add_device_info(ies, p2p, NULL);
+
        if (p2p->p2ps_seek && p2p->p2ps_seek_count)
                p2p_buf_add_service_hash(ies, p2p);
 
@@ -3694,6 +3800,8 @@ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
                break;
        case P2P_PENDING_INVITATION_RESPONSE:
                p2p_invitation_resp_cb(p2p, success);
+               if (p2p->inv_status != P2P_SC_SUCCESS)
+                       p2p_check_after_scan_tx_continuation(p2p);
                break;
        case P2P_PENDING_DEV_DISC_REQUEST:
                p2p_dev_disc_req_cb(p2p, success);
@@ -5400,3 +5508,34 @@ void p2p_set_own_pref_freq_list(struct p2p_data *p2p,
                        i, p2p->pref_freq_list[i]);
        }
 }
+
+
+struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p,
+                                             unsigned int freq)
+{
+       struct wpabuf *ies, *buf;
+       u8 addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+       int ret;
+
+       ies = p2p_build_probe_resp_ies(p2p, NULL, 0);
+       if (!ies) {
+               wpa_printf(MSG_ERROR,
+                          "CTRL: Failed to build Probe Response IEs");
+               return NULL;
+       }
+
+       buf = wpabuf_alloc(200 + wpabuf_len(ies));
+       if (!buf) {
+               wpabuf_free(ies);
+               return NULL;
+       }
+
+       ret = p2p_build_probe_resp_buf(p2p, buf, ies, addr, freq);
+       wpabuf_free(ies);
+       if (ret) {
+               wpabuf_free(buf);
+               return NULL;
+       }
+
+       return buf;
+}
index b4060be..7b18dcf 100644 (file)
@@ -31,7 +31,7 @@
 /**
  * P2P_MAX_REG_CLASSES - Maximum number of regulatory classes
  */
-#define P2P_MAX_REG_CLASSES 10
+#define P2P_MAX_REG_CLASSES 15
 
 /**
  * P2P_MAX_REG_CLASS_CHANNELS - Maximum number of channels per regulatory class
@@ -99,6 +99,10 @@ struct p2p_go_neg_results {
 
        int vht;
 
+       u8 max_oper_chwidth;
+
+       unsigned int vht_center_freq2;
+
        /**
         * ssid - SSID of the group
         */
@@ -224,6 +228,16 @@ struct p2ps_provision {
        u8 cpt_priority[P2PS_FEATURE_CAPAB_CPT_MAX + 1];
 
        /**
+        * force_freq - The only allowed channel frequency in MHz or 0.
+        */
+       unsigned int force_freq;
+
+       /**
+        * pref_freq - Preferred operating frequency in MHz or 0.
+        */
+       unsigned int pref_freq;
+
+       /**
         * info - Vendor defined extra Provisioning information
         */
        char info[0];
@@ -1024,6 +1038,8 @@ struct p2p_config {
         * @ssid_len: Buffer for returning length of @ssid
         * @group_iface: Buffer for returning whether a separate group interface
         *      would be used
+        * @freq: Variable for returning the current operating frequency of a
+        *      currently running P2P GO.
         * Returns: 1 if GO info found, 0 otherwise
         *
         * This is used to compose New Group settings (SSID, and intended
@@ -1031,7 +1047,8 @@ struct p2p_config {
         * result in our being an autonomous GO.
         */
        int (*get_go_info)(void *ctx, u8 *intended_addr,
-                          u8 *ssid, size_t *ssid_len, int *group_iface);
+                          u8 *ssid, size_t *ssid_len, int *group_iface,
+                          unsigned int *freq);
 
        /**
         * remove_stale_groups - Remove stale P2PS groups
@@ -1056,7 +1073,9 @@ struct p2p_config {
                                   const u8 *persist_ssid,
                                   size_t persist_ssid_size, int response_done,
                                   int prov_start, const char *session_info,
-                                  const u8 *feat_cap, size_t feat_cap_len);
+                                  const u8 *feat_cap, size_t feat_cap_len,
+                                  unsigned int freq, const u8 *group_ssid,
+                                  size_t group_ssid_len);
 
        /**
         * prov_disc_resp_cb - Callback for indicating completion of PD Response
@@ -1070,14 +1089,20 @@ struct p2p_config {
 
        /**
         * p2ps_group_capability - Determine group capability
+        * @ctx: Callback context from cb_ctx
+        * @incoming: Peer requested roles, expressed with P2PS_SETUP_* bitmap.
+        * @role: Local roles, expressed with P2PS_SETUP_* bitmap.
+        * @force_freq: Variable for returning forced frequency for the group.
+        * @pref_freq: Variable for returning preferred frequency for the group.
+        * Returns: P2PS_SETUP_* bitmap of group capability result.
         *
-        * This function can be used to determine group capability based on
-        * information from P2PS PD exchange and the current state of ongoing
-        * groups and driver capabilities.
-        *
-        * P2PS_SETUP_* bitmap is used as the parameters and return value.
+        * This function can be used to determine group capability and
+        * frequencies based on information from P2PS PD exchange and the
+        * current state of ongoing groups and driver capabilities.
         */
-       u8 (*p2ps_group_capability)(void *ctx, u8 incoming, u8 role);
+       u8 (*p2ps_group_capability)(void *ctx, u8 incoming, u8 role,
+                                   unsigned int *force_freq,
+                                   unsigned int *pref_freq);
 
        /**
         * get_pref_freq_list - Get preferred frequency list for an interface
@@ -1530,12 +1555,13 @@ enum p2p_probe_req_status {
  * @ie: Information elements from the Probe Request frame body
  * @ie_len: Length of ie buffer in octets
  * @rx_freq: Probe Request frame RX frequency
+ * @p2p_lo_started: Whether P2P Listen Offload is started
  * Returns: value indicating the type and status of the probe request
  */
 enum p2p_probe_req_status
 p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
                 const u8 *bssid, const u8 *ie, size_t ie_len,
-                unsigned int rx_freq);
+                unsigned int rx_freq, int p2p_lo_started);
 
 /**
  * p2p_rx_action - Report received Action frame
@@ -1691,6 +1717,12 @@ struct p2p_group_config {
        int freq;
 
        /**
+        * ip_addr_alloc - Whether IP address allocation within 4-way handshake
+        *      is supported
+        */
+       int ip_addr_alloc;
+
+       /**
         * cb_ctx - Context to use with callback functions
         */
        void *cb_ctx;
@@ -1877,8 +1909,10 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf,
  * @p2p: P2P module context from p2p_init()
  * @ies: Buffer for writing P2P IE
  * @dev_id: Device ID to search for or %NULL for any
+ * @bands: Frequency bands used in the scan (enum wpa_radio_work_band bitmap)
  */
-void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id);
+void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id,
+                unsigned int bands);
 
 /**
  * p2p_scan_ie_buf_len - Get maximum buffer length needed for p2p_scan_ie
@@ -2100,6 +2134,16 @@ int p2p_client_limit_reached(struct p2p_group *group);
 const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next);
 
 /**
+ * p2p_group_get_client_interface_addr - Get P2P Interface Address of a client in a group
+ * @group: P2P group context from p2p_group_init()
+ * @dev_addr: P2P Device Address of the client
+ * Returns: P2P Interface Address of the client if found or %NULL if no match
+ * found
+ */
+const u8 * p2p_group_get_client_interface_addr(struct p2p_group *group,
+                                              const u8 *dev_addr);
+
+/**
  * p2p_group_get_dev_addr - Get a P2P Device Address of a client in a group
  * @group: P2P group context from p2p_group_init()
  * @addr: P2P Interface Address of the client
@@ -2241,7 +2285,7 @@ struct wpabuf * wifi_display_encaps(struct wpabuf *subelems);
  * discovery (p2p_find). A random number of 100 TU units is picked for each
  * Listen state iteration from [min_disc_int,max_disc_int] range.
  *
- * max_disc_tu can be used to futher limit the discoverable duration. However,
+ * max_disc_tu can be used to further limit the discoverable duration. However,
  * it should be noted that use of this parameter is not recommended since it
  * would not be compliant with the P2P specification.
  */
@@ -2340,4 +2384,7 @@ void p2p_set_own_pref_freq_list(struct p2p_data *p2p,
 int p2p_group_get_common_freqs(struct p2p_group *group, int *common_freqs,
                               unsigned int *num);
 
+struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p,
+                                             unsigned int freq);
+
 #endif /* P2P_H */
index 793d28b..2882c6a 100644 (file)
@@ -202,11 +202,11 @@ void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p,
        if (peer && peer->wps_method != WPS_NOT_READY) {
                if (peer->wps_method == WPS_PBC)
                        methods |= WPS_CONFIG_PUSHBUTTON;
+               else if (peer->wps_method == WPS_P2PS)
+                       methods |= WPS_CONFIG_P2PS;
                else if (peer->wps_method == WPS_PIN_DISPLAY ||
-                        peer->wps_method == WPS_PIN_KEYPAD) {
+                        peer->wps_method == WPS_PIN_KEYPAD)
                        methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
-                       methods |= WPS_CONFIG_P2PS;
-               }
        } else if (p2p->cfg->config_methods) {
                methods |= p2p->cfg->config_methods &
                        (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY |
index 83b4356..9f0b3f3 100644 (file)
@@ -38,7 +38,7 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
 {
        const u8 *pos, *end;
        struct p2p_channels *ch;
-       size_t channels;
+       u8 channels;
        struct p2p_channels intersection;
 
        ch = &dev->channels;
@@ -58,14 +58,14 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
        }
        pos += 3;
 
-       while (pos + 2 < end) {
+       while (end - pos > 2) {
                struct p2p_reg_class *cl = &ch->reg_class[ch->reg_classes];
                cl->reg_class = *pos++;
-               if (pos + 1 + pos[0] > end) {
+               channels = *pos++;
+               if (channels > end - pos) {
                        p2p_info(p2p, "Invalid peer Channel List");
                        return -1;
                }
-               channels = *pos++;
                cl->channels = channels > P2P_MAX_REG_CLASS_CHANNELS ?
                        P2P_MAX_REG_CLASS_CHANNELS : channels;
                os_memcpy(cl->channel, pos, cl->channels);
@@ -384,7 +384,7 @@ void p2p_reselect_channel(struct p2p_data *p2p,
        unsigned int i;
        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_vht[] = { 128, 129, 130, 0 };
 
        if (p2p->own_freq_preference > 0 &&
            p2p_freq_to_channel(p2p->own_freq_preference,
@@ -901,6 +901,14 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
                        return;
                }
 
+               if (dev->go_neg_req_sent &&
+                   (dev->flags & P2P_DEV_PEER_WAITING_RESPONSE)) {
+                       p2p_dbg(p2p,
+                               "Do not reply since peer is waiting for us to start a new GO Negotiation and GO Neg Request already sent");
+                       p2p_parse_free(&msg);
+                       return;
+               }
+
                go = p2p_go_det(p2p->go_intent, *msg.go_intent);
                if (go < 0) {
                        p2p_dbg(p2p, "Incompatible GO Intent");
@@ -1052,7 +1060,7 @@ fail:
                        P2P_PENDING_GO_NEG_RESPONSE_FAILURE;
        if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
                            p2p->cfg->dev_addr,
-                           wpabuf_head(resp), wpabuf_len(resp), 500) < 0) {
+                           wpabuf_head(resp), wpabuf_len(resp), 100) < 0) {
                p2p_dbg(p2p, "Failed to send Action frame");
        }
 
@@ -1260,6 +1268,11 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
                dev->client_timeout = msg.config_timeout[1];
        }
 
+       if (msg.wfd_subelems) {
+               wpabuf_free(dev->info.wfd_subelems);
+               dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+       }
+
        if (!msg.operating_channel && !go) {
                /*
                 * Note: P2P Client may omit Operating Channel attribute to
@@ -1386,7 +1399,7 @@ fail:
 
        if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
                            wpabuf_head(dev->go_neg_conf),
-                           wpabuf_len(dev->go_neg_conf), 200) < 0) {
+                           wpabuf_len(dev->go_neg_conf), 50) < 0) {
                p2p_dbg(p2p, "Failed to send Action frame");
                p2p_go_neg_failed(p2p, -1);
                p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
index 0d66993..051b4e3 100644 (file)
@@ -155,7 +155,8 @@ static void p2p_group_add_common_ies(struct p2p_group *group,
                group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
        if (group->num_members >= group->cfg->max_clients)
                group_capab |= P2P_GROUP_CAPAB_GROUP_LIMIT;
-       group_capab |= P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION;
+       if (group->cfg->ip_addr_alloc)
+               group_capab |= P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION;
        p2p_buf_add_capability(ie, dev_capab, group_capab);
 }
 
@@ -296,14 +297,14 @@ static int wifi_display_add_dev_info_descr(struct wpabuf *buf,
        os_memset(zero_addr, 0, ETH_ALEN);
        pos = wpabuf_head_u8(m->wfd_ie);
        end = pos + wpabuf_len(m->wfd_ie);
-       while (pos + 1 < end) {
+       while (end - pos >= 3) {
                u8 id;
                u16 len;
 
                id = *pos++;
                len = WPA_GET_BE16(pos);
                pos += 2;
-               if (pos + len > end)
+               if (len > end - pos)
                        break;
 
                switch (id) {
@@ -849,6 +850,20 @@ static struct p2p_group_member * p2p_group_get_client(struct p2p_group *group,
 }
 
 
+const u8 * p2p_group_get_client_interface_addr(struct p2p_group *group,
+                                              const u8 *dev_addr)
+{
+       struct p2p_group_member *m;
+
+       if (!group)
+               return NULL;
+       m = p2p_group_get_client(group, dev_addr);
+       if (m)
+               return m->addr;
+       return NULL;
+}
+
+
 static struct p2p_group_member * p2p_group_get_client_iface(
        struct p2p_group *group, const u8 *interface_addr)
 {
@@ -1097,7 +1112,7 @@ int p2p_group_get_common_freqs(struct p2p_group *group, int *common_freqs,
                struct p2p_device *dev;
 
                dev = p2p_get_device(group->p2p, m->dev_addr);
-               if (!dev)
+               if (!dev || dev->channels.reg_classes == 0)
                        continue;
 
                p2p_channels_intersect(&intersect, &dev->channels, &res);
index 0ce4058..47524d4 100644 (file)
@@ -308,6 +308,18 @@ struct p2p_data {
         */
        int num_p2p_sd_queries;
 
+       /**
+        * sd_query_no_ack - The first peer (Dev Addr) that did not ACK SD Query
+        *
+        * This is used to track the first peer that did not ACK an SD Query
+        * within a single P2P Search iteration. All zeros address means no such
+        * peer was yet seen. This information is used to allow a new Listen and
+        * Search phases to be once every pending SD Query has been sent once to
+        * each peer instead of looping all pending attempts continuously until
+        * running out of retry maximums.
+        */
+       u8 sd_query_no_ack[ETH_ALEN];
+
        /* GO Negotiation data */
 
        /**
@@ -691,6 +703,8 @@ int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
                              u8 *op_channel);
 
 /* p2p_parse.c */
+void p2p_copy_filter_devname(char *dst, size_t dst_len,
+                            const void *src, size_t src_len);
 int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg);
 int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg);
 int p2p_parse(const u8 *data, size_t len, struct p2p_message *msg);
index 108e5b7..bbba001 100644 (file)
@@ -284,7 +284,7 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
 
                if (!p2p_channels_includes(&intersection, reg_class, channel))
                {
-                       p2p_dbg(p2p, "forced freq %d MHz not in the supported channels interaction",
+                       p2p_dbg(p2p, "forced freq %d MHz not in the supported channels intersection",
                                op_freq);
                        status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
                        goto fail;
@@ -418,7 +418,7 @@ fail:
        p2p->pending_action_state = P2P_PENDING_INVITATION_RESPONSE;
        if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
                            p2p->cfg->dev_addr,
-                           wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
+                           wpabuf_head(resp), wpabuf_len(resp), 50) < 0) {
                p2p_dbg(p2p, "Failed to send Action frame");
        }
 
index bd1e68b..5d2299c 100644 (file)
 #include "p2p_i.h"
 
 
+void p2p_copy_filter_devname(char *dst, size_t dst_len,
+                            const void *src, size_t src_len)
+{
+       size_t i;
+
+       if (src_len >= dst_len)
+               src_len = dst_len - 1;
+       os_memcpy(dst, src, src_len);
+       dst[src_len] = '\0';
+       for (i = 0; i < src_len; i++) {
+               if (dst[i] == '\0')
+                       break;
+               if (is_ctrl_char(dst[i]))
+                       dst[i] = '_';
+       }
+}
+
+
 static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
                               struct p2p_message *msg)
 {
        const u8 *pos;
-       size_t i, nlen;
+       u16 nlen;
        char devtype[WPS_DEV_TYPE_BUFSIZE];
 
        switch (id) {
@@ -149,21 +167,14 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
                pos += 2;
                nlen = WPA_GET_BE16(pos);
                pos += 2;
-               if (data + len - pos < (int) nlen ||
-                   nlen > WPS_DEV_NAME_MAX_LEN) {
+               if (nlen > data + len - pos || nlen > WPS_DEV_NAME_MAX_LEN) {
                        wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name "
-                                  "length %d (buf len %d)", (int) nlen,
+                                  "length %u (buf len %d)", nlen,
                                   (int) (data + len - pos));
                        return -1;
                }
-               os_memcpy(msg->device_name, pos, nlen);
-               msg->device_name[nlen] = '\0';
-               for (i = 0; i < nlen; i++) {
-                       if (msg->device_name[i] == '\0')
-                               break;
-                       if (is_ctrl_char(msg->device_name[i]))
-                               msg->device_name[i] = '_';
-               }
+               p2p_copy_filter_devname(msg->device_name,
+                                       sizeof(msg->device_name), pos, nlen);
                wpa_printf(MSG_DEBUG, "P2P: * Device Info: addr " MACSTR
                           " primary device type %s device name '%s' "
                           "config methods 0x%x",
@@ -637,49 +648,48 @@ int p2p_group_info_parse(const u8 *gi, size_t gi_len,
        gend = gi + gi_len;
        while (g < gend) {
                struct p2p_client_info *cli;
-               const u8 *t, *cend;
-               int count;
+               const u8 *cend;
+               u16 count;
+               u8 len;
 
                cli = &info->client[info->num_clients];
-               cend = g + 1 + g[0];
-               if (cend > gend)
+               len = *g++;
+               if (len > gend - g || len < 2 * ETH_ALEN + 1 + 2 + 8 + 1)
                        return -1; /* invalid data */
+               cend = g + len;
                /* g at start of P2P Client Info Descriptor */
-               /* t at Device Capability Bitmap */
-               t = g + 1 + 2 * ETH_ALEN;
-               if (t > cend)
-                       return -1; /* invalid data */
-               cli->p2p_device_addr = g + 1;
-               cli->p2p_interface_addr = g + 1 + ETH_ALEN;
-               cli->dev_capab = t[0];
-
-               if (t + 1 + 2 + 8 + 1 > cend)
-                       return -1; /* invalid data */
-
-               cli->config_methods = WPA_GET_BE16(&t[1]);
-               cli->pri_dev_type = &t[3];
-
-               t += 1 + 2 + 8;
-               /* t at Number of Secondary Device Types */
-               cli->num_sec_dev_types = *t++;
-               if (t + 8 * cli->num_sec_dev_types > cend)
+               cli->p2p_device_addr = g;
+               g += ETH_ALEN;
+               cli->p2p_interface_addr = g;
+               g += ETH_ALEN;
+               cli->dev_capab = *g++;
+
+               cli->config_methods = WPA_GET_BE16(g);
+               g += 2;
+               cli->pri_dev_type = g;
+               g += 8;
+
+               /* g at Number of Secondary Device Types */
+               len = *g++;
+               if (8 * len > cend - g)
                        return -1; /* invalid data */
-               cli->sec_dev_types = t;
-               t += 8 * cli->num_sec_dev_types;
+               cli->num_sec_dev_types = len;
+               cli->sec_dev_types = g;
+               g += 8 * len;
 
-               /* t at Device Name in WPS TLV format */
-               if (t + 2 + 2 > cend)
+               /* g at Device Name in WPS TLV format */
+               if (cend - g < 2 + 2)
                        return -1; /* invalid data */
-               if (WPA_GET_BE16(t) != ATTR_DEV_NAME)
+               if (WPA_GET_BE16(g) != ATTR_DEV_NAME)
                        return -1; /* invalid Device Name TLV */
-               t += 2;
-               count = WPA_GET_BE16(t);
-               t += 2;
-               if (count > cend - t)
+               g += 2;
+               count = WPA_GET_BE16(g);
+               g += 2;
+               if (count > cend - g)
                        return -1; /* invalid Device Name TLV */
                if (count >= WPS_DEV_NAME_MAX_LEN)
                        count = WPS_DEV_NAME_MAX_LEN;
-               cli->dev_name = (const char *) t;
+               cli->dev_name = (const char *) g;
                cli->dev_name_len = count;
 
                g = cend;
index 8900945..93a0535 100644 (file)
@@ -40,21 +40,31 @@ static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
 }
 
 
-static void p2ps_add_new_group_info(struct p2p_data *p2p, struct wpabuf *buf)
+static void p2ps_add_new_group_info(struct p2p_data *p2p,
+                                   struct p2p_device *dev,
+                                   struct wpabuf *buf)
 {
        int found;
        u8 intended_addr[ETH_ALEN];
        u8 ssid[SSID_MAX_LEN];
        size_t ssid_len;
        int group_iface;
+       unsigned int force_freq;
 
        if (!p2p->cfg->get_go_info)
                return;
 
        found = p2p->cfg->get_go_info(
                p2p->cfg->cb_ctx, intended_addr, ssid,
-               &ssid_len, &group_iface);
+               &ssid_len, &group_iface, &force_freq);
        if (found) {
+               if (force_freq > 0) {
+                       p2p->p2ps_prov->force_freq = force_freq;
+                       p2p->p2ps_prov->pref_freq = 0;
+
+                       if (dev)
+                               p2p_prepare_channel(p2p, dev, force_freq, 0, 0);
+               }
                p2p_buf_add_group_id(buf, p2p->cfg->dev_addr,
                                     ssid, ssid_len);
 
@@ -92,62 +102,62 @@ static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev,
        size_t ssid_len;
        u8 go_dev_addr[ETH_ALEN];
        u8 intended_addr[ETH_ALEN];
+       int follow_on_req_fail = prov->status >= 0 &&
+               prov->status != P2P_SC_SUCCESS_DEFERRED;
 
        /* If we might be explicite group owner, add GO details */
-       if (prov->conncap & (P2PS_SETUP_GROUP_OWNER |
-                            P2PS_SETUP_NEW))
-               p2ps_add_new_group_info(p2p, buf);
+       if (!follow_on_req_fail &&
+           (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW)))
+               p2ps_add_new_group_info(p2p, dev, buf);
 
        if (prov->status >= 0)
                p2p_buf_add_status(buf, (u8) prov->status);
        else
                prov->method = config_methods;
 
-       if (p2p->cfg->get_persistent_group) {
-               shared_group = p2p->cfg->get_persistent_group(
-                       p2p->cfg->cb_ctx, dev->info.p2p_device_addr, NULL, 0,
-                       go_dev_addr, ssid, &ssid_len, intended_addr);
-       }
-
-       /* Add Operating Channel if conncap includes GO */
-       if (shared_group ||
-           (prov->conncap & (P2PS_SETUP_GROUP_OWNER |
-                             P2PS_SETUP_NEW))) {
-               u8 tmp;
+       if (!follow_on_req_fail) {
+               if (p2p->cfg->get_persistent_group) {
+                       shared_group = p2p->cfg->get_persistent_group(
+                               p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
+                               NULL, 0, go_dev_addr, ssid, &ssid_len,
+                               intended_addr);
+               }
 
-               p2p_go_select_channel(p2p, dev, &tmp);
+               if (shared_group ||
+                   (prov->conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_NEW)))
+                       p2p_buf_add_channel_list(buf, p2p->cfg->country,
+                                                &p2p->channels);
 
-               if (p2p->op_reg_class && p2p->op_channel)
+               if ((shared_group && !is_zero_ether_addr(intended_addr)) ||
+                   (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW)))
                        p2p_buf_add_operating_channel(buf, p2p->cfg->country,
                                                      p2p->op_reg_class,
                                                      p2p->op_channel);
-               else
-                       p2p_buf_add_operating_channel(buf, p2p->cfg->country,
-                                                     p2p->cfg->op_reg_class,
-                                                     p2p->cfg->op_channel);
        }
 
-       p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->cfg->channels);
-
-       if (prov->info[0])
+       if (prov->status < 0 && prov->info[0])
                p2p_buf_add_session_info(buf, prov->info);
 
-       p2p_buf_add_connection_capability(buf, prov->conncap);
+       if (!follow_on_req_fail)
+               p2p_buf_add_connection_capability(buf, prov->conncap);
 
        p2p_buf_add_advertisement_id(buf, prov->adv_id, prov->adv_mac);
 
-       if (shared_group || prov->conncap == P2PS_SETUP_NEW ||
-           prov->conncap ==
-           (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW) ||
-           prov->conncap ==
-           (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT)) {
-               /* Add Config Timeout */
-               p2p_buf_add_config_timeout(buf, p2p->go_timeout,
-                                          p2p->client_timeout);
-       }
+       if (!follow_on_req_fail) {
+               if (shared_group || prov->conncap == P2PS_SETUP_NEW ||
+                   prov->conncap ==
+                   (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW) ||
+                   prov->conncap ==
+                   (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT)) {
+                       /* Add Config Timeout */
+                       p2p_buf_add_config_timeout(buf, p2p->go_timeout,
+                                                  p2p->client_timeout);
+               }
 
-       p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class,
-                                  p2p->cfg->channel);
+               p2p_buf_add_listen_channel(buf, p2p->cfg->country,
+                                          p2p->cfg->reg_class,
+                                          p2p->cfg->channel);
+       }
 
        p2p_buf_add_session_id(buf, prov->session_id, prov->session_mac);
 
@@ -285,6 +295,11 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
                u8 *len = p2p_buf_add_ie_hdr(buf);
                struct p2ps_provision *prov = p2p->p2ps_prov;
                u8 group_capab;
+               u8 conncap = 0;
+
+               if (status == P2P_SC_SUCCESS ||
+                   status == P2P_SC_SUCCESS_DEFERRED)
+                       conncap = prov->conncap;
 
                if (!status && prov->status != -1)
                        status = prov->status;
@@ -301,7 +316,7 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
                                       group_capab);
                p2p_buf_add_device_info(buf, p2p, NULL);
 
-               if (persist_ssid && p2p->cfg->get_persistent_group &&
+               if (persist_ssid && p2p->cfg->get_persistent_group && dev &&
                    (status == P2P_SC_SUCCESS ||
                     status == P2P_SC_SUCCESS_DEFERRED)) {
                        u8 ssid[SSID_MAX_LEN];
@@ -323,16 +338,11 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
                        }
                }
 
-               if (!persist && (prov->conncap & P2PS_SETUP_GROUP_OWNER))
-                       p2ps_add_new_group_info(p2p, buf);
+               if (!persist && (conncap & P2PS_SETUP_GROUP_OWNER))
+                       p2ps_add_new_group_info(p2p, dev, buf);
 
                /* Add Operating Channel if conncap indicates GO */
-               if (persist || (prov->conncap & P2PS_SETUP_GROUP_OWNER)) {
-                       u8 tmp;
-
-                       if (dev)
-                               p2p_go_select_channel(p2p, dev, &tmp);
-
+               if (persist || (conncap & P2PS_SETUP_GROUP_OWNER)) {
                        if (p2p->op_reg_class && p2p->op_channel)
                                p2p_buf_add_operating_channel(
                                        buf, p2p->cfg->country,
@@ -345,17 +355,20 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
                                        p2p->cfg->op_channel);
                }
 
-               p2p_buf_add_channel_list(buf, p2p->cfg->country,
-                                        &p2p->cfg->channels);
+               if (persist ||
+                   (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER)))
+                       p2p_buf_add_channel_list(buf, p2p->cfg->country,
+                                                &p2p->channels);
 
-               if (!persist && (status == P2P_SC_SUCCESS ||
-                                status == P2P_SC_SUCCESS_DEFERRED))
-                       p2p_buf_add_connection_capability(buf, prov->conncap);
+               if (!persist && conncap)
+                       p2p_buf_add_connection_capability(buf, conncap);
 
                p2p_buf_add_advertisement_id(buf, adv_id, prov->adv_mac);
 
-               p2p_buf_add_config_timeout(buf, p2p->go_timeout,
-                                          p2p->client_timeout);
+               if (persist ||
+                   (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER)))
+                       p2p_buf_add_config_timeout(buf, p2p->go_timeout,
+                                                  p2p->client_timeout);
 
                p2p_buf_add_session_id(buf, prov->session_id,
                                       prov->session_mac);
@@ -427,6 +440,117 @@ static u8 p2ps_own_preferred_cpt(const u8 *cpt_priority, u8 req_cpt_mask)
 }
 
 
+/* Check if the message contains a valid P2PS PD Request */
+static int p2ps_validate_pd_req(struct p2p_data *p2p, struct p2p_message *msg,
+                               const u8 *addr)
+{
+       u8 group_id = 0;
+       u8 intended_addr = 0;
+       u8 operating_channel = 0;
+       u8 channel_list = 0;
+       u8 config_timeout = 0;
+       u8 listen_channel = 0;
+
+#define P2PS_PD_REQ_CHECK(_val, _attr) \
+do { \
+       if ((_val) && !msg->_attr) { \
+               p2p_dbg(p2p, "Not P2PS PD Request. Missing %s", #_attr); \
+               return -1; \
+       } \
+} while (0)
+
+       P2PS_PD_REQ_CHECK(1, adv_id);
+       P2PS_PD_REQ_CHECK(1, session_id);
+       P2PS_PD_REQ_CHECK(1, session_mac);
+       P2PS_PD_REQ_CHECK(1, adv_mac);
+       P2PS_PD_REQ_CHECK(1, capability);
+       P2PS_PD_REQ_CHECK(1, p2p_device_info);
+       P2PS_PD_REQ_CHECK(1, feature_cap);
+
+       /*
+        * We don't need to check Connection Capability, Persistent Group,
+        * and related attributes for follow-on PD Request with a status
+        * other than SUCCESS_DEFERRED.
+        */
+       if (msg->status && *msg->status != P2P_SC_SUCCESS_DEFERRED)
+               return 0;
+
+       P2PS_PD_REQ_CHECK(1, conn_cap);
+
+       /*
+        * Note 1: A feature capability attribute structure can be changed
+        * in the future. The assumption is that such modifications are
+        * backward compatible, therefore we allow processing of msg.feature_cap
+        * exceeding the size of the p2ps_feature_capab structure.
+        * Note 2: Verification of msg.feature_cap_len below has to be changed
+        * to allow 2 byte feature capability processing if
+        * struct p2ps_feature_capab is extended to include additional fields
+        * and it affects the structure size.
+        */
+       if (msg->feature_cap_len < sizeof(struct p2ps_feature_capab)) {
+               p2p_dbg(p2p, "P2PS: Invalid feature capability len");
+               return -1;
+       }
+
+       switch (*msg->conn_cap) {
+       case P2PS_SETUP_NEW:
+               group_id = 1;
+               intended_addr = 1;
+               operating_channel = 1;
+               channel_list = 1;
+               config_timeout = 1;
+               listen_channel = 1;
+               break;
+       case P2PS_SETUP_CLIENT:
+               channel_list = 1;
+               listen_channel = 1;
+               break;
+       case P2PS_SETUP_GROUP_OWNER:
+               group_id = 1;
+               intended_addr = 1;
+               operating_channel = 1;
+               break;
+       case P2PS_SETUP_NEW | P2PS_SETUP_GROUP_OWNER:
+               group_id = 1;
+               operating_channel = 1;
+               intended_addr = 1;
+               channel_list = 1;
+               config_timeout = 1;
+               break;
+       case P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER:
+               group_id = 1;
+               intended_addr = 1;
+               operating_channel = 1;
+               channel_list = 1;
+               config_timeout = 1;
+               break;
+       default:
+               p2p_dbg(p2p, "Invalid P2PS PD connection capability");
+               return -1;
+       }
+
+       if (msg->persistent_dev) {
+               channel_list = 1;
+               config_timeout = 1;
+               if (os_memcmp(msg->persistent_dev, addr, ETH_ALEN) == 0) {
+                       intended_addr = 1;
+                       operating_channel = 1;
+               }
+       }
+
+       P2PS_PD_REQ_CHECK(group_id, group_id);
+       P2PS_PD_REQ_CHECK(intended_addr, intended_addr);
+       P2PS_PD_REQ_CHECK(operating_channel, operating_channel);
+       P2PS_PD_REQ_CHECK(channel_list, channel_list);
+       P2PS_PD_REQ_CHECK(config_timeout, config_timeout);
+       P2PS_PD_REQ_CHECK(listen_channel, listen_channel);
+
+#undef P2PS_PD_REQ_CHECK
+
+       return 0;
+}
+
+
 void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                               const u8 *data, size_t len, int rx_freq)
 {
@@ -440,14 +564,16 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
        u8 conncap = P2PS_SETUP_NEW;
        u8 auto_accept = 0;
        u32 session_id = 0;
-       u8 session_mac[ETH_ALEN];
-       u8 adv_mac[ETH_ALEN];
+       u8 session_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+       u8 adv_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
        const u8 *group_mac;
        int passwd_id = DEV_PW_DEFAULT;
        u16 config_methods;
        u16 allowed_config_methods = WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
        struct p2ps_feature_capab resp_fcap = { 0, 0 };
-       struct p2ps_feature_capab *req_fcap;
+       struct p2ps_feature_capab *req_fcap = NULL;
+       u8 remote_conncap;
+       u16 method;
 
        if (p2p_parse(data, len, &msg))
                return;
@@ -466,300 +592,431 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                                   0)) {
                        p2p_dbg(p2p, "Provision Discovery Request add device failed "
                                MACSTR, MAC2STR(sa));
+                       goto out;
+               }
+
+               if (!dev) {
+                       dev = p2p_get_device(p2p, sa);
+                       if (!dev) {
+                               p2p_dbg(p2p,
+                                       "Provision Discovery device not found "
+                                       MACSTR, MAC2STR(sa));
+                               goto out;
+                       }
                }
        } else if (msg.wfd_subelems) {
                wpabuf_free(dev->info.wfd_subelems);
                dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
        }
 
-       if (msg.adv_id)
-               allowed_config_methods |= WPS_CONFIG_P2PS;
-       else
+       if (!msg.adv_id) {
                allowed_config_methods |= WPS_CONFIG_PUSHBUTTON;
+               if (!(msg.wps_config_methods & allowed_config_methods)) {
+                       p2p_dbg(p2p,
+                               "Unsupported Config Methods in Provision Discovery Request");
+                       goto out;
+               }
 
-       if (!(msg.wps_config_methods & allowed_config_methods)) {
-               p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request");
-               goto out;
-       }
+               /* Legacy (non-P2PS) - Unknown groups allowed for P2PS */
+               if (msg.group_id) {
+                       size_t i;
 
-       /* Legacy (non-P2PS) - Unknown groups allowed for P2PS */
-       if (!msg.adv_id && msg.group_id) {
-               size_t i;
-               for (i = 0; i < p2p->num_groups; i++) {
-                       if (p2p_group_is_group_id_match(p2p->groups[i],
-                                                       msg.group_id,
-                                                       msg.group_id_len))
-                               break;
+                       for (i = 0; i < p2p->num_groups; i++) {
+                               if (p2p_group_is_group_id_match(
+                                           p2p->groups[i],
+                                           msg.group_id, msg.group_id_len))
+                                       break;
+                       }
+                       if (i == p2p->num_groups) {
+                               p2p_dbg(p2p,
+                                       "PD request for unknown P2P Group ID - reject");
+                               goto out;
+                       }
                }
-               if (i == p2p->num_groups) {
-                       p2p_dbg(p2p, "PD request for unknown P2P Group ID - reject");
+       } else {
+               allowed_config_methods |= WPS_CONFIG_P2PS;
+
+               /*
+                * Set adv_id here, so in case of an error, a P2PS PD Response
+                * will be sent.
+                */
+               adv_id = WPA_GET_LE32(msg.adv_id);
+               if (p2ps_validate_pd_req(p2p, &msg, sa) < 0) {
+                       reject = P2P_SC_FAIL_INVALID_PARAMS;
                        goto out;
                }
-       }
 
-       if (dev) {
-               dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
-                               P2P_DEV_PD_PEER_KEYPAD |
-                               P2P_DEV_PD_PEER_P2PS);
+               req_fcap = (struct p2ps_feature_capab *) msg.feature_cap;
 
-               /* Remove stale persistent groups */
-               if (p2p->cfg->remove_stale_groups) {
-                       p2p->cfg->remove_stale_groups(
-                               p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
-                               msg.persistent_dev,
-                               msg.persistent_ssid, msg.persistent_ssid_len);
+               os_memcpy(session_mac, msg.session_mac, ETH_ALEN);
+               os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
+
+               session_id = WPA_GET_LE32(msg.session_id);
+
+               if (msg.conn_cap)
+                       conncap = *msg.conn_cap;
+
+               /*
+                * We need to verify a P2PS config methog in an initial PD
+                * request or in a follow-on PD request with the status
+                * SUCCESS_DEFERRED.
+                */
+               if ((!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) &&
+                   !(msg.wps_config_methods & allowed_config_methods)) {
+                       p2p_dbg(p2p,
+                               "Unsupported Config Methods in Provision Discovery Request");
+                       goto out;
                }
+
+               /*
+                * TODO: since we don't support multiple PD, reject PD request
+                * if we are in the middle of P2PS PD with some other peer
+                */
        }
+
+       dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
+                       P2P_DEV_PD_PEER_KEYPAD |
+                       P2P_DEV_PD_PEER_P2PS);
+
        if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
                p2p_dbg(p2p, "Peer " MACSTR
                        " requested us to show a PIN on display", MAC2STR(sa));
-               if (dev)
-                       dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
+               dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
                passwd_id = DEV_PW_USER_SPECIFIED;
        } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
                p2p_dbg(p2p, "Peer " MACSTR
                        " requested us to write its PIN using keypad",
                        MAC2STR(sa));
-               if (dev)
-                       dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
+               dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
                passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
        } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) {
                p2p_dbg(p2p, "Peer " MACSTR " requesting P2PS PIN",
                        MAC2STR(sa));
-               if (dev)
-                       dev->flags |= P2P_DEV_PD_PEER_P2PS;
+               dev->flags |= P2P_DEV_PD_PEER_P2PS;
                passwd_id = DEV_PW_P2PS_DEFAULT;
        }
 
-       reject = P2P_SC_SUCCESS;
+       /* Remove stale persistent groups */
+       if (p2p->cfg->remove_stale_groups) {
+               p2p->cfg->remove_stale_groups(
+                       p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
+                       msg.persistent_dev,
+                       msg.persistent_ssid, msg.persistent_ssid_len);
+       }
 
-       os_memset(session_mac, 0, ETH_ALEN);
-       os_memset(adv_mac, 0, ETH_ALEN);
+       reject = P2P_SC_SUCCESS;
 
-       /* Note 1: A feature capability attribute structure can be changed
-        * in the future. The assumption is that such modifications are
-        * backwards compatible, therefore we allow processing of
-        * msg.feature_cap exceeding the size of the p2ps_feature_capab
-        * structure.
-        * Note 2: Vverification of msg.feature_cap_len below has to be changed
-        * to allow 2 byte feature capability processing if struct
-        * p2ps_feature_capab is extended to include additional fields and it
-        * affects the structure size.
+       /*
+        * End of a legacy P2P PD Request processing, from this point continue
+        * with P2PS one.
         */
-       if (msg.adv_id && msg.session_id && msg.session_mac && msg.adv_mac &&
-           msg.feature_cap && msg.feature_cap_len >= sizeof(*req_fcap) &&
-           (msg.status || msg.conn_cap)) {
-               u8 remote_conncap;
+       if (!msg.adv_id)
+               goto out;
 
-               req_fcap = (struct p2ps_feature_capab *) msg.feature_cap;
+       remote_conncap = conncap;
 
-               os_memcpy(session_mac, msg.session_mac, ETH_ALEN);
-               os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
+       if (!msg.status) {
+               unsigned int forced_freq, pref_freq;
 
-               session_id = WPA_GET_LE32(msg.session_id);
-               adv_id = WPA_GET_LE32(msg.adv_id);
-
-               if (!msg.status)
-                       p2ps_adv = p2p_service_p2ps_id(p2p, adv_id);
+               if (os_memcmp(p2p->cfg->dev_addr, msg.adv_mac, ETH_ALEN)) {
+                       p2p_dbg(p2p,
+                               "P2PS PD adv mac does not match the local one");
+                       reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+                       goto out;
+               }
 
-               p2p_dbg(p2p, "adv_id: %x - p2ps_adv - %p", adv_id, p2ps_adv);
+               p2ps_adv = p2p_service_p2ps_id(p2p, adv_id);
+               if (!p2ps_adv) {
+                       p2p_dbg(p2p, "P2PS PD invalid adv_id=0x%X", adv_id);
+                       reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+                       goto out;
+               }
+               p2p_dbg(p2p, "adv_id: 0x%X, p2ps_adv: %p", adv_id, p2ps_adv);
 
-               if (msg.conn_cap)
-                       conncap = *msg.conn_cap;
-               remote_conncap = conncap;
+               auto_accept = p2ps_adv->auto_accept;
+               conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx,
+                                                         conncap, auto_accept,
+                                                         &forced_freq,
+                                                         &pref_freq);
 
-               if (p2ps_adv) {
-                       auto_accept = p2ps_adv->auto_accept;
-                       conncap = p2p->cfg->p2ps_group_capability(
-                               p2p->cfg->cb_ctx, conncap, auto_accept);
+               p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d",
+                       auto_accept, remote_conncap, conncap);
 
-                       p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d",
-                               auto_accept, remote_conncap, conncap);
+               p2p_prepare_channel(p2p, dev, forced_freq, pref_freq, 0);
 
-                       resp_fcap.cpt =
-                               p2ps_own_preferred_cpt(p2ps_adv->cpt_priority,
+               resp_fcap.cpt = p2ps_own_preferred_cpt(p2ps_adv->cpt_priority,
                                                       req_fcap->cpt);
 
+               p2p_dbg(p2p, "cpt: service:0x%x remote:0x%x result:0x%x",
+                       p2ps_adv->cpt_mask, req_fcap->cpt, resp_fcap.cpt);
+
+               if (!resp_fcap.cpt) {
+                       p2p_dbg(p2p,
+                               "Incompatible P2PS feature capability CPT bitmask");
+                       reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+               } else if (p2ps_adv->config_methods &&
+                          !(msg.wps_config_methods &
+                            p2ps_adv->config_methods)) {
                        p2p_dbg(p2p,
-                               "cpt: service:0x%x remote:0x%x result:0x%x",
-                               p2ps_adv->cpt_mask, req_fcap->cpt,
-                               resp_fcap.cpt);
+                               "Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)",
+                               p2ps_adv->config_methods,
+                               msg.wps_config_methods);
+                       reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+               } else if (!p2ps_adv->state) {
+                       p2p_dbg(p2p, "P2PS state unavailable");
+                       reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+               } else if (!conncap) {
+                       p2p_dbg(p2p, "Conncap resolution failed");
+                       reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+               }
 
-                       if (!resp_fcap.cpt) {
-                               p2p_dbg(p2p,
-                                       "Incompatible P2PS feature capability CPT bitmask");
-                               reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
-                       } else if (p2ps_adv->config_methods &&
-                                  !(msg.wps_config_methods &
-                                  p2ps_adv->config_methods)) {
-                               p2p_dbg(p2p,
-                                       "Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)",
-                                       p2ps_adv->config_methods,
-                                       msg.wps_config_methods);
-                               reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
-                       } else if (!p2ps_adv->state) {
-                               p2p_dbg(p2p, "P2PS state unavailable");
-                               reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
-                       } else if (!conncap) {
-                               p2p_dbg(p2p, "Conncap resolution failed");
-                               reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
-                       }
+               if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
+                       p2p_dbg(p2p, "Keypad - always defer");
+                       auto_accept = 0;
+               }
 
-                       if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
-                               p2p_dbg(p2p, "Keypad - always defer");
-                               auto_accept = 0;
+               if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) ||
+                    msg.persistent_dev) && conncap != P2PS_SETUP_NEW &&
+                   msg.channel_list && msg.channel_list_len &&
+                   p2p_peer_channels_check(p2p, &p2p->channels, dev,
+                                           msg.channel_list,
+                                           msg.channel_list_len) < 0) {
+                       p2p_dbg(p2p,
+                               "No common channels - force deferred flow");
+                       auto_accept = 0;
+               }
+
+               if (((remote_conncap & P2PS_SETUP_GROUP_OWNER) ||
+                    msg.persistent_dev) && msg.operating_channel) {
+                       struct p2p_channels intersect;
+
+                       /*
+                        * There are cases where only the operating channel is
+                        * provided. This requires saving the channel as the
+                        * supported channel list, and verifying that it is
+                        * supported.
+                        */
+                       if (dev->channels.reg_classes == 0 ||
+                           !p2p_channels_includes(&dev->channels,
+                                                  msg.operating_channel[3],
+                                                  msg.operating_channel[4])) {
+                               struct p2p_channels *ch = &dev->channels;
+
+                               os_memset(ch, 0, sizeof(*ch));
+                               ch->reg_class[0].reg_class =
+                                       msg.operating_channel[3];
+                               ch->reg_class[0].channel[0] =
+                                       msg.operating_channel[4];
+                               ch->reg_class[0].channels = 1;
+                               ch->reg_classes = 1;
                        }
 
-                       if (auto_accept || reject != P2P_SC_SUCCESS) {
-                               struct p2ps_provision *tmp;
-
-                               if (reject == P2P_SC_SUCCESS && !conncap) {
-                                       reject =
-                                               P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
-                               }
-
-                               if (p2ps_setup_p2ps_prov(
-                                           p2p, adv_id, session_id,
-                                           msg.wps_config_methods,
-                                           session_mac, adv_mac) < 0) {
-                                       reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
-                                       goto out;
-                               }
-
-                               tmp = p2p->p2ps_prov;
-                               if (conncap) {
-                                       tmp->conncap = conncap;
-                                       tmp->status = P2P_SC_SUCCESS;
-                               } else {
-                                       tmp->conncap = auto_accept;
-                                       tmp->status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
-                               }
-
-                               if (reject != P2P_SC_SUCCESS)
-                                       goto out;
+                       p2p_channels_intersect(&p2p->channels, &dev->channels,
+                                              &intersect);
+
+                       if (intersect.reg_classes == 0) {
+                               p2p_dbg(p2p,
+                                       "No common channels - force deferred flow");
+                               auto_accept = 0;
                        }
-               } else if (!msg.status) {
-                       reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
-                       goto out;
                }
 
-               if (!msg.status && !auto_accept &&
-                   (!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) {
+               if (auto_accept || reject != P2P_SC_SUCCESS) {
                        struct p2ps_provision *tmp;
 
-                       if (!conncap) {
-                               reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
-                               goto out;
-                       }
-
                        if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
                                                 msg.wps_config_methods,
                                                 session_mac, adv_mac) < 0) {
                                reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
                                goto out;
                        }
+
                        tmp = p2p->p2ps_prov;
-                       reject = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
-                       tmp->status = reject;
+                       tmp->force_freq = forced_freq;
+                       tmp->pref_freq = pref_freq;
+                       if (conncap) {
+                               tmp->conncap = conncap;
+                               tmp->status = P2P_SC_SUCCESS;
+                       } else {
+                               tmp->conncap = auto_accept;
+                               tmp->status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+                       }
+
+                       if (reject != P2P_SC_SUCCESS)
+                               goto out;
                }
+       }
 
-               if (msg.status) {
-                       if (*msg.status &&
-                           *msg.status != P2P_SC_SUCCESS_DEFERRED) {
-                               reject = *msg.status;
-                       } else if (*msg.status == P2P_SC_SUCCESS_DEFERRED &&
-                                  p2p->p2ps_prov) {
-                               u16 method = p2p->p2ps_prov->method;
+       if (!msg.status && !auto_accept &&
+           (!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) {
+               struct p2ps_provision *tmp;
 
-                               conncap = p2p->cfg->p2ps_group_capability(
-                                       p2p->cfg->cb_ctx, remote_conncap,
-                                       p2p->p2ps_prov->conncap);
+               if (!conncap) {
+                       reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+                       goto out;
+               }
 
-                               p2p_dbg(p2p,
-                                       "Conncap: local:%d remote:%d result:%d",
-                                       p2p->p2ps_prov->conncap,
-                                       remote_conncap, conncap);
+               if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
+                                        msg.wps_config_methods,
+                                        session_mac, adv_mac) < 0) {
+                       reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+                       goto out;
+               }
+               tmp = p2p->p2ps_prov;
+               reject = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
+               tmp->status = reject;
+       }
 
-                               resp_fcap.cpt = p2ps_own_preferred_cpt(
-                                       p2p->p2ps_prov->cpt_priority,
-                                       req_fcap->cpt);
+       /* Not a P2PS Follow-on PD */
+       if (!msg.status)
+               goto out;
 
-                               p2p_dbg(p2p,
-                                       "cpt: local:0x%x remote:0x%x result:0x%x",
-                                       p2p->p2ps_prov->cpt_mask,
-                                       req_fcap->cpt, resp_fcap.cpt);
+       if (*msg.status && *msg.status != P2P_SC_SUCCESS_DEFERRED) {
+               reject = *msg.status;
+               goto out;
+       }
 
-                               /*
-                                * Ensure that if we asked for PIN originally,
-                                * our method is consistent with original
-                                * request.
-                                */
-                               if (method & WPS_CONFIG_DISPLAY)
-                                       method = WPS_CONFIG_KEYPAD;
-                               else if (method & WPS_CONFIG_KEYPAD)
-                                       method = WPS_CONFIG_DISPLAY;
-
-                               if (!conncap ||
-                                   !(msg.wps_config_methods & method)) {
-                                       /*
-                                        * Reject this "Deferred Accept*
-                                        * if incompatible conncap or method
-                                        */
-                                       reject =
-                                               P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
-                               } else if (!resp_fcap.cpt) {
-                                       p2p_dbg(p2p,
-                                               "Incompatible P2PS feature capability CPT bitmask");
-                                       reject =
-                                               P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
-                               } else {
-                                       reject = P2P_SC_SUCCESS;
-                               }
-
-                               p2p->p2ps_prov->status = reject;
-                               p2p->p2ps_prov->conncap = conncap;
-                       }
-               }
+       if (*msg.status != P2P_SC_SUCCESS_DEFERRED || !p2p->p2ps_prov)
+               goto out;
+
+       if (p2p->p2ps_prov->adv_id != adv_id ||
+           os_memcmp(p2p->p2ps_prov->adv_mac, msg.adv_mac, ETH_ALEN)) {
+               p2p_dbg(p2p,
+                       "P2PS Follow-on PD with mismatch Advertisement ID/MAC");
+               goto out;
        }
 
+       if (p2p->p2ps_prov->session_id != session_id ||
+           os_memcmp(p2p->p2ps_prov->session_mac, msg.session_mac, ETH_ALEN)) {
+               p2p_dbg(p2p, "P2PS Follow-on PD with mismatch Session ID/MAC");
+               goto out;
+       }
+
+       method = p2p->p2ps_prov->method;
+
+       conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx,
+                                                 remote_conncap,
+                                                 p2p->p2ps_prov->conncap,
+                                                 &p2p->p2ps_prov->force_freq,
+                                                 &p2p->p2ps_prov->pref_freq);
+
+       resp_fcap.cpt = p2ps_own_preferred_cpt(p2p->p2ps_prov->cpt_priority,
+                                              req_fcap->cpt);
+
+       p2p_dbg(p2p, "cpt: local:0x%x remote:0x%x result:0x%x",
+               p2p->p2ps_prov->cpt_mask, req_fcap->cpt, resp_fcap.cpt);
+
+       p2p_prepare_channel(p2p, dev, p2p->p2ps_prov->force_freq,
+                           p2p->p2ps_prov->pref_freq, 0);
+
+       /*
+        * Ensure that if we asked for PIN originally, our method is consistent
+        * with original request.
+        */
+       if (method & WPS_CONFIG_DISPLAY)
+               method = WPS_CONFIG_KEYPAD;
+       else if (method & WPS_CONFIG_KEYPAD)
+               method = WPS_CONFIG_DISPLAY;
+
+       if (!conncap || !(msg.wps_config_methods & method)) {
+               /*
+                * Reject this "Deferred Accept*
+                * if incompatible conncap or method
+                */
+               reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+       } else if (!resp_fcap.cpt) {
+               p2p_dbg(p2p,
+                       "Incompatible P2PS feature capability CPT bitmask");
+               reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+       } else if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) ||
+                   msg.persistent_dev) && conncap != P2PS_SETUP_NEW &&
+                  msg.channel_list && msg.channel_list_len &&
+                  p2p_peer_channels_check(p2p, &p2p->channels, dev,
+                                          msg.channel_list,
+                                          msg.channel_list_len) < 0) {
+               p2p_dbg(p2p,
+                       "No common channels in Follow-On Provision Discovery Request");
+               reject = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+       } else {
+               reject = P2P_SC_SUCCESS;
+       }
+
+       dev->oper_freq = 0;
+       if (reject == P2P_SC_SUCCESS || reject == P2P_SC_SUCCESS_DEFERRED) {
+               u8 tmp;
+
+               if (msg.operating_channel)
+                       dev->oper_freq =
+                               p2p_channel_to_freq(msg.operating_channel[3],
+                                                   msg.operating_channel[4]);
+
+               if ((conncap & P2PS_SETUP_GROUP_OWNER) &&
+                   p2p_go_select_channel(p2p, dev, &tmp) < 0)
+                       reject = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+       }
+
+       p2p->p2ps_prov->status = reject;
+       p2p->p2ps_prov->conncap = conncap;
+
 out:
        if (reject == P2P_SC_SUCCESS ||
            reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
                config_methods = msg.wps_config_methods;
        else
                config_methods = 0;
-       resp = p2p_build_prov_disc_resp(p2p, dev, msg.dialog_token, reject,
-                                       config_methods, adv_id,
-                                       msg.group_id, msg.group_id_len,
-                                       msg.persistent_ssid,
-                                       msg.persistent_ssid_len,
-                                       (const u8 *) &resp_fcap,
-                                       sizeof(resp_fcap));
-       if (resp == NULL) {
-               p2p_parse_free(&msg);
-               return;
-       }
-       p2p_dbg(p2p, "Sending Provision Discovery Response");
-       if (rx_freq > 0)
-               freq = rx_freq;
-       else
-               freq = p2p_channel_to_freq(p2p->cfg->reg_class,
-                                          p2p->cfg->channel);
-       if (freq < 0) {
-               p2p_dbg(p2p, "Unknown regulatory class/channel");
+
+       /*
+        * Send PD Response for an initial PD Request or for follow-on
+        * PD Request with P2P_SC_SUCCESS_DEFERRED status.
+        */
+       if (!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) {
+               resp = p2p_build_prov_disc_resp(p2p, dev, msg.dialog_token,
+                                               reject, config_methods, adv_id,
+                                               msg.group_id, msg.group_id_len,
+                                               msg.persistent_ssid,
+                                               msg.persistent_ssid_len,
+                                               (const u8 *) &resp_fcap,
+                                               sizeof(resp_fcap));
+               if (!resp) {
+                       p2p_parse_free(&msg);
+                       return;
+               }
+               p2p_dbg(p2p, "Sending Provision Discovery Response");
+               if (rx_freq > 0)
+                       freq = rx_freq;
+               else
+                       freq = p2p_channel_to_freq(p2p->cfg->reg_class,
+                                                  p2p->cfg->channel);
+               if (freq < 0) {
+                       p2p_dbg(p2p, "Unknown regulatory class/channel");
+                       wpabuf_free(resp);
+                       p2p_parse_free(&msg);
+                       return;
+               }
+               p2p->pending_action_state = P2P_PENDING_PD_RESPONSE;
+               if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
+                                   p2p->cfg->dev_addr,
+                                   wpabuf_head(resp), wpabuf_len(resp),
+                                   50) < 0)
+                       p2p_dbg(p2p, "Failed to send Action frame");
+               else
+                       p2p->send_action_in_progress = 1;
+
                wpabuf_free(resp);
+       }
+
+       if (!dev) {
                p2p_parse_free(&msg);
                return;
        }
-       p2p->pending_action_state = P2P_PENDING_PD_RESPONSE;
-       if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
-                           p2p->cfg->dev_addr,
-                           wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
-               p2p_dbg(p2p, "Failed to send Action frame");
-       } else
-               p2p->send_action_in_progress = 1;
 
-       wpabuf_free(resp);
+       freq = 0;
+       if (reject == P2P_SC_SUCCESS && conncap == P2PS_SETUP_GROUP_OWNER) {
+               freq = p2p_channel_to_freq(p2p->op_reg_class,
+                                          p2p->op_channel);
+               if (freq < 0)
+                       freq = 0;
+       }
 
        if (!p2p->cfg->p2ps_prov_complete) {
                /* Don't emit anything */
@@ -771,7 +1028,8 @@ out:
                                             NULL, adv_id, session_id,
                                             0, 0, msg.persistent_ssid,
                                             msg.persistent_ssid_len,
-                                            0, 0, NULL, NULL, 0);
+                                            0, 0, NULL, NULL, 0, freq,
+                                            NULL, 0);
        } else if (msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED &&
                   p2p->p2ps_prov) {
                p2p->p2ps_prov->status = reject;
@@ -784,7 +1042,8 @@ out:
                                                     session_id, conncap, 0,
                                                     msg.persistent_ssid,
                                                     msg.persistent_ssid_len, 0,
-                                                    0, NULL, NULL, 0);
+                                                    0, NULL, NULL, 0, freq,
+                                                    NULL, 0);
                else
                        p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx,
                                                     *msg.status,
@@ -796,7 +1055,8 @@ out:
                                                     msg.persistent_ssid_len, 0,
                                                     0, NULL,
                                                     (const u8 *) &resp_fcap,
-                                                    sizeof(resp_fcap));
+                                                    sizeof(resp_fcap), freq,
+                                                    NULL, 0);
        } else if (msg.status && p2p->p2ps_prov) {
                p2p->p2ps_prov->status = P2P_SC_SUCCESS;
                p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg.status, sa,
@@ -807,7 +1067,7 @@ out:
                                             msg.persistent_ssid_len,
                                             0, 0, NULL,
                                             (const u8 *) &resp_fcap,
-                                            sizeof(resp_fcap));
+                                            sizeof(resp_fcap), freq, NULL, 0);
        } else if (msg.status) {
        } else if (auto_accept && reject == P2P_SC_SUCCESS) {
                p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
@@ -818,7 +1078,11 @@ out:
                                             msg.persistent_ssid_len,
                                             0, 0, NULL,
                                             (const u8 *) &resp_fcap,
-                                            sizeof(resp_fcap));
+                                            sizeof(resp_fcap), freq,
+                                            msg.group_id ?
+                                            msg.group_id + ETH_ALEN : NULL,
+                                            msg.group_id ?
+                                            msg.group_id_len - ETH_ALEN : 0);
        } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
                   (!msg.session_info || !msg.session_info_len)) {
                p2p->p2ps_prov->method = msg.wps_config_methods;
@@ -831,7 +1095,7 @@ out:
                                             msg.persistent_ssid_len,
                                             0, 1, NULL,
                                             (const u8 *) &resp_fcap,
-                                            sizeof(resp_fcap));
+                                            sizeof(resp_fcap), freq, NULL, 0);
        } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
                size_t buf_len = msg.session_info_len;
                char *buf = os_malloc(2 * buf_len + 1);
@@ -848,7 +1112,8 @@ out:
                                session_id, conncap, passwd_id,
                                msg.persistent_ssid, msg.persistent_ssid_len,
                                0, 1, buf,
-                               (const u8 *) &resp_fcap, sizeof(resp_fcap));
+                               (const u8 *) &resp_fcap, sizeof(resp_fcap),
+                               freq, NULL, 0);
 
                        os_free(buf);
                }
@@ -898,7 +1163,7 @@ out:
                                        msg.group_id, msg.group_id_len);
        }
 
-       if (dev && reject == P2P_SC_SUCCESS) {
+       if (reject == P2P_SC_SUCCESS) {
                switch (config_methods) {
                case WPS_CONFIG_DISPLAY:
                        dev->wps_prov_info = WPS_CONFIG_KEYPAD;
@@ -1084,6 +1349,9 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
                        " with no pending request", MAC2STR(sa));
                p2p_parse_free(&msg);
                return;
+       } else if (msg.wfd_subelems) {
+               wpabuf_free(dev->info.wfd_subelems);
+               dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
        }
 
        if (dev->dialog_token != msg.dialog_token) {
@@ -1148,17 +1416,71 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
                passwd_id = DEV_PW_P2PS_DEFAULT;
        }
 
-       if ((msg.conn_cap || msg.persistent_dev) &&
-           (status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) &&
+       if ((status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) &&
            p2p->p2ps_prov) {
+               dev->oper_freq = 0;
+
+               /*
+                * Save the reported channel list and operating frequency.
+                * Note that the specification mandates that the responder
+                * should include in the channel list only channels reported by
+                * the initiator, so this is only a sanity check, and if this
+                * fails the flow would continue, although it would probably
+                * fail. Same is true for the operating channel.
+                */
+               if (msg.channel_list && msg.channel_list_len &&
+                   p2p_peer_channels_check(p2p, &p2p->channels, dev,
+                                           msg.channel_list,
+                                           msg.channel_list_len) < 0)
+                       p2p_dbg(p2p, "P2PS PD Response - no common channels");
+
+               if (msg.operating_channel) {
+                       if (p2p_channels_includes(&p2p->channels,
+                                                 msg.operating_channel[3],
+                                                 msg.operating_channel[4]) &&
+                           p2p_channels_includes(&dev->channels,
+                                                 msg.operating_channel[3],
+                                                 msg.operating_channel[4])) {
+                               dev->oper_freq =
+                                       p2p_channel_to_freq(
+                                               msg.operating_channel[3],
+                                               msg.operating_channel[4]);
+                       } else {
+                               p2p_dbg(p2p,
+                                       "P2PS PD Response - invalid operating channel");
+                       }
+               }
+
                if (p2p->cfg->p2ps_prov_complete) {
+                       int freq = 0;
+
+                       if (conncap == P2PS_SETUP_GROUP_OWNER) {
+                               u8 tmp;
+
+                               /*
+                                * Re-select the operating channel as it is
+                                * possible that original channel is no longer
+                                * valid. This should not really fail.
+                                */
+                               if (p2p_go_select_channel(p2p, dev, &tmp) < 0)
+                                       p2p_dbg(p2p,
+                                               "P2PS PD channel selection failed");
+
+                               freq = p2p_channel_to_freq(p2p->op_reg_class,
+                                                          p2p->op_channel);
+                               if (freq < 0)
+                                       freq = 0;
+                       }
+
                        p2p->cfg->p2ps_prov_complete(
                                p2p->cfg->cb_ctx, status, sa, adv_mac,
                                p2p->p2ps_prov->session_mac,
                                group_mac, adv_id, p2p->p2ps_prov->session_id,
                                conncap, passwd_id, msg.persistent_ssid,
                                msg.persistent_ssid_len, 1, 0, NULL,
-                               msg.feature_cap, msg.feature_cap_len);
+                               msg.feature_cap, msg.feature_cap_len, freq,
+                               msg.group_id ? msg.group_id + ETH_ALEN : NULL,
+                               msg.group_id ? msg.group_id_len - ETH_ALEN : 0);
                }
                p2ps_prov_free(p2p);
        } else if (status != P2P_SC_SUCCESS &&
@@ -1169,7 +1491,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
                                p2p->cfg->cb_ctx, status, sa, adv_mac,
                                p2p->p2ps_prov->session_mac,
                                group_mac, adv_id, p2p->p2ps_prov->session_id,
-                               0, 0, NULL, 0, 1, 0, NULL, NULL, 0);
+                               0, 0, NULL, 0, 1, 0, NULL, NULL, 0, 0, NULL, 0);
                p2ps_prov_free(p2p);
        }
 
@@ -1318,6 +1640,10 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
                        "Building PD Request based on P2PS config method 0x%x status %d --> req_config_methods 0x%x",
                        p2p->p2ps_prov->method, p2p->p2ps_prov->status,
                        dev->req_config_methods);
+
+               if (p2p_prepare_channel(p2p, dev, p2p->p2ps_prov->force_freq,
+                                       p2p->p2ps_prov->pref_freq, 1) < 0)
+                       return -1;
        }
 
        req = p2p_build_prov_disc_req(p2p, dev, join);
index 1a2af04..a8bc5ba 100644 (file)
@@ -28,11 +28,11 @@ static int wfd_wsd_supported(struct wpabuf *wfd)
        pos = wpabuf_head(wfd);
        end = pos + wpabuf_len(wfd);
 
-       while (pos + 3 <= end) {
+       while (end - pos >= 3) {
                subelem = *pos++;
                len = WPA_GET_BE16(pos);
                pos += 2;
-               if (pos + len > end)
+               if (len > end - pos)
                        break;
 
                if (subelem == WFD_SUBELEM_DEVICE_INFO && len >= 6) {
@@ -288,6 +288,14 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
        query = p2p_pending_sd_req(p2p, dev);
        if (query == NULL)
                return -1;
+       if (p2p->state == P2P_SEARCH &&
+           os_memcmp(p2p->sd_query_no_ack, dev->info.p2p_device_addr,
+                     ETH_ALEN) == 0) {
+               p2p_dbg(p2p, "Do not start Service Discovery with " MACSTR
+                       " due to it being the first no-ACK peer in this search iteration",
+                       MAC2STR(dev->info.p2p_device_addr));
+               return -2;
+       }
 
        p2p_dbg(p2p, "Start Service Discovery with " MACSTR,
                MAC2STR(dev->info.p2p_device_addr));
@@ -355,11 +363,11 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
        pos++;
 
        slen = *pos++;
-       next = pos + slen;
-       if (next > end || slen < 2) {
+       if (slen > end - pos || slen < 2) {
                p2p_dbg(p2p, "Invalid IE in GAS Initial Request");
                return;
        }
+       next = pos + slen;
        pos++; /* skip QueryRespLenLimit and PAME-BI */
 
        if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
@@ -370,16 +378,16 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
 
        pos = next;
        /* Query Request */
-       if (pos + 2 > end)
+       if (end - pos < 2)
                return;
        slen = WPA_GET_LE16(pos);
        pos += 2;
-       if (pos + slen > end)
+       if (slen > end - pos)
                return;
        end = pos + slen;
 
        /* ANQP Query Request */
-       if (pos + 4 > end)
+       if (end - pos < 4)
                return;
        if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
                p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
@@ -389,7 +397,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
 
        slen = WPA_GET_LE16(pos);
        pos += 2;
-       if (pos + slen > end || slen < 3 + 1) {
+       if (slen > end - pos || slen < 3 + 1) {
                p2p_dbg(p2p, "Invalid ANQP Query Request length");
                return;
        }
@@ -401,7 +409,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
        }
        pos += 4;
 
-       if (pos + 2 > end)
+       if (end - pos < 2)
                return;
        update_indic = WPA_GET_LE16(pos);
        p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
@@ -417,9 +425,16 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
                     u8 dialog_token, const struct wpabuf *resp_tlvs)
 {
        struct wpabuf *resp;
+       size_t max_len;
+
+       /*
+        * In the 60 GHz, we have a smaller maximum frame length for management
+        * frames.
+        */
+       max_len = (freq > 56160) ? 928 : 1400;
 
        /* TODO: fix the length limit to match with the maximum frame length */
-       if (wpabuf_len(resp_tlvs) > 1400) {
+       if (wpabuf_len(resp_tlvs) > max_len) {
                p2p_dbg(p2p, "SD response long enough to require fragmentation");
                if (p2p->sd_resp) {
                        /*
@@ -512,11 +527,11 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
        pos++;
 
        slen = *pos++;
-       next = pos + slen;
-       if (next > end || slen < 2) {
+       if (slen > end - pos || slen < 2) {
                p2p_dbg(p2p, "Invalid IE in GAS Initial Response");
                return;
        }
+       next = pos + slen;
        pos++; /* skip QueryRespLenLimit and PAME-BI */
 
        if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
@@ -527,14 +542,14 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
 
        pos = next;
        /* Query Response */
-       if (pos + 2 > end) {
+       if (end - pos < 2) {
                p2p_dbg(p2p, "Too short Query Response");
                return;
        }
        slen = WPA_GET_LE16(pos);
        pos += 2;
        p2p_dbg(p2p, "Query Response Length: %d", slen);
-       if (pos + slen > end) {
+       if (slen > end - pos) {
                p2p_dbg(p2p, "Not enough Query Response data");
                return;
        }
@@ -552,7 +567,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
        }
 
        /* ANQP Query Response */
-       if (pos + 4 > end)
+       if (end - pos < 4)
                return;
        if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
                p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
@@ -562,7 +577,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
 
        slen = WPA_GET_LE16(pos);
        pos += 2;
-       if (pos + slen > end || slen < 3 + 1) {
+       if (slen > end - pos || slen < 3 + 1) {
                p2p_dbg(p2p, "Invalid ANQP Query Response length");
                return;
        }
@@ -574,7 +589,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
        }
        pos += 4;
 
-       if (pos + 2 > end)
+       if (end - pos < 2)
                return;
        update_indic = WPA_GET_LE16(pos);
        p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
@@ -606,7 +621,7 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
 {
        struct wpabuf *resp;
        u8 dialog_token;
-       size_t frag_len;
+       size_t frag_len, max_len;
        int more = 0;
 
        wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Request", data, len);
@@ -630,9 +645,14 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
                return;
        }
 
+       /*
+        * In the 60 GHz, we have a smaller maximum frame length for management
+        * frames.
+        */
+       max_len = (rx_freq > 56160) ? 928 : 1400;
        frag_len = wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos;
-       if (frag_len > 1400) {
-               frag_len = 1400;
+       if (frag_len > max_len) {
+               frag_len = max_len;
                more = 1;
        }
        resp = p2p_build_gas_comeback_resp(dialog_token, WLAN_STATUS_SUCCESS,
@@ -727,11 +747,11 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
        pos++;
 
        slen = *pos++;
-       next = pos + slen;
-       if (next > end || slen < 2) {
+       if (slen > end - pos || slen < 2) {
                p2p_dbg(p2p, "Invalid IE in GAS Comeback Response");
                return;
        }
+       next = pos + slen;
        pos++; /* skip QueryRespLenLimit and PAME-BI */
 
        if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
@@ -742,14 +762,14 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
 
        pos = next;
        /* Query Response */
-       if (pos + 2 > end) {
+       if (end - pos < 2) {
                p2p_dbg(p2p, "Too short Query Response");
                return;
        }
        slen = WPA_GET_LE16(pos);
        pos += 2;
        p2p_dbg(p2p, "Query Response Length: %d", slen);
-       if (pos + slen > end) {
+       if (slen > end - pos) {
                p2p_dbg(p2p, "Not enough Query Response data");
                return;
        }
@@ -768,7 +788,7 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
        }
 
        /* ANQP Query Response */
-       if (pos + 4 > end)
+       if (end - pos < 4)
                return;
        if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
                p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
@@ -783,7 +803,7 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
                p2p_dbg(p2p, "Invalid ANQP Query Response length");
                return;
        }
-       if (pos + 4 > end)
+       if (end - pos < 4)
                return;
 
        if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
@@ -793,7 +813,7 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
        }
        pos += 4;
 
-       if (pos + 2 > end)
+       if (end - pos < 2)
                return;
        p2p->sd_rx_update_indic = WPA_GET_LE16(pos);
        p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic);
index cf43c59..e294e64 100644 (file)
@@ -20,7 +20,7 @@
 #define STATE_MACHINE_DATA struct ieee802_1x_cp_sm
 #define STATE_MACHINE_DEBUG_PREFIX "CP"
 
-static u8 default_cs_id[] = CS_ID_GCM_AES_128;
+static u64 default_cs_id = CS_ID_GCM_AES_128;
 
 /* The variable defined in clause 12 in IEEE Std 802.1X-2010 */
 enum connect_type { PENDING, UNAUTHENTICATED, AUTHENTICATED, SECURE };
@@ -45,7 +45,7 @@ struct ieee802_1x_cp_sm {
        Boolean elected_self;
        u8 *authorization_data1;
        enum confidentiality_offset cipher_offset;
-       u8 *cipher_suite;
+       u64 cipher_suite;
        Boolean new_sak; /* clear by CP */
        struct ieee802_1x_mka_ki distributed_ki;
        u8 distributed_an;
@@ -71,7 +71,7 @@ struct ieee802_1x_cp_sm {
        Boolean replay_protect;
        u32 replay_window;
 
-       u8 *current_cipher_suite;
+       u64 current_cipher_suite;
        enum confidentiality_offset confidentiality_offset;
        Boolean controlled_port_enabled;
 
@@ -97,8 +97,7 @@ static void ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx,
 static int changed_cipher(struct ieee802_1x_cp_sm *sm)
 {
        return sm->confidentiality_offset != sm->cipher_offset ||
-               os_memcmp(sm->current_cipher_suite, sm->cipher_suite,
-                         CS_ID_LEN) != 0;
+               sm->current_cipher_suite != sm->cipher_suite;
 }
 
 
@@ -185,21 +184,17 @@ SM_STATE(CP, AUTHENTICATED)
 
 SM_STATE(CP, SECURED)
 {
-       struct ieee802_1x_cp_conf conf;
-
        SM_ENTRY(CP, SECURED);
 
        sm->chgd_server = FALSE;
 
-       ieee802_1x_kay_cp_conf(sm->kay, &conf);
-       sm->protect_frames = conf.protect;
-       sm->replay_protect = conf.replay_protect;
-       sm->validate_frames = conf.validate;
+       sm->protect_frames = sm->kay->macsec_protect;
+       sm->replay_protect = sm->kay->macsec_replay_protect;
+       sm->validate_frames = sm->kay->macsec_validate;
 
-       /* NOTE: now no other than default cipher suiter(AES-GCM-128) */
-       os_memcpy(sm->current_cipher_suite, sm->cipher_suite, CS_ID_LEN);
-       secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite,
-                                            CS_ID_LEN);
+       /* NOTE: now no other than default cipher suite (AES-GCM-128) */
+       sm->current_cipher_suite = sm->cipher_suite;
+       secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite);
 
        sm->confidentiality_offset = sm->cipher_offset;
 
@@ -428,9 +423,7 @@ SM_STEP(CP)
 /**
  * ieee802_1x_cp_sm_init -
  */
-struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(
-       struct ieee802_1x_kay *kay,
-       struct ieee802_1x_cp_conf *pcp_conf)
+struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay)
 {
        struct ieee802_1x_cp_sm *sm;
 
@@ -446,10 +439,10 @@ struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(
 
        sm->chgd_server = FALSE;
 
-       sm->protect_frames = pcp_conf->protect;
-       sm->validate_frames = pcp_conf->validate;
-       sm->replay_protect = pcp_conf->replay_protect;
-       sm->replay_window = pcp_conf->replay_window;
+       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;
 
@@ -460,17 +453,8 @@ struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(
        sm->orx = FALSE;
        sm->otx = FALSE;
 
-       sm->cipher_suite = os_zalloc(CS_ID_LEN);
-       sm->current_cipher_suite = os_zalloc(CS_ID_LEN);
-       if (!sm->cipher_suite || !sm->current_cipher_suite) {
-               wpa_printf(MSG_ERROR, "CP-%s: out of memory", __func__);
-               os_free(sm->cipher_suite);
-               os_free(sm->current_cipher_suite);
-               os_free(sm);
-               return NULL;
-       }
-       os_memcpy(sm->current_cipher_suite, default_cs_id, CS_ID_LEN);
-       os_memcpy(sm->cipher_suite, default_cs_id, CS_ID_LEN);
+       sm->current_cipher_suite = default_cs_id;
+       sm->cipher_suite = default_cs_id;
        sm->cipher_offset = CONFIDENTIALITY_OFFSET_0;
        sm->confidentiality_offset = sm->cipher_offset;
        sm->transmit_delay = MKA_LIFE_TIME;
@@ -530,8 +514,6 @@ void ieee802_1x_cp_sm_deinit(struct ieee802_1x_cp_sm *sm)
        eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL);
        os_free(sm->lki);
        os_free(sm->oki);
-       os_free(sm->cipher_suite);
-       os_free(sm->current_cipher_suite);
        os_free(sm->authorization_data);
        os_free(sm);
 }
@@ -618,10 +600,10 @@ void ieee802_1x_cp_set_authorizationdata(void *cp_ctx, u8 *pdata, int len)
 /**
  * ieee802_1x_cp_set_ciphersuite -
  */
-void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, void *pid)
+void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, u64 cs)
 {
        struct ieee802_1x_cp_sm *sm = cp_ctx;
-       os_memcpy(sm->cipher_suite, pid, CS_ID_LEN);
+       sm->cipher_suite = cs;
 }
 
 
index 773c930..695629e 100644 (file)
@@ -16,17 +16,7 @@ struct ieee802_1x_cp_sm;
 struct ieee802_1x_kay;
 struct ieee802_1x_mka_ki;
 
-struct ieee802_1x_cp_conf {
-       Boolean protect;
-       Boolean replay_protect;
-       enum validate_frames validate;
-       u32 replay_window;
-};
-
-
-struct ieee802_1x_cp_sm *
-ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay,
-                     struct ieee802_1x_cp_conf *pcp_conf);
+struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay);
 void ieee802_1x_cp_sm_deinit(struct ieee802_1x_cp_sm *sm);
 void ieee802_1x_cp_sm_step(void *cp_ctx);
 void ieee802_1x_cp_connect_pending(void *cp_ctx);
@@ -36,7 +26,7 @@ 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_authorizationdata(void *cp_ctx, u8 *pdata, int len);
-void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, void *pid);
+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,
index ef74430..a8e7efc 100644 (file)
@@ -29,6 +29,8 @@
 
 #define PENDING_PN_EXHAUSTION 0xC0000000
 
+#define MKA_ALIGN_LENGTH(len) (((len) + 0x3) & ~0x3)
+
 /* IEEE Std 802.1X-2010, Table 9-1 - MKA Algorithm Agility */
 #define MKA_ALGO_AGILITY_2009 { 0x00, 0x80, 0xC2, 0x01 }
 static u8 mka_algo_agility[4] = MKA_ALGO_AGILITY_2009;
@@ -37,12 +39,11 @@ static u8 mka_algo_agility[4] = MKA_ALGO_AGILITY_2009;
 static struct macsec_ciphersuite cipher_suite_tbl[] = {
        /* GCM-AES-128 */
        {
-               CS_ID_GCM_AES_128,
-               CS_NAME_GCM_AES_128,
-               MACSEC_CAP_INTEG_AND_CONF_0_30_50,
-               16,
-
-               0 /* index */
+               .id = CS_ID_GCM_AES_128,
+               .name = CS_NAME_GCM_AES_128,
+               .capable = MACSEC_CAP_INTEG_AND_CONF_0_30_50,
+               .sak_len = DEFAULT_SA_KEY_LEN,
+               .index = 0,
        },
 };
 #define CS_TABLE_SIZE (ARRAY_SIZE(cipher_suite_tbl))
@@ -50,16 +51,21 @@ static struct macsec_ciphersuite cipher_suite_tbl[] = {
 
 static struct mka_alg mka_alg_tbl[] = {
        {
-               MKA_ALGO_AGILITY_2009,
+               .parameter = MKA_ALGO_AGILITY_2009,
+
                /* 128-bit CAK, KEK, ICK, ICV */
-               16, 16, 16, 16,
-               ieee802_1x_cak_128bits_aes_cmac,
-               ieee802_1x_ckn_128bits_aes_cmac,
-               ieee802_1x_kek_128bits_aes_cmac,
-               ieee802_1x_ick_128bits_aes_cmac,
-               ieee802_1x_icv_128bits_aes_cmac,
-
-               1, /* index */
+               .cak_len = DEFAULT_ICV_LEN,
+               .kek_len = DEFAULT_ICV_LEN,
+               .ick_len = DEFAULT_ICV_LEN,
+               .icv_len = DEFAULT_ICV_LEN,
+
+               .cak_trfm = ieee802_1x_cak_128bits_aes_cmac,
+               .ckn_trfm = ieee802_1x_ckn_128bits_aes_cmac,
+               .kek_trfm = ieee802_1x_kek_128bits_aes_cmac,
+               .ick_trfm = ieee802_1x_ick_128bits_aes_cmac,
+               .icv_hash = ieee802_1x_icv_128bits_aes_cmac,
+
+               .index = 1,
        },
 };
 #define MKA_ALG_TABLE_SIZE (ARRAY_SIZE(mka_alg_tbl))
@@ -73,16 +79,6 @@ static int is_ki_equal(struct ieee802_1x_mka_ki *ki1,
 }
 
 
-struct mka_param_body_handler {
-       int (*body_tx)(struct ieee802_1x_mka_participant *participant,
-                      struct wpabuf *buf);
-       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);
-};
-
-
 static void set_mka_param_body_len(void *body, unsigned int len)
 {
        struct ieee802_1x_mka_hdr *hdr = body;
@@ -98,7 +94,7 @@ static unsigned int get_mka_param_body_len(const void *body)
 }
 
 
-static int get_mka_param_body_type(const void *body)
+static u8 get_mka_param_body_type(const void *body)
 {
        const struct ieee802_1x_mka_hdr *hdr = body;
        return hdr->type;
@@ -122,8 +118,8 @@ ieee802_1x_mka_dump_basic_body(struct ieee802_1x_mka_basic_body *body)
        wpa_printf(MSG_DEBUG, "\tPriority......: %d", body->priority);
        wpa_printf(MSG_DEBUG, "\tKeySvr........: %d", body->key_server);
        wpa_printf(MSG_DEBUG, "\tMACSecDesired.: %d", body->macsec_desired);
-       wpa_printf(MSG_DEBUG, "\tMACSecCapable.: %d", body->macsec_capbility);
-       wpa_printf(MSG_DEBUG, "\tBody Length...: %d", (int) body_len);
+       wpa_printf(MSG_DEBUG, "\tMACSecCapable.: %d", body->macsec_capability);
+       wpa_printf(MSG_DEBUG, "\tBody Length...: %zu", body_len);
        wpa_printf(MSG_DEBUG, "\tSCI MAC.......: " MACSTR,
                   MAC2STR(body->actor_sci.addr));
        wpa_printf(MSG_DEBUG, "\tSCI Port .....: %d",
@@ -148,7 +144,7 @@ ieee802_1x_mka_dump_peer_body(struct ieee802_1x_mka_peer_body *body)
        size_t body_len;
        size_t i;
        u8 *mi;
-       u32 mn;
+       be32 mn;
 
        if (body == NULL)
                return;
@@ -156,10 +152,10 @@ ieee802_1x_mka_dump_peer_body(struct ieee802_1x_mka_peer_body *body)
        body_len = get_mka_param_body_len(body);
        if (body->type == MKA_LIVE_PEER_LIST) {
                wpa_printf(MSG_DEBUG, "*** Live Peer List ***");
-               wpa_printf(MSG_DEBUG, "\tBody Length...: %d", (int) body_len);
+               wpa_printf(MSG_DEBUG, "\tBody Length...: %zu", body_len);
        } else if (body->type == MKA_POTENTIAL_PEER_LIST) {
                wpa_printf(MSG_DEBUG, "*** Potential Live Peer List ***");
-               wpa_printf(MSG_DEBUG, "\tBody Length...: %d", (int) body_len);
+               wpa_printf(MSG_DEBUG, "\tBody Length...: %zu", body_len);
        }
 
        for (i = 0; i < body_len; i += MI_LEN + sizeof(mn)) {
@@ -187,7 +183,7 @@ ieee802_1x_mka_dump_dist_sak_body(struct ieee802_1x_mka_dist_sak_body *body)
        wpa_printf(MSG_INFO, "\tDistributed AN........: %d", body->dan);
        wpa_printf(MSG_INFO, "\tConfidentiality Offset: %d",
                   body->confid_offset);
-       wpa_printf(MSG_INFO, "\tBody Length...........: %d", (int) body_len);
+       wpa_printf(MSG_INFO, "\tBody Length...........: %zu", body_len);
        if (!body_len)
                return;
 
@@ -280,7 +276,7 @@ ieee802_1x_kay_get_principal_participant(struct ieee802_1x_kay *kay)
                        return participant;
        }
 
-       wpa_printf(MSG_DEBUG, "KaY: principal participant is not founded");
+       wpa_printf(MSG_DEBUG, "KaY: principal participant is not found");
        return NULL;
 }
 
@@ -300,36 +296,46 @@ static struct ieee802_1x_kay_peer * get_peer_mi(struct dl_list *peers,
 
 
 /**
- * ieee802_1x_kay_is_in_potential_peer
+ * ieee802_1x_kay_get_potential_peer
  */
-static Boolean
-ieee802_1x_kay_is_in_potential_peer(
+static struct ieee802_1x_kay_peer *
+ieee802_1x_kay_get_potential_peer(
        struct ieee802_1x_mka_participant *participant, const u8 *mi)
 {
-       return get_peer_mi(&participant->potential_peers, mi) != NULL;
+       return get_peer_mi(&participant->potential_peers, mi);
 }
 
 
 /**
- * ieee802_1x_kay_is_in_live_peer
+ * ieee802_1x_kay_get_live_peer
+ */
+static struct ieee802_1x_kay_peer *
+ieee802_1x_kay_get_live_peer(struct ieee802_1x_mka_participant *participant,
+                            const u8 *mi)
+{
+       return get_peer_mi(&participant->live_peers, mi);
+}
+
+
+/**
+ * ieee802_1x_kay_is_in_potential_peer
  */
 static Boolean
-ieee802_1x_kay_is_in_live_peer(
+ieee802_1x_kay_is_in_potential_peer(
        struct ieee802_1x_mka_participant *participant, const u8 *mi)
 {
-       return get_peer_mi(&participant->live_peers, mi) != NULL;
+       return ieee802_1x_kay_get_potential_peer(participant, mi) != NULL;
 }
 
 
 /**
- * ieee802_1x_kay_is_in_peer
+ * ieee802_1x_kay_is_in_live_peer
  */
 static Boolean
-ieee802_1x_kay_is_in_peer(struct ieee802_1x_mka_participant *participant,
-                         const u8 *mi)
+ieee802_1x_kay_is_in_live_peer(
+       struct ieee802_1x_mka_participant *participant, const u8 *mi)
 {
-       return ieee802_1x_kay_is_in_live_peer(participant, mi) ||
-               ieee802_1x_kay_is_in_potential_peer(participant, mi);
+       return ieee802_1x_kay_get_live_peer(participant, mi) != NULL;
 }
 
 
@@ -342,22 +348,11 @@ ieee802_1x_kay_get_peer(struct ieee802_1x_mka_participant *participant,
 {
        struct ieee802_1x_kay_peer *peer;
 
-       peer = get_peer_mi(&participant->live_peers, mi);
+       peer = ieee802_1x_kay_get_live_peer(participant, mi);
        if (peer)
                return peer;
 
-       return get_peer_mi(&participant->potential_peers, mi);
-}
-
-
-/**
- * ieee802_1x_kay_get_live_peer
- */
-static struct ieee802_1x_kay_peer *
-ieee802_1x_kay_get_live_peer(struct ieee802_1x_mka_participant *participant,
-                            const u8 *mi)
-{
-       return get_peer_mi(&participant->live_peers, mi);
+       return ieee802_1x_kay_get_potential_peer(participant, mi);
 }
 
 
@@ -366,18 +361,28 @@ ieee802_1x_kay_get_live_peer(struct ieee802_1x_mka_participant *participant,
  */
 static struct macsec_ciphersuite *
 ieee802_1x_kay_get_cipher_suite(struct ieee802_1x_mka_participant *participant,
-                               u8 *cs_id)
+                               const u8 *cs_id)
 {
        unsigned int i;
+       u64 cs;
+       be64 _cs;
+
+       os_memcpy(&_cs, cs_id, CS_ID_LEN);
+       cs = be_to_host64(_cs);
 
        for (i = 0; i < CS_TABLE_SIZE; i++) {
-               if (os_memcmp(cipher_suite_tbl[i].id, cs_id, CS_ID_LEN) == 0)
-                       break;
+               if (cipher_suite_tbl[i].id == cs)
+                       return &cipher_suite_tbl[i];
        }
-       if (i >= CS_TABLE_SIZE)
-               return NULL;
 
-       return &cipher_suite_tbl[i];
+       return NULL;
+}
+
+
+static Boolean 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;
 }
 
 
@@ -392,13 +397,13 @@ ieee802_1x_kay_get_peer_sci(struct ieee802_1x_mka_participant *participant,
 
        dl_list_for_each(peer, &participant->live_peers,
                         struct ieee802_1x_kay_peer, list) {
-               if (os_memcmp(&peer->sci, sci, sizeof(peer->sci)) == 0)
+               if (sci_equal(&peer->sci, sci))
                        return peer;
        }
 
        dl_list_for_each(peer, &participant->potential_peers,
                         struct ieee802_1x_kay_peer, list) {
-               if (os_memcmp(&peer->sci, sci, sizeof(peer->sci)) == 0)
+               if (sci_equal(&peer->sci, sci))
                        return peer;
        }
 
@@ -435,8 +440,8 @@ ieee802_1x_kay_init_receive_sa(struct receive_sc *psc, u8 an, u32 lowest_pn,
 
        dl_list_add(&psc->sa_list, &psa->list);
        wpa_printf(MSG_DEBUG,
-                  "KaY: Create receive SA(AN: %d lowest_pn: %u of SC(channel: %d)",
-                  (int) an, lowest_pn, psc->channel);
+                  "KaY: Create receive SA(AN: %hhu lowest_pn: %u of SC(channel: %d)",
+                  an, lowest_pn, psc->channel);
 
        return psa;
 }
@@ -449,8 +454,8 @@ static void ieee802_1x_kay_deinit_receive_sa(struct receive_sa *psa)
 {
        psa->pkey = NULL;
        wpa_printf(MSG_DEBUG,
-                  "KaY: Delete receive SA(an: %d) of SC(channel: %d)",
-                  psa->an, psa->sc->channel);
+                  "KaY: Delete receive SA(an: %hhu) of SC",
+                  psa->an);
        dl_list_del(&psa->list);
        os_free(psa);
 }
@@ -509,19 +514,22 @@ ieee802_1x_kay_deinit_receive_sc(
 }
 
 
-/**
- * ieee802_1x_kay_create_live_peer
- */
+static void ieee802_1x_kay_dump_peer(struct ieee802_1x_kay_peer *peer)
+{
+       wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi, sizeof(peer->mi));
+       wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn);
+       wpa_hexdump(MSG_DEBUG, "\tSCI Addr: ", peer->sci.addr, ETH_ALEN);
+       wpa_printf(MSG_DEBUG, "\tPort: %d", peer->sci.port);
+}
+
+
 static struct ieee802_1x_kay_peer *
-ieee802_1x_kay_create_live_peer(struct ieee802_1x_mka_participant *participant,
-                               u8 *mi, u32 mn)
+ieee802_1x_kay_create_peer(const u8 *mi, u32 mn)
 {
        struct ieee802_1x_kay_peer *peer;
-       struct receive_sc *rxsc;
-       u32 sc_ch = 0;
 
        peer = os_zalloc(sizeof(*peer));
-       if (peer == NULL) {
+       if (!peer) {
                wpa_printf(MSG_ERROR, "KaY-%s: out of memory", __func__);
                return NULL;
        }
@@ -530,24 +538,43 @@ ieee802_1x_kay_create_live_peer(struct ieee802_1x_mka_participant *participant,
        peer->mn = mn;
        peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
        peer->sak_used = FALSE;
+
+       return peer;
+}
+
+
+/**
+ * ieee802_1x_kay_create_live_peer
+ */
+static struct ieee802_1x_kay_peer *
+ieee802_1x_kay_create_live_peer(struct ieee802_1x_mka_participant *participant,
+                               const u8 *mi, u32 mn)
+{
+       struct ieee802_1x_kay_peer *peer;
+       struct receive_sc *rxsc;
+       u32 sc_ch = 0;
+
+       peer = ieee802_1x_kay_create_peer(mi, mn);
+       if (!peer)
+               return NULL;
+
        os_memcpy(&peer->sci, &participant->current_peer_sci,
                  sizeof(peer->sci));
-       dl_list_add(&participant->live_peers, &peer->list);
 
        secy_get_available_receive_sc(participant->kay, &sc_ch);
 
        rxsc = ieee802_1x_kay_init_receive_sc(&peer->sci, sc_ch);
-       if (!rxsc)
+       if (!rxsc) {
+               os_free(peer);
                return NULL;
+       }
 
+       dl_list_add(&participant->live_peers, &peer->list);
        dl_list_add(&participant->rxsc_list, &rxsc->list);
        secy_create_receive_sc(participant->kay, rxsc);
 
        wpa_printf(MSG_DEBUG, "KaY: Live peer created");
-       wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi, sizeof(peer->mi));
-       wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn);
-       wpa_hexdump(MSG_DEBUG, "\tSCI Addr: ", peer->sci.addr, ETH_ALEN);
-       wpa_printf(MSG_DEBUG, "\tPort: %d", peer->sci.port);
+       ieee802_1x_kay_dump_peer(peer);
 
        return peer;
 }
@@ -562,24 +589,14 @@ ieee802_1x_kay_create_potential_peer(
 {
        struct ieee802_1x_kay_peer *peer;
 
-       peer = os_zalloc(sizeof(*peer));
-       if (peer == NULL) {
-               wpa_printf(MSG_ERROR, "KaY-%s: out of memory", __func__);
+       peer = ieee802_1x_kay_create_peer(mi, mn);
+       if (!peer)
                return NULL;
-       }
-
-       os_memcpy(peer->mi, mi, MI_LEN);
-       peer->mn = mn;
-       peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
-       peer->sak_used = FALSE;
 
        dl_list_add(&participant->potential_peers, &peer->list);
 
        wpa_printf(MSG_DEBUG, "KaY: potential peer created");
-       wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi, sizeof(peer->mi));
-       wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn);
-       wpa_hexdump(MSG_DEBUG, "\tSCI Addr: ", peer->sci.addr, ETH_ALEN);
-       wpa_printf(MSG_DEBUG, "\tPort: %d", peer->sci.port);
+       ieee802_1x_kay_dump_peer(peer);
 
        return peer;
 }
@@ -596,11 +613,12 @@ ieee802_1x_kay_move_live_peer(struct ieee802_1x_mka_participant *participant,
        struct receive_sc *rxsc;
        u32 sc_ch = 0;
 
-       dl_list_for_each(peer, &participant->potential_peers,
-                        struct ieee802_1x_kay_peer, list) {
-               if (os_memcmp(peer->mi, mi, MI_LEN) == 0)
-                       break;
-       }
+       peer = ieee802_1x_kay_get_potential_peer(participant, mi);
+
+       rxsc = ieee802_1x_kay_init_receive_sc(&participant->current_peer_sci,
+                                             sc_ch);
+       if (!rxsc)
+               return NULL;
 
        os_memcpy(&peer->sci, &participant->current_peer_sci,
                  sizeof(peer->sci));
@@ -608,20 +626,13 @@ ieee802_1x_kay_move_live_peer(struct ieee802_1x_mka_participant *participant,
        peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
 
        wpa_printf(MSG_DEBUG, "KaY: move potential peer to live peer");
-       wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi, sizeof(peer->mi));
-       wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn);
-       wpa_hexdump(MSG_DEBUG, "\tSCI Addr: ", peer->sci.addr, ETH_ALEN);
-       wpa_printf(MSG_DEBUG, "\tPort: %d", peer->sci.port);
+       ieee802_1x_kay_dump_peer(peer);
 
        dl_list_del(&peer->list);
        dl_list_add_tail(&participant->live_peers, &peer->list);
 
        secy_get_available_receive_sc(participant->kay, &sc_ch);
 
-       rxsc = ieee802_1x_kay_init_receive_sc(&peer->sci, sc_ch);
-       if (!rxsc)
-               return NULL;
-
        dl_list_add(&participant->rxsc_list, &rxsc->list);
        secy_create_receive_sc(participant->kay, rxsc);
 
@@ -651,7 +662,7 @@ ieee802_1x_mka_basic_body_length(struct ieee802_1x_mka_participant *participant)
 
        length = sizeof(struct ieee802_1x_mka_basic_body);
        length += participant->ckn.len;
-       return (length + 0x3) & ~0x3;
+       return MKA_ALIGN_LENGTH(length);
 }
 
 
@@ -677,17 +688,17 @@ ieee802_1x_mka_encode_basic_body(
                body->key_server = participant->can_be_key_server;
 
        body->macsec_desired = kay->macsec_desired;
-       body->macsec_capbility = kay->macsec_capable;
+       body->macsec_capability = kay->macsec_capable;
        set_mka_param_body_len(body, length - MKA_HDR_LEN);
 
        os_memcpy(body->actor_sci.addr, kay->actor_sci.addr,
                  sizeof(kay->actor_sci.addr));
-       body->actor_sci.port = host_to_be16(kay->actor_sci.port);
+       body->actor_sci.port = kay->actor_sci.port;
 
        os_memcpy(body->actor_mi, participant->mi, sizeof(body->actor_mi));
        participant->mn = participant->mn + 1;
        body->actor_mn = host_to_be32(participant->mn);
-       os_memcpy(body->algo_agility, participant->kay->algo_agility,
+       os_memcpy(body->algo_agility, kay->algo_agility,
                  sizeof(body->algo_agility));
 
        os_memcpy(body->ckn, participant->ckn.name, participant->ckn.len);
@@ -698,6 +709,17 @@ ieee802_1x_mka_encode_basic_body(
 }
 
 
+static Boolean
+reset_participant_mi(struct ieee802_1x_mka_participant *participant)
+{
+       if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
+               return FALSE;
+       participant->mn = 0;
+
+       return TRUE;
+}
+
+
 /**
  * ieee802_1x_mka_decode_basic_body -
  */
@@ -729,16 +751,15 @@ ieee802_1x_mka_decode_basic_body(struct ieee802_1x_kay *kay, const u8 *mka_msg,
 
        /* If the peer's MI is my MI, I will choose new MI */
        if (os_memcmp(body->actor_mi, participant->mi, MI_LEN) == 0) {
-               if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
+               if (!reset_participant_mi(participant))
                        return NULL;
-               participant->mn = 0;
        }
 
        os_memcpy(participant->current_peer_id.mi, body->actor_mi, MI_LEN);
-       participant->current_peer_id.mn =  be_to_host32(body->actor_mn);
+       participant->current_peer_id.mn = body->actor_mn;
        os_memcpy(participant->current_peer_sci.addr, body->actor_sci.addr,
                  sizeof(participant->current_peer_sci.addr));
-       participant->current_peer_sci.port = be_to_host16(body->actor_sci.port);
+       participant->current_peer_sci.port = body->actor_sci.port;
 
        /* handler peer */
        peer = ieee802_1x_kay_get_peer(participant, body->actor_mi);
@@ -763,14 +784,14 @@ ieee802_1x_mka_decode_basic_body(struct ieee802_1x_kay *kay, const u8 *mka_msg,
                        return NULL;
 
                peer->macsec_desired = body->macsec_desired;
-               peer->macsec_capbility = body->macsec_capbility;
+               peer->macsec_capability = body->macsec_capability;
                peer->is_key_server = (Boolean) 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->expire = time(NULL) + MKA_LIFE_TIME / 1000;
                peer->macsec_desired = body->macsec_desired;
-               peer->macsec_capbility = body->macsec_capbility;
+               peer->macsec_capability = body->macsec_capability;
                peer->is_key_server = (Boolean) body->key_server;
                peer->key_server_priority = body->priority;
        } else {
@@ -807,7 +828,7 @@ ieee802_1x_mka_get_live_peer_length(
                         struct ieee802_1x_kay_peer, list)
                len += sizeof(struct ieee802_1x_mka_peer_id);
 
-       return (len + 0x3) & ~0x3;
+       return MKA_ALIGN_LENGTH(len);
 }
 
 
@@ -836,7 +857,6 @@ ieee802_1x_mka_encode_live_peer_body(
                                       sizeof(struct ieee802_1x_mka_peer_id));
                os_memcpy(body_peer->mi, peer->mi, MI_LEN);
                body_peer->mn = host_to_be32(peer->mn);
-               body_peer++;
        }
 
        ieee802_1x_mka_dump_peer_body(body);
@@ -868,7 +888,7 @@ ieee802_1x_mka_get_potential_peer_length(
                         struct ieee802_1x_kay_peer, list)
                len += sizeof(struct ieee802_1x_mka_peer_id);
 
-       return (len + 0x3) & ~0x3;
+       return MKA_ALIGN_LENGTH(len);
 }
 
 
@@ -897,7 +917,6 @@ ieee802_1x_mka_encode_potential_peer_body(
                                       sizeof(struct ieee802_1x_mka_peer_id));
                os_memcpy(body_peer->mi, peer->mi, MI_LEN);
                body_peer->mn = host_to_be32(peer->mn);
-               body_peer++;
        }
 
        ieee802_1x_mka_dump_peer_body(body);
@@ -912,62 +931,54 @@ static Boolean
 ieee802_1x_mka_i_in_peerlist(struct ieee802_1x_mka_participant *participant,
                             const u8 *mka_msg, size_t msg_len)
 {
-       Boolean included = FALSE;
        struct ieee802_1x_mka_hdr *hdr;
        size_t body_len;
        size_t left_len;
-       int body_type;
-       u32 peer_mn;
-       const u8 *peer_mi;
+       u8 body_type;
        const u8 *pos;
        size_t i;
 
-       pos = mka_msg;
-       left_len = msg_len;
-       while (left_len > (MKA_HDR_LEN + DEFAULT_ICV_LEN)) {
+       for (pos = mka_msg, left_len = msg_len;
+            left_len > MKA_HDR_LEN + DEFAULT_ICV_LEN;
+            left_len -= body_len + MKA_HDR_LEN,
+                    pos += body_len + MKA_HDR_LEN) {
                hdr = (struct ieee802_1x_mka_hdr *) pos;
                body_len = get_mka_param_body_len(hdr);
                body_type = get_mka_param_body_type(hdr);
 
                if (body_type != MKA_LIVE_PEER_LIST &&
                    body_type != MKA_POTENTIAL_PEER_LIST)
-                       goto SKIP_PEER;
+                       continue;
 
                ieee802_1x_mka_dump_peer_body(
                        (struct ieee802_1x_mka_peer_body *)pos);
 
                if (left_len < (MKA_HDR_LEN + body_len + DEFAULT_ICV_LEN)) {
                        wpa_printf(MSG_ERROR,
-                                  "KaY: MKA Peer Packet Body Length (%d bytes) is less than the Parameter Set Header Length (%d bytes) + the Parameter Set Body Length (%d bytes) + %d bytes of ICV",
-                                  (int) left_len, (int) MKA_HDR_LEN,
-                                  (int) body_len, DEFAULT_ICV_LEN);
-                       goto SKIP_PEER;
+                                  "KaY: MKA Peer Packet Body Length (%zu bytes) is less than the Parameter Set Header Length (%zu bytes) + the Parameter Set Body Length (%zu bytes) + %d bytes of ICV",
+                                  left_len, MKA_HDR_LEN,
+                                  body_len, DEFAULT_ICV_LEN);
+                       continue;
                }
 
                if ((body_len % 16) != 0) {
                        wpa_printf(MSG_ERROR,
-                                  "KaY: MKA Peer Packet Body Length (%d bytes) should multiple of 16 octets",
-                                  (int) body_len);
-                       goto SKIP_PEER;
-               }
-
-               for (i = 0; i < body_len; i += MI_LEN + sizeof(peer_mn)) {
-                       peer_mi = MKA_HDR_LEN + pos + i;
-                       os_memcpy(&peer_mn, peer_mi + MI_LEN, sizeof(peer_mn));
-                       peer_mn = be_to_host32(peer_mn);
-                       if (os_memcmp(peer_mi, participant->mi, MI_LEN) == 0 &&
-                           peer_mn == participant->mn) {
-                               included = TRUE;
-                               break;
-                       }
+                                  "KaY: MKA Peer Packet Body Length (%zu bytes) should be a multiple of 16 octets",
+                                  body_len);
+                       continue;
                }
 
-               if (included)
-                       return TRUE;
+               for (i = 0; i < body_len;
+                    i += sizeof(struct ieee802_1x_mka_peer_id)) {
+                       const struct ieee802_1x_mka_peer_id *peer_mi;
 
-SKIP_PEER:
-               left_len -= body_len + MKA_HDR_LEN;
-               pos += body_len + MKA_HDR_LEN;
+                       peer_mi = (const struct ieee802_1x_mka_peer_id *)
+                               (pos + MKA_HDR_LEN + i);
+                       if (os_memcmp(peer_mi->mi, participant->mi,
+                                     MI_LEN) == 0 &&
+                           be_to_host32(peer_mi->mn) == participant->mn)
+                               return TRUE;
+               }
        }
 
        return FALSE;
@@ -984,8 +995,6 @@ static int ieee802_1x_mka_decode_live_peer_body(
        const struct ieee802_1x_mka_hdr *hdr;
        struct ieee802_1x_kay_peer *peer;
        size_t body_len;
-       u32 peer_mn;
-       const u8 *peer_mi;
        size_t i;
        Boolean is_included;
 
@@ -994,36 +1003,40 @@ static int ieee802_1x_mka_decode_live_peer_body(
 
        hdr = (const struct ieee802_1x_mka_hdr *) peer_msg;
        body_len = get_mka_param_body_len(hdr);
+       if (body_len % 16 != 0) {
+               wpa_printf(MSG_ERROR,
+                          "KaY: MKA Peer Packet Body Length (%zu bytes) should be a multiple of 16 octets",
+                          body_len);
+               return -1;
+       }
+
+       for (i = 0; i < body_len; i += sizeof(struct ieee802_1x_mka_peer_id)) {
+               const struct ieee802_1x_mka_peer_id *peer_mi;
+               u32 peer_mn;
 
-       for (i = 0; i < body_len; i += MI_LEN + sizeof(peer_mn)) {
-               peer_mi = MKA_HDR_LEN + peer_msg + i;
-               os_memcpy(&peer_mn, peer_mi + MI_LEN, sizeof(peer_mn));
-               peer_mn = be_to_host32(peer_mn);
+               peer_mi = (const struct ieee802_1x_mka_peer_id *)
+                       (peer_msg + MKA_HDR_LEN + i);
+               peer_mn = be_to_host32(peer_mi->mn);
 
                /* it is myself */
                if (os_memcmp(peer_mi, participant->mi, MI_LEN) == 0) {
                        /* My message id is used by other participant */
-                       if (peer_mn > participant->mn) {
-                               if (os_get_random(participant->mi,
-                                                 sizeof(participant->mi)) < 0)
-                                       wpa_printf(MSG_DEBUG,
-                                                  "KaY: Could not update mi");
-                               participant->mn = 0;
-                       }
+                       if (peer_mn > participant->mn &&
+                           !reset_participant_mi(participant))
+                               wpa_printf(MSG_DEBUG, "KaY: Could not update mi");
                        continue;
                }
+
                if (!is_included)
                        continue;
 
-               peer = ieee802_1x_kay_get_peer(participant, peer_mi);
-               if (NULL != peer) {
+               peer = ieee802_1x_kay_get_peer(participant, peer_mi->mi);
+               if (peer) {
                        peer->mn = peer_mn;
                        peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
-               } else {
-                       if (!ieee802_1x_kay_create_potential_peer(
-                               participant, peer_mi, peer_mn)) {
-                               return -1;
-                       }
+               } else if (!ieee802_1x_kay_create_potential_peer(
+                               participant, peer_mi->mi, peer_mn)) {
+                       return -1;
                }
        }
 
@@ -1039,30 +1052,33 @@ ieee802_1x_mka_decode_potential_peer_body(
        struct ieee802_1x_mka_participant *participant,
        const u8 *peer_msg, size_t msg_len)
 {
-       struct ieee802_1x_mka_hdr *hdr;
+       const struct ieee802_1x_mka_hdr *hdr;
        size_t body_len;
-       u32 peer_mn;
-       const u8 *peer_mi;
        size_t i;
 
-       hdr = (struct ieee802_1x_mka_hdr *) peer_msg;
+       hdr = (const struct ieee802_1x_mka_hdr *) peer_msg;
        body_len = get_mka_param_body_len(hdr);
+       if (body_len % 16 != 0) {
+               wpa_printf(MSG_ERROR,
+                          "KaY: MKA Peer Packet Body Length (%zu bytes) should be a multiple of 16 octets",
+                          body_len);
+               return -1;
+       }
 
-       for (i = 0; i < body_len; i += MI_LEN + sizeof(peer_mn)) {
-               peer_mi = MKA_HDR_LEN + peer_msg + i;
-               os_memcpy(&peer_mn, peer_mi + MI_LEN, sizeof(peer_mn));
-               peer_mn = be_to_host32(peer_mn);
+       for (i = 0; i < body_len; i += sizeof(struct ieee802_1x_mka_peer_id)) {
+               const struct ieee802_1x_mka_peer_id *peer_mi;
+               u32 peer_mn;
+
+               peer_mi = (struct ieee802_1x_mka_peer_id *)
+                       (peer_msg + MKA_HDR_LEN + i);
+               peer_mn = be_to_host32(peer_mi->mn);
 
                /* it is myself */
                if (os_memcmp(peer_mi, participant->mi, MI_LEN) == 0) {
                        /* My message id is used by other participant */
-                       if (peer_mn > participant->mn) {
-                               if (os_get_random(participant->mi,
-                                                 sizeof(participant->mi)) < 0)
-                                       wpa_printf(MSG_DEBUG,
-                                                  "KaY: Could not update mi");
-                               participant->mn = 0;
-                       }
+                       if (peer_mn > participant->mn &&
+                           !reset_participant_mi(participant))
+                               wpa_printf(MSG_DEBUG, "KaY: Could not update mi");
                        continue;
                }
        }
@@ -1078,10 +1094,7 @@ static Boolean
 ieee802_1x_mka_sak_use_body_present(
        struct ieee802_1x_mka_participant *participant)
 {
-       if (participant->to_use_sak)
-               return TRUE;
-       else
-               return FALSE;
+       return participant->to_use_sak;
 }
 
 
@@ -1096,12 +1109,8 @@ ieee802_1x_mka_get_sak_use_length(
 
        if (participant->kay->macsec_desired && participant->advised_desired)
                length = sizeof(struct ieee802_1x_mka_sak_use_body);
-       else
-               length = MKA_HDR_LEN;
 
-       length = (length + 0x3) & ~0x3;
-
-       return length;
+       return MKA_ALIGN_LENGTH(length);
 }
 
 
@@ -1146,11 +1155,12 @@ ieee802_1x_mka_encode_sak_use_body(
        struct wpabuf *buf)
 {
        struct ieee802_1x_mka_sak_use_body *body;
+       struct ieee802_1x_kay *kay = participant->kay;
        unsigned int length;
        u32 pn = 1;
 
        length = ieee802_1x_mka_get_sak_use_length(participant);
-       body = wpabuf_put(buf, sizeof(struct ieee802_1x_mka_sak_use_body));
+       body = wpabuf_put(buf, length);
 
        body->type = MKA_SAK_USE;
        set_mka_param_body_len(body, length - MKA_HDR_LEN);
@@ -1166,9 +1176,9 @@ ieee802_1x_mka_encode_sak_use_body(
        }
 
        /* data protect, lowest accept packet number */
-       body->delay_protect = participant->kay->macsec_replay_protect;
+       body->delay_protect = kay->macsec_replay_protect;
        pn = ieee802_1x_mka_get_lpn(participant, &participant->lki);
-       if (pn > participant->kay->pn_exhaustion) {
+       if (pn > kay->pn_exhaustion) {
                wpa_printf(MSG_WARNING, "KaY: My LPN exhaustion");
                if (participant->is_key_server)
                        participant->new_sak = TRUE;
@@ -1179,20 +1189,12 @@ ieee802_1x_mka_encode_sak_use_body(
        body->olpn = host_to_be32(pn);
 
        /* plain tx, plain rx */
-       if (participant->kay->macsec_protect)
-               body->ptx = FALSE;
-       else
-               body->ptx = TRUE;
-
-       if (participant->kay->macsec_validate == Strict)
-               body->prx = FALSE;
-       else
-               body->prx = TRUE;
+       body->ptx = !kay->macsec_protect;
+       body->prx = kay->macsec_validate != Strict;
 
        /* latest key: rx, tx, key server member identifier key number */
        body->lan = participant->lan;
-       os_memcpy(body->lsrv_mi, participant->lki.mi,
-                 sizeof(body->lsrv_mi));
+       os_memcpy(body->lsrv_mi, participant->lki.mi, sizeof(body->lsrv_mi));
        body->lkn = host_to_be32(participant->lki.kn);
        body->lrx = participant->lrx;
        body->ltx = participant->ltx;
@@ -1213,16 +1215,11 @@ ieee802_1x_mka_encode_sak_use_body(
 
        /* set CP's variable */
        if (body->ltx) {
-               if (!participant->kay->tx_enable)
-                       participant->kay->tx_enable = TRUE;
-
-               if (!participant->kay->port_enable)
-                       participant->kay->port_enable = TRUE;
-       }
-       if (body->lrx) {
-               if (!participant->kay->rx_enable)
-                       participant->kay->rx_enable = TRUE;
+               kay->tx_enable = TRUE;
+               kay->port_enable = TRUE;
        }
+       if (body->lrx)
+               kay->rx_enable = TRUE;
 
        ieee802_1x_mka_dump_sak_use_body(body);
        return 0;
@@ -1246,7 +1243,8 @@ ieee802_1x_mka_decode_sak_use_body(
        struct ieee802_1x_mka_ki ki;
        u32 lpn;
        Boolean all_receiving;
-       Boolean founded;
+       Boolean found;
+       struct ieee802_1x_kay *kay = participant->kay;
 
        if (!participant->principal) {
                wpa_printf(MSG_WARNING, "KaY: Participant is not principal");
@@ -1266,8 +1264,8 @@ ieee802_1x_mka_decode_sak_use_body(
 
        if ((body_len != 0) && (body_len < 40)) {
                wpa_printf(MSG_ERROR,
-                          "KaY: MKA Use SAK Packet Body Length (%d bytes) should be 0, 40, or more octets",
-                          (int) body_len);
+                          "KaY: MKA Use SAK Packet Body Length (%zu bytes) should be 0, 40, or more octets",
+                          body_len);
                return -1;
        }
 
@@ -1288,30 +1286,29 @@ ieee802_1x_mka_decode_sak_use_body(
 
        /* check latest key is valid */
        if (body->ltx || body->lrx) {
-               founded = FALSE;
+               found = FALSE;
                os_memcpy(ki.mi, body->lsrv_mi, sizeof(ki.mi));
-               ki.kn = ntohl(body->lkn);
+               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)) {
-                               founded = TRUE;
+                               found = TRUE;
                                break;
                        }
                }
-               if (!founded) {
+               if (!found) {
                        wpa_printf(MSG_WARNING, "KaY: Latest key is invalid");
                        return -1;
                }
                if (os_memcmp(participant->lki.mi, body->lsrv_mi,
                              sizeof(participant->lki.mi)) == 0 &&
-                   ntohl(body->lkn) == participant->lki.kn &&
+                   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(
-                               participant->kay->cp, TRUE);
-                       ieee802_1x_cp_sm_step(participant->kay->cp);
+                       ieee802_1x_cp_set_servertransmitting(kay->cp, TRUE);
+                       ieee802_1x_cp_sm_step(kay->cp);
                }
        }
 
@@ -1319,7 +1316,7 @@ ieee802_1x_mka_decode_sak_use_body(
        if (body->otx || body->orx) {
                if (os_memcmp(participant->oki.mi, body->osrv_mi,
                              sizeof(participant->oki.mi)) != 0 ||
-                   ntohl(body->okn) != participant->oki.kn ||
+                   be_to_host32(body->okn) != participant->oki.kn ||
                    body->oan != participant->oan) {
                        wpa_printf(MSG_WARNING, "KaY: Old key is invalid");
                        return -1;
@@ -1327,7 +1324,8 @@ ieee802_1x_mka_decode_sak_use_body(
        }
 
        /* TODO: how to set the MACsec hardware when delay_protect is true */
-       if (body->delay_protect && (!ntohl(body->llpn) || !ntohl(body->olpn))) {
+       if (body->delay_protect &&
+           (!be_to_host32(body->llpn) || !be_to_host32(body->olpn))) {
                wpa_printf(MSG_WARNING,
                           "KaY: Lowest packet number should greater than 0 when delay_protect is TRUE");
                return -1;
@@ -1344,28 +1342,28 @@ ieee802_1x_mka_decode_sak_use_body(
        }
        if (all_receiving) {
                participant->to_dist_sak = FALSE;
-               ieee802_1x_cp_set_allreceiving(participant->kay->cp, TRUE);
-               ieee802_1x_cp_sm_step(participant->kay->cp);
+               ieee802_1x_cp_set_allreceiving(kay->cp, TRUE);
+               ieee802_1x_cp_sm_step(kay->cp);
        }
 
        /* if i'm key server, and detects peer member pn exhaustion, rekey.*/
-       lpn = ntohl(body->llpn);
-       if (lpn > participant->kay->pn_exhaustion) {
+       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");
                }
        }
 
-       founded = FALSE;
+       found = FALSE;
        dl_list_for_each(txsa, &participant->txsc->sa_list,
                         struct transmit_sa, list) {
                if (sa_key != NULL && txsa->pkey == sa_key) {
-                       founded = TRUE;
+                       found = TRUE;
                        break;
                }
        }
-       if (!founded) {
+       if (!found) {
                wpa_printf(MSG_WARNING, "KaY: Can't find txsa");
                return -1;
        }
@@ -1373,9 +1371,9 @@ ieee802_1x_mka_decode_sak_use_body(
        /* FIXME: Secy creates txsa with default npn. If MKA detected Latest Key
         * npn is larger than txsa's npn, set it to txsa.
         */
-       secy_get_transmit_next_pn(participant->kay, txsa);
+       secy_get_transmit_next_pn(kay, txsa);
        if (lpn > txsa->next_pn) {
-               secy_set_transmit_next_pn(participant->kay, txsa);
+               secy_set_transmit_next_pn(kay, txsa);
                wpa_printf(MSG_INFO, "KaY: update lpn =0x%x", lpn);
        }
 
@@ -1390,10 +1388,7 @@ static Boolean
 ieee802_1x_mka_dist_sak_body_present(
        struct ieee802_1x_mka_participant *participant)
 {
-       if (!participant->to_dist_sak || !participant->new_key)
-               return FALSE;
-
-       return TRUE;
+       return participant->to_dist_sak && participant->new_key;
 }
 
 
@@ -1404,21 +1399,18 @@ static int
 ieee802_1x_mka_get_dist_sak_length(
        struct ieee802_1x_mka_participant *participant)
 {
-       int length;
-       int cs_index = participant->kay->macsec_csindex;
+       int length = MKA_HDR_LEN;
+       unsigned int cs_index = participant->kay->macsec_csindex;
 
-       if (participant->advised_desired) {
+       if (participant->advised_desired && cs_index < CS_TABLE_SIZE) {
                length = sizeof(struct ieee802_1x_mka_dist_sak_body);
                if (cs_index != DEFAULT_CS_INDEX)
                        length += CS_ID_LEN;
 
                length += cipher_suite_tbl[cs_index].sak_len + 8;
-       } else {
-               length = MKA_HDR_LEN;
        }
-       length = (length + 0x3) & ~0x3;
 
-       return length;
+       return MKA_ALIGN_LENGTH(length);
 }
 
 
@@ -1433,7 +1425,7 @@ ieee802_1x_mka_encode_dist_sak_body(
        struct ieee802_1x_mka_dist_sak_body *body;
        struct data_key *sak;
        unsigned int length;
-       int cs_index;
+       unsigned int cs_index;
        int sak_pos;
 
        length = ieee802_1x_mka_get_dist_sak_length(participant);
@@ -1452,8 +1444,13 @@ ieee802_1x_mka_encode_dist_sak_body(
        body->kn = host_to_be32(sak->key_identifier.kn);
        cs_index = participant->kay->macsec_csindex;
        sak_pos = 0;
+       if (cs_index >= CS_TABLE_SIZE)
+               return -1;
        if (cs_index != DEFAULT_CS_INDEX) {
-               os_memcpy(body->sak, cipher_suite_tbl[cs_index].id, CS_ID_LEN);
+               be64 cs;
+
+               cs = host_to_be64(cipher_suite_tbl[cs_index].id);
+               os_memcpy(body->sak, &cs, CS_ID_LEN);
                sak_pos = CS_ID_LEN;
        }
        if (aes_wrap(participant->kek.key, 16,
@@ -1472,39 +1469,13 @@ ieee802_1x_mka_encode_dist_sak_body(
 /**
  * ieee802_1x_kay_init_data_key -
  */
-static struct data_key *
-ieee802_1x_kay_init_data_key(const struct key_conf *conf)
+static void ieee802_1x_kay_init_data_key(struct data_key *pkey)
 {
-       struct data_key *pkey;
-
-       if (!conf)
-               return NULL;
-
-       pkey = os_zalloc(sizeof(*pkey));
-       if (pkey == NULL) {
-               wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
-               return NULL;
-       }
-
-       pkey->key = os_zalloc(conf->key_len);
-       if (pkey->key == NULL) {
-               wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
-               os_free(pkey);
-               return NULL;
-       }
-
-       os_memcpy(pkey->key, conf->key, conf->key_len);
-       os_memcpy(&pkey->key_identifier, &conf->ki,
-                 sizeof(pkey->key_identifier));
-       pkey->confidentiality_offset = conf->offset;
-       pkey->an = conf->an;
-       pkey->transmits = conf->tx;
-       pkey->receives = conf->rx;
+       pkey->transmits = TRUE;
+       pkey->receives = TRUE;
        os_get_time(&pkey->created_time);
 
        pkey->user = 1;
-
-       return pkey;
 }
 
 
@@ -1521,19 +1492,18 @@ ieee802_1x_mka_decode_dist_sak_body(
        struct ieee802_1x_kay_peer *peer;
        struct macsec_ciphersuite *cs;
        size_t body_len;
-       struct key_conf *conf;
        struct data_key *sa_key = NULL;
-       struct ieee802_1x_mka_ki sak_ki;
        int sak_len;
        u8 *wrap_sak;
        u8 *unwrap_sak;
+       struct ieee802_1x_kay *kay = participant->kay;
 
        hdr = (struct ieee802_1x_mka_hdr *) mka_msg;
        body_len = get_mka_param_body_len(hdr);
        if ((body_len != 0) && (body_len != 28) && (body_len < 36)) {
                wpa_printf(MSG_ERROR,
-                          "KaY: MKA Use SAK Packet Body Length (%d bytes) should be 0, 28, 36, or more octets",
-                          (int) body_len);
+                          "KaY: MKA Use SAK Packet Body Length (%zu bytes) should be 0, 28, 36, or more octets",
+                          body_len);
                return -1;
        }
 
@@ -1547,8 +1517,8 @@ ieee802_1x_mka_decode_dist_sak_body(
                           "KaY: I can't accept the distributed SAK as myself is key server ");
                return -1;
        }
-       if (!participant->kay->macsec_desired ||
-           participant->kay->macsec_capable == MACSEC_CAP_NOT_IMPLEMENTED) {
+       if (!kay->macsec_desired ||
+           kay->macsec_capable == MACSEC_CAP_NOT_IMPLEMENTED) {
                wpa_printf(MSG_ERROR,
                           "KaY: I am not MACsec-desired or without MACsec capable");
                return -1;
@@ -1561,28 +1531,29 @@ ieee802_1x_mka_decode_dist_sak_body(
                           "KaY: The key server is not in my live peers list");
                return -1;
        }
-       if (os_memcmp(&participant->kay->key_server_sci,
-                     &peer->sci, sizeof(struct ieee802_1x_mka_sci)) != 0) {
+       if (!sci_equal(&kay->key_server_sci, &peer->sci)) {
                wpa_printf(MSG_ERROR, "KaY: The key server is not elected");
                return -1;
        }
+
        if (body_len == 0) {
-               participant->kay->authenticated = TRUE;
-               participant->kay->secured = FALSE;
-               participant->kay->failed = FALSE;
+               kay->authenticated = TRUE;
+               kay->secured = FALSE;
+               kay->failed = FALSE;
                participant->advised_desired = FALSE;
-               ieee802_1x_cp_connect_authenticated(participant->kay->cp);
-               ieee802_1x_cp_sm_step(participant->kay->cp);
+               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 = TRUE;
                return 0;
        }
+
        participant->advised_desired = TRUE;
-       participant->kay->authenticated = FALSE;
-       participant->kay->secured = TRUE;
-       participant->kay->failed = FALSE;
-       ieee802_1x_cp_connect_secure(participant->kay->cp);
-       ieee802_1x_cp_sm_step(participant->kay->cp);
+       kay->authenticated = FALSE;
+       kay->secured = TRUE;
+       kay->failed = FALSE;
+       ieee802_1x_cp_connect_secure(kay->cp);
+       ieee802_1x_cp_sm_step(kay->cp);
 
        body = (struct ieee802_1x_mka_dist_sak_body *)mka_msg;
        ieee802_1x_mka_dump_dist_sak_body(body);
@@ -1595,10 +1566,12 @@ ieee802_1x_mka_decode_dist_sak_body(
                        return 0;
                }
        }
+
        if (body_len == 28) {
                sak_len = DEFAULT_SA_KEY_LEN;
                wrap_sak =  body->sak;
-               participant->kay->macsec_csindex = DEFAULT_CS_INDEX;
+               kay->macsec_csindex = DEFAULT_CS_INDEX;
+               cs = &cipher_suite_tbl[kay->macsec_csindex];
        } else {
                cs = ieee802_1x_kay_get_cipher_suite(participant, body->sak);
                if (!cs) {
@@ -1608,7 +1581,7 @@ ieee802_1x_mka_decode_dist_sak_body(
                }
                sak_len = cs->sak_len;
                wrap_sak = body->sak + CS_ID_LEN;
-               participant->kay->macsec_csindex = cs->index;
+               kay->macsec_csindex = cs->index;
        }
 
        unwrap_sak = os_zalloc(sak_len);
@@ -1624,62 +1597,36 @@ ieee802_1x_mka_decode_dist_sak_body(
        }
        wpa_hexdump(MSG_DEBUG, "\tAES Key Unwrap of SAK:", unwrap_sak, sak_len);
 
-       conf = os_zalloc(sizeof(*conf));
-       if (!conf) {
-               wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
-               os_free(unwrap_sak);
-               return -1;
-       }
-       conf->key_len = sak_len;
-
-       conf->key = os_zalloc(conf->key_len);
-       if (!conf->key) {
-               wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
+       sa_key = os_zalloc(sizeof(*sa_key));
+       if (!sa_key) {
                os_free(unwrap_sak);
-               os_free(conf);
                return -1;
        }
 
-       os_memcpy(conf->key, unwrap_sak, conf->key_len);
+       os_memcpy(&sa_key->key_identifier.mi, &participant->current_peer_id.mi,
+                 MI_LEN);
+       sa_key->key_identifier.kn = be_to_host32(body->kn);
 
-       os_memcpy(&sak_ki.mi, &participant->current_peer_id.mi,
-                 sizeof(sak_ki.mi));
-       sak_ki.kn = be_to_host32(body->kn);
+       sa_key->key = unwrap_sak;
+       sa_key->key_len = sak_len;
 
-       os_memcpy(conf->ki.mi, sak_ki.mi, MI_LEN);
-       conf->ki.kn = sak_ki.kn;
-       conf->an = body->dan;
-       conf->offset = body->confid_offset;
-       conf->rx = TRUE;
-       conf->tx = TRUE;
-
-       sa_key = ieee802_1x_kay_init_data_key(conf);
-       if (!sa_key) {
-               os_free(unwrap_sak);
-               os_free(conf->key);
-               os_free(conf);
-               return -1;
-       }
+       sa_key->confidentiality_offset = body->confid_offset;
+       sa_key->an = body->dan;
+       ieee802_1x_kay_init_data_key(sa_key);
 
        dl_list_add(&participant->sak_list, &sa_key->list);
 
-       ieee802_1x_cp_set_ciphersuite(
-               participant->kay->cp,
-               cipher_suite_tbl[participant->kay->macsec_csindex].id);
-       ieee802_1x_cp_sm_step(participant->kay->cp);
-       ieee802_1x_cp_set_offset(participant->kay->cp, body->confid_offset);
-       ieee802_1x_cp_sm_step(participant->kay->cp);
-       ieee802_1x_cp_set_distributedki(participant->kay->cp, &sak_ki);
-       ieee802_1x_cp_set_distributedan(participant->kay->cp, body->dan);
-       ieee802_1x_cp_signal_newsak(participant->kay->cp);
-       ieee802_1x_cp_sm_step(participant->kay->cp);
+       ieee802_1x_cp_set_ciphersuite(kay->cp, cs->id);
+       ieee802_1x_cp_sm_step(kay->cp);
+       ieee802_1x_cp_set_offset(kay->cp, body->confid_offset);
+       ieee802_1x_cp_sm_step(kay->cp);
+       ieee802_1x_cp_set_distributedki(kay->cp, &sa_key->key_identifier);
+       ieee802_1x_cp_set_distributedan(kay->cp, body->dan);
+       ieee802_1x_cp_signal_newsak(kay->cp);
+       ieee802_1x_cp_sm_step(kay->cp);
 
        participant->to_use_sak = TRUE;
 
-       os_free(unwrap_sak);
-       os_free(conf->key);
-       os_free(conf);
-
        return 0;
 }
 
@@ -1705,7 +1652,7 @@ ieee802_1x_mka_get_icv_length(struct ieee802_1x_mka_participant *participant)
        length = sizeof(struct ieee802_1x_mka_icv_body);
        length += mka_alg_tbl[participant->kay->mka_algindex].icv_len;
 
-       return (length + 0x3) & ~0x3;
+       return MKA_ALIGN_LENGTH(length);
 }
 
 
@@ -1733,12 +1680,9 @@ ieee802_1x_mka_encode_icv_body(struct ieee802_1x_mka_participant *participant,
                return -1;
        }
 
-       if (length != DEFAULT_ICV_LEN)  {
-               os_memcpy(wpabuf_put(buf, length - MKA_HDR_LEN), cmac,
-                         length - MKA_HDR_LEN);
-       } else {
-               os_memcpy(wpabuf_put(buf, length), cmac, length);
-       }
+       if (length != DEFAULT_ICV_LEN)
+               length -= MKA_HDR_LEN;
+       os_memcpy(wpabuf_put(buf, length), cmac, length);
 
        return 0;
 }
@@ -1754,7 +1698,7 @@ ieee802_1x_mka_decode_icv_body(struct ieee802_1x_mka_participant *participant,
        struct ieee802_1x_mka_icv_body *body;
        size_t body_len;
        size_t left_len;
-       int body_type;
+       u8 body_type;
        const u8 *pos;
 
        pos = mka_msg;
@@ -1801,8 +1745,8 @@ ieee802_1x_mka_decode_dist_cak_body(
        body_len = get_mka_param_body_len(hdr);
        if (body_len < 28) {
                wpa_printf(MSG_ERROR,
-                          "KaY: MKA Use SAK Packet Body Length (%d bytes) should be 28 or more octets",
-                          (int) body_len);
+                          "KaY: MKA Use SAK Packet Body Length (%zu bytes) should be 28 or more octets",
+                          body_len);
                return -1;
        }
 
@@ -1825,8 +1769,8 @@ ieee802_1x_mka_decode_kmd_body(
        body_len = get_mka_param_body_len(hdr);
        if (body_len < 5) {
                wpa_printf(MSG_ERROR,
-                          "KaY: MKA Use SAK Packet Body Length (%d bytes) should be 5 or more octets",
-                          (int) body_len);
+                          "KaY: MKA Use SAK Packet Body Length (%zu bytes) should be 5 or more octets",
+                          body_len);
                return -1;
        }
 
@@ -1845,77 +1789,87 @@ static int ieee802_1x_mka_decode_announce_body(
 }
 
 
-static struct mka_param_body_handler mak_body_handler[] = {
+struct mka_param_body_handler {
+       int (*body_tx)(struct ieee802_1x_mka_participant *participant,
+                      struct wpabuf *buf);
+       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);
+};
+
+
+static struct mka_param_body_handler mka_body_handler[] = {
        /* basic parameter set */
        {
-               ieee802_1x_mka_encode_basic_body,
-               NULL,
-               ieee802_1x_mka_basic_body_length,
-               ieee802_1x_mka_basic_body_present
+               .body_tx      = ieee802_1x_mka_encode_basic_body,
+               .body_rx      = NULL,
+               .body_length  = ieee802_1x_mka_basic_body_length,
+               .body_present = ieee802_1x_mka_basic_body_present
        },
 
        /* live peer list parameter set */
        {
-               ieee802_1x_mka_encode_live_peer_body,
-               ieee802_1x_mka_decode_live_peer_body,
-               ieee802_1x_mka_get_live_peer_length,
-               ieee802_1x_mka_live_peer_body_present
+               .body_tx      = ieee802_1x_mka_encode_live_peer_body,
+               .body_rx      = ieee802_1x_mka_decode_live_peer_body,
+               .body_length  = ieee802_1x_mka_get_live_peer_length,
+               .body_present = ieee802_1x_mka_live_peer_body_present
        },
 
        /* potential peer list parameter set */
        {
-               ieee802_1x_mka_encode_potential_peer_body,
-               ieee802_1x_mka_decode_potential_peer_body,
-               ieee802_1x_mka_get_potential_peer_length,
-               ieee802_1x_mka_potential_peer_body_present
+               .body_tx      = ieee802_1x_mka_encode_potential_peer_body,
+               .body_rx      = ieee802_1x_mka_decode_potential_peer_body,
+               .body_length  = ieee802_1x_mka_get_potential_peer_length,
+               .body_present = ieee802_1x_mka_potential_peer_body_present
        },
 
        /* sak use parameter set */
        {
-               ieee802_1x_mka_encode_sak_use_body,
-               ieee802_1x_mka_decode_sak_use_body,
-               ieee802_1x_mka_get_sak_use_length,
-               ieee802_1x_mka_sak_use_body_present
+               .body_tx      = ieee802_1x_mka_encode_sak_use_body,
+               .body_rx      = ieee802_1x_mka_decode_sak_use_body,
+               .body_length  = ieee802_1x_mka_get_sak_use_length,
+               .body_present = ieee802_1x_mka_sak_use_body_present
        },
 
        /* distribute sak parameter set */
        {
-               ieee802_1x_mka_encode_dist_sak_body,
-               ieee802_1x_mka_decode_dist_sak_body,
-               ieee802_1x_mka_get_dist_sak_length,
-               ieee802_1x_mka_dist_sak_body_present
+               .body_tx      = ieee802_1x_mka_encode_dist_sak_body,
+               .body_rx      = ieee802_1x_mka_decode_dist_sak_body,
+               .body_length  = ieee802_1x_mka_get_dist_sak_length,
+               .body_present = ieee802_1x_mka_dist_sak_body_present
        },
 
        /* distribute cak parameter set */
        {
-               NULL,
-               ieee802_1x_mka_decode_dist_cak_body,
-               NULL,
-               NULL
+               .body_tx      = NULL,
+               .body_rx      = ieee802_1x_mka_decode_dist_cak_body,
+               .body_length  = NULL,
+               .body_present = NULL
        },
 
        /* kmd parameter set */
        {
-               NULL,
-               ieee802_1x_mka_decode_kmd_body,
-               NULL,
-               NULL
+               .body_tx      = NULL,
+               .body_rx      = ieee802_1x_mka_decode_kmd_body,
+               .body_length  = NULL,
+               .body_present = NULL
        },
 
        /* announce parameter set */
        {
-               NULL,
-               ieee802_1x_mka_decode_announce_body,
-               NULL,
-               NULL
+               .body_tx      = NULL,
+               .body_rx      = ieee802_1x_mka_decode_announce_body,
+               .body_length  = NULL,
+               .body_present = NULL
        },
 
        /* icv parameter set */
        {
-               ieee802_1x_mka_encode_icv_body,
-               NULL,
-               ieee802_1x_mka_get_icv_length,
-               ieee802_1x_mka_icv_body_present
+               .body_tx      = ieee802_1x_mka_encode_icv_body,
+               .body_rx      = NULL,
+               .body_length  = ieee802_1x_mka_get_icv_length,
+               .body_present = ieee802_1x_mka_icv_body_present
        },
 };
 
@@ -1923,7 +1877,7 @@ static struct mka_param_body_handler mak_body_handler[] = {
 /**
  * ieee802_1x_kay_deinit_data_key -
  */
-void ieee802_1x_kay_deinit_data_key(struct data_key *pkey)
+static void ieee802_1x_kay_deinit_data_key(struct data_key *pkey)
 {
        if (!pkey)
                return;
@@ -1945,11 +1899,13 @@ static int
 ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant)
 {
        struct data_key *sa_key = NULL;
-       struct key_conf *conf;
        struct ieee802_1x_kay_peer *peer;
        struct ieee802_1x_kay *kay = participant->kay;
        int ctx_len, ctx_offset;
        u8 *context;
+       unsigned int key_len;
+       u8 *key;
+       struct macsec_ciphersuite *cs;
 
        /* check condition for generating a fresh SAK:
         * must have one live peer
@@ -1976,40 +1932,29 @@ ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant)
                return -1;
        }
 
-       conf = os_zalloc(sizeof(*conf));
-       if (!conf) {
+       cs = &cipher_suite_tbl[kay->macsec_csindex];
+       key_len = cs->sak_len;
+       key = os_zalloc(key_len);
+       if (!key) {
                wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
                return -1;
        }
-       conf->key_len = cipher_suite_tbl[kay->macsec_csindex].sak_len;
 
-       conf->key = os_zalloc(conf->key_len);
-       if (!conf->key) {
-               os_free(conf);
-               wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
-               return -1;
-       }
-
-       ctx_len = conf->key_len + sizeof(kay->dist_kn);
+       ctx_len = key_len + sizeof(kay->dist_kn);
        dl_list_for_each(peer, &participant->live_peers,
                         struct ieee802_1x_kay_peer, list)
                ctx_len += sizeof(peer->mi);
        ctx_len += sizeof(participant->mi);
 
        context = os_zalloc(ctx_len);
-       if (!context) {
-               os_free(conf->key);
-               os_free(conf);
-               return -1;
-       }
+       if (!context)
+               goto fail;
+
        ctx_offset = 0;
-       if (os_get_random(context + ctx_offset, conf->key_len) < 0) {
-               os_free(context);
-               os_free(conf->key);
-               os_free(conf);
-               return -1;
-       }
-       ctx_offset += conf->key_len;
+       if (os_get_random(context + ctx_offset, key_len) < 0)
+               goto fail;
+
+       ctx_offset += key_len;
        dl_list_for_each(peer, &participant->live_peers,
                         struct ieee802_1x_kay_peer, list) {
                os_memcpy(context + ctx_offset, peer->mi, sizeof(peer->mi));
@@ -2020,46 +1965,44 @@ ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant)
        ctx_offset += sizeof(participant->mi);
        os_memcpy(context + ctx_offset, &kay->dist_kn, sizeof(kay->dist_kn));
 
-       if (conf->key_len == 16) {
+       if (key_len == 16) {
                ieee802_1x_sak_128bits_aes_cmac(participant->cak.key,
-                                               context, ctx_len, conf->key);
-       } else if (conf->key_len == 32) {
+                                               context, ctx_len, key);
+       } else if (key_len == 32) {
                ieee802_1x_sak_128bits_aes_cmac(participant->cak.key,
-                                               context, ctx_len, conf->key);
+                                               context, ctx_len, key);
        } else {
                wpa_printf(MSG_ERROR, "KaY: SAK Length not support");
-               os_free(conf->key);
-               os_free(conf);
-               os_free(context);
-               return -1;
+               goto fail;
        }
-       wpa_hexdump(MSG_DEBUG, "KaY: generated new SAK",
-                   conf->key, conf->key_len);
-
-       os_memcpy(conf->ki.mi, participant->mi, MI_LEN);
-       conf->ki.kn = participant->kay->dist_kn;
-       conf->an = participant->kay->dist_an;
-       conf->offset = kay->macsec_confidentiality;
-       conf->rx = TRUE;
-       conf->tx = TRUE;
+       wpa_hexdump(MSG_DEBUG, "KaY: generated new SAK", key, key_len);
+       os_free(context);
+       context = NULL;
 
-       sa_key = ieee802_1x_kay_init_data_key(conf);
+       sa_key = os_zalloc(sizeof(*sa_key));
        if (!sa_key) {
-               os_free(conf->key);
-               os_free(conf);
-               os_free(context);
-               return -1;
+               wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
+               goto fail;
        }
+
+       sa_key->key = key;
+       sa_key->key_len = key_len;
+       os_memcpy(sa_key->key_identifier.mi, participant->mi, MI_LEN);
+       sa_key->key_identifier.kn = kay->dist_kn;
+
+       sa_key->confidentiality_offset = kay->macsec_confidentiality;
+       sa_key->an = kay->dist_an;
+       ieee802_1x_kay_init_data_key(sa_key);
+
        participant->new_key = sa_key;
 
        dl_list_add(&participant->sak_list, &sa_key->list);
-       ieee802_1x_cp_set_ciphersuite(participant->kay->cp,
-                                     cipher_suite_tbl[kay->macsec_csindex].id);
+       ieee802_1x_cp_set_ciphersuite(kay->cp, cs->id);
        ieee802_1x_cp_sm_step(kay->cp);
-       ieee802_1x_cp_set_offset(kay->cp, conf->offset);
+       ieee802_1x_cp_set_offset(kay->cp, kay->macsec_confidentiality);
        ieee802_1x_cp_sm_step(kay->cp);
-       ieee802_1x_cp_set_distributedki(kay->cp, &conf->ki);
-       ieee802_1x_cp_set_distributedan(kay->cp, conf->an);
+       ieee802_1x_cp_set_distributedki(kay->cp, &sa_key->key_identifier);
+       ieee802_1x_cp_set_distributedan(kay->cp, sa_key->an);
        ieee802_1x_cp_signal_newsak(kay->cp);
        ieee802_1x_cp_sm_step(kay->cp);
 
@@ -2067,17 +2010,31 @@ ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant)
                         struct ieee802_1x_kay_peer, list)
                peer->sak_used = FALSE;
 
-       participant->kay->dist_kn++;
-       participant->kay->dist_an++;
-       if (participant->kay->dist_an > 3)
-               participant->kay->dist_an = 0;
+       kay->dist_kn++;
+       kay->dist_an++;
+       if (kay->dist_an > 3)
+               kay->dist_an = 0;
 
-       participant->kay->dist_time = time(NULL);
+       kay->dist_time = time(NULL);
 
-       os_free(conf->key);
-       os_free(conf);
-       os_free(context);
        return 0;
+
+fail:
+       os_free(key);
+       os_free(context);
+       return -1;
+}
+
+
+static int compare_priorities(const struct ieee802_1x_kay_peer *peer,
+                             const struct ieee802_1x_kay_peer *other)
+{
+       if (peer->key_server_priority < other->key_server_priority)
+               return -1;
+       if (other->key_server_priority < peer->key_server_priority)
+               return 1;
+
+       return os_memcmp(peer->sci.addr, other->sci.addr, ETH_ALEN);
 }
 
 
@@ -2092,7 +2049,6 @@ ieee802_1x_kay_elect_key_server(struct ieee802_1x_mka_participant *participant)
        struct ieee802_1x_kay_peer *key_server = NULL;
        struct ieee802_1x_kay *kay = participant->kay;
        Boolean i_is_key_server;
-       int i;
 
        if (participant->is_obliged_key_server) {
                participant->new_sak = TRUE;
@@ -2112,47 +2068,26 @@ ieee802_1x_kay_elect_key_server(struct ieee802_1x_mka_participant *participant)
                        continue;
                }
 
-               if (peer->key_server_priority <
-                   key_server->key_server_priority) {
+               if (compare_priorities(peer, key_server) < 0)
                        key_server = peer;
-               } else if (peer->key_server_priority ==
-                          key_server->key_server_priority) {
-                       for (i = 0; i < 6; i++) {
-                               if (peer->sci.addr[i] <
-                                   key_server->sci.addr[i])
-                                       key_server = peer;
-                       }
-               }
        }
 
        /* elect the key server between me and the above elected peer */
        i_is_key_server = FALSE;
        if (key_server && participant->can_be_key_server) {
-               if (kay->actor_priority
-                          < key_server->key_server_priority) {
-                       i_is_key_server = TRUE;
-               } else if (kay->actor_priority
-                                       == key_server->key_server_priority) {
-                       for (i = 0; i < 6; i++) {
-                               if (kay->actor_sci.addr[i]
-                                       < key_server->sci.addr[i]) {
-                                       i_is_key_server = TRUE;
-                               }
-                       }
-               }
-       }
+               struct ieee802_1x_kay_peer tmp;
 
-       if (!key_server && !i_is_key_server) {
-               participant->principal = FALSE;
-               participant->is_key_server = FALSE;
-               participant->is_elected = FALSE;
-               return 0;
+               tmp.key_server_priority = kay->actor_priority;
+               os_memcpy(&tmp.sci, &kay->actor_sci, sizeof(tmp.sci));
+               if (compare_priorities(&tmp, key_server) < 0)
+                       i_is_key_server = TRUE;
+       } else if (participant->can_be_key_server) {
+               i_is_key_server = TRUE;
        }
 
        if (i_is_key_server) {
                ieee802_1x_cp_set_electedself(kay->cp, TRUE);
-               if (os_memcmp(&kay->key_server_sci, &kay->actor_sci,
-                             sizeof(kay->key_server_sci))) {
+               if (!sci_equal(&kay->key_server_sci, &kay->actor_sci)) {
                        ieee802_1x_cp_signal_chgdserver(kay->cp);
                        ieee802_1x_cp_sm_step(kay->cp);
                }
@@ -2167,12 +2102,9 @@ ieee802_1x_kay_elect_key_server(struct ieee802_1x_mka_participant *participant)
                os_memcpy(&kay->key_server_sci, &kay->actor_sci,
                          sizeof(kay->key_server_sci));
                kay->key_server_priority = kay->actor_priority;
-       }
-
-       if (key_server) {
+       } else if (key_server) {
                ieee802_1x_cp_set_electedself(kay->cp, FALSE);
-               if (os_memcmp(&kay->key_server_sci, &key_server->sci,
-                             sizeof(kay->key_server_sci))) {
+               if (!sci_equal(&kay->key_server_sci, &key_server->sci)) {
                        ieee802_1x_cp_signal_chgdserver(kay->cp);
                        ieee802_1x_cp_sm_step(kay->cp);
                }
@@ -2184,6 +2116,10 @@ ieee802_1x_kay_elect_key_server(struct ieee802_1x_mka_participant *participant)
                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;
        }
 
        return 0;
@@ -2226,11 +2162,11 @@ ieee802_1x_kay_decide_macsec_use(
                if (!peer->macsec_desired)
                        continue;
 
-               if (peer->macsec_capbility == MACSEC_CAP_NOT_IMPLEMENTED)
+               if (peer->macsec_capability == MACSEC_CAP_NOT_IMPLEMENTED)
                        continue;
 
-               less_capability = (less_capability < peer->macsec_capbility) ?
-                       less_capability : peer->macsec_capbility;
+               less_capability = (less_capability < peer->macsec_capability) ?
+                       less_capability : peer->macsec_capability;
                has_peer = TRUE;
        }
 
@@ -2291,10 +2227,10 @@ ieee802_1x_kay_encode_mkpdu(struct ieee802_1x_mka_participant *participant,
        eapol_hdr->type = IEEE802_1X_TYPE_EAPOL_MKA;
        eapol_hdr->length = host_to_be16(pbuf->size - pbuf->used);
 
-       for (i = 0; i < ARRAY_SIZE(mak_body_handler); i++) {
-               if (mak_body_handler[i].body_present &&
-                   mak_body_handler[i].body_present(participant)) {
-                       if (mak_body_handler[i].body_tx(participant, pbuf))
+       for (i = 0; i < ARRAY_SIZE(mka_body_handler); i++) {
+               if (mka_body_handler[i].body_present &&
+                   mka_body_handler[i].body_present(participant)) {
+                       if (mka_body_handler[i].body_tx(participant, pbuf))
                                return -1;
                }
        }
@@ -2316,10 +2252,10 @@ ieee802_1x_participant_send_mkpdu(
 
        wpa_printf(MSG_DEBUG, "KaY: to enpacket and send the MKPDU");
        length += sizeof(struct ieee802_1x_hdr) + sizeof(struct ieee8023_hdr);
-       for (i = 0; i < ARRAY_SIZE(mak_body_handler); i++) {
-               if (mak_body_handler[i].body_present &&
-                   mak_body_handler[i].body_present(participant))
-                       length += mak_body_handler[i].body_length(participant);
+       for (i = 0; i < ARRAY_SIZE(mka_body_handler); i++) {
+               if (mka_body_handler[i].body_present &&
+                   mka_body_handler[i].body_present(participant))
+                       length += mka_body_handler[i].body_length(participant);
        }
 
        buf = wpabuf_alloc(length);
@@ -2360,27 +2296,16 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
        participant = (struct ieee802_1x_mka_participant *)eloop_ctx;
        kay = participant->kay;
        if (participant->cak_life) {
-               if (now > participant->cak_life) {
-                       kay->authenticated = FALSE;
-                       kay->secured = FALSE;
-                       kay->failed = TRUE;
-                       ieee802_1x_kay_delete_mka(kay, &participant->ckn);
-                       return;
-               }
+               if (now > participant->cak_life)
+                       goto delete_mka;
        }
 
        /* should delete MKA instance if there are not live peers
         * when the MKA life elapsed since its creating */
        if (participant->mka_life) {
                if (dl_list_empty(&participant->live_peers)) {
-                       if (now > participant->mka_life) {
-                               kay->authenticated = FALSE;
-                               kay->secured = FALSE;
-                               kay->failed = TRUE;
-                               ieee802_1x_kay_delete_mka(kay,
-                                                         &participant->ckn);
-                               return;
-                       }
+                       if (now > participant->mka_life)
+                               goto delete_mka;
                } else {
                        participant->mka_life = 0;
                }
@@ -2397,8 +2322,7 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
                        dl_list_for_each_safe(rxsc, pre_rxsc,
                                              &participant->rxsc_list,
                                              struct receive_sc, list) {
-                               if (os_memcmp(&rxsc->sci, &peer->sci,
-                                             sizeof(rxsc->sci)) == 0) {
+                               if (sci_equal(&rxsc->sci, &peer->sci)) {
                                        secy_delete_receive_sc(kay, rxsc);
                                        ieee802_1x_kay_deinit_receive_sc(
                                                participant, rxsc);
@@ -2469,6 +2393,14 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
        eloop_register_timeout(MKA_HELLO_TIME / 1000, 0,
                               ieee802_1x_participant_timer,
                               participant, NULL);
+
+       return;
+
+delete_mka:
+       kay->authenticated = FALSE;
+       kay->secured = FALSE;
+       kay->failed = TRUE;
+       ieee802_1x_kay_delete_mka(kay, &participant->ckn);
 }
 
 
@@ -2506,8 +2438,8 @@ ieee802_1x_kay_init_transmit_sa(struct transmit_sc *psc, u8 an, u32 next_PN,
 
        dl_list_add(&psc->sa_list, &psa->list);
        wpa_printf(MSG_DEBUG,
-                  "KaY: Create transmit SA(an: %d, next_PN: %u) of SC(channel: %d)",
-                  (int) an, next_PN, psc->channel);
+                  "KaY: Create transmit SA(an: %hhu, next_PN: %u) of SC(channel: %d)",
+                  an, next_PN, psc->channel);
 
        return psa;
 }
@@ -2520,8 +2452,8 @@ static void ieee802_1x_kay_deinit_transmit_sa(struct transmit_sa *psa)
 {
        psa->pkey = NULL;
        wpa_printf(MSG_DEBUG,
-                  "KaY: Delete transmit SA(an: %d) of SC(channel: %d)",
-                  psa->an, psa->sc->channel);
+                  "KaY: Delete transmit SA(an: %hhu) of SC",
+                  psa->an);
        dl_list_del(&psa->list);
        os_free(psa);
 }
@@ -2837,38 +2769,6 @@ int ieee802_1x_kay_enable_new_info(struct ieee802_1x_kay *kay)
 
 
 /**
- * ieee802_1x_kay_cp_conf -
- */
-int ieee802_1x_kay_cp_conf(struct ieee802_1x_kay *kay,
-                          struct ieee802_1x_cp_conf *pconf)
-{
-       pconf->protect = kay->macsec_protect;
-       pconf->replay_protect = kay->macsec_replay_protect;
-       pconf->validate = kay->macsec_validate;
-
-       return 0;
-}
-
-
-/**
- * ieee802_1x_kay_alloc_cp_sm -
- */
-static struct ieee802_1x_cp_sm *
-ieee802_1x_kay_alloc_cp_sm(struct ieee802_1x_kay *kay)
-{
-       struct ieee802_1x_cp_conf conf;
-
-       os_memset(&conf, 0, sizeof(conf));
-       conf.protect = kay->macsec_protect;
-       conf.replay_protect = kay->macsec_replay_protect;
-       conf.validate = kay->macsec_validate;
-       conf.replay_window = kay->macsec_replay_window;
-
-       return ieee802_1x_cp_sm_init(kay, &conf);
-}
-
-
-/**
  * ieee802_1x_kay_mkpdu_sanity_check -
  *     sanity check specified in clause 11.11.2 of IEEE802.1X-2010
  */
@@ -2896,13 +2796,13 @@ static int ieee802_1x_kay_mkpdu_sanity_check(struct ieee802_1x_kay *kay,
                return -1;
        }
 
-       /* MKPDU should not less than 32 octets */
+       /* MKPDU should not be less than 32 octets */
        mka_msg_len = be_to_host16(eapol_hdr->length);
        if (mka_msg_len < 32) {
                wpa_printf(MSG_MSGDUMP, "KaY: MKPDU is less than 32 octets");
                return -1;
        }
-       /* MKPDU should multiple 4 octets */
+       /* MKPDU should be a multiple of 4 octets */
        if ((mka_msg_len % 4) != 0) {
                wpa_printf(MSG_MSGDUMP,
                           "KaY: MKPDU is not multiple of 4 octets");
@@ -2915,9 +2815,9 @@ static int ieee802_1x_kay_mkpdu_sanity_check(struct ieee802_1x_kay *kay,
        /* EAPOL-MKA body should comprise basic parameter set and ICV */
        if (mka_msg_len < MKA_HDR_LEN + body_len + DEFAULT_ICV_LEN) {
                wpa_printf(MSG_ERROR,
-                          "KaY: Received EAPOL-MKA Packet Body Length (%d bytes) is less than the Basic Parameter Set Header Length (%d bytes) + the Basic Parameter Set Body Length (%d bytes) + %d bytes of ICV",
-                          (int) mka_msg_len, (int) MKA_HDR_LEN,
-                          (int) body_len, DEFAULT_ICV_LEN);
+                          "KaY: Received EAPOL-MKA Packet Body Length (%zu bytes) is less than the Basic Parameter Set Header Length (%zu bytes) + the Basic Parameter Set Body Length (%zu bytes) + %d bytes of ICV",
+                          mka_msg_len, MKA_HDR_LEN,
+                          body_len, DEFAULT_ICV_LEN);
                return -1;
        }
 
@@ -2948,21 +2848,19 @@ static int ieee802_1x_kay_mkpdu_sanity_check(struct ieee802_1x_kay *kay,
                wpa_printf(MSG_ERROR, "KaY: omac1_aes_128 failed");
                return -1;
        }
+
        msg_icv = ieee802_1x_mka_decode_icv_body(participant, (u8 *) mka_hdr,
                                                 mka_msg_len);
-
-       if (msg_icv) {
-               if (os_memcmp_const(msg_icv, icv,
-                                   mka_alg_tbl[kay->mka_algindex].icv_len) !=
-                   0) {
-                       wpa_printf(MSG_ERROR,
-                                  "KaY: Computed ICV is not equal to Received ICV");
-               return -1;
-               }
-       } else {
+       if (!msg_icv) {
                wpa_printf(MSG_ERROR, "KaY: No ICV");
                return -1;
        }
+       if (os_memcmp_const(msg_icv, icv,
+                           mka_alg_tbl[kay->mka_algindex].icv_len) != 0) {
+               wpa_printf(MSG_ERROR,
+                          "KaY: Computed ICV is not equal to Received ICV");
+               return -1;
+       }
 
        return 0;
 }
@@ -2978,10 +2876,9 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
        struct ieee802_1x_mka_hdr *hdr;
        size_t body_len;
        size_t left_len;
-       int body_type;
+       u8 body_type;
        int i;
        const u8 *pos;
-       Boolean my_included;
        Boolean handled[256];
 
        if (ieee802_1x_kay_mkpdu_sanity_check(kay, buf, len))
@@ -3002,28 +2899,27 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
        left_len -= body_len + MKA_HDR_LEN;
 
        /* check i am in the peer's peer list */
-       my_included = ieee802_1x_mka_i_in_peerlist(participant, pos, left_len);
-       if (my_included) {
+       if (ieee802_1x_mka_i_in_peerlist(participant, pos, left_len) &&
+           !ieee802_1x_kay_is_in_live_peer(participant,
+                                           participant->current_peer_id.mi)) {
                /* accept the peer as live peer */
-               if (!ieee802_1x_kay_is_in_peer(
-                           participant,
-                           participant->current_peer_id.mi)) {
-                       if (!ieee802_1x_kay_create_live_peer(
+               if (ieee802_1x_kay_is_in_potential_peer(
+                           participant, participant->current_peer_id.mi)) {
+                       if (!ieee802_1x_kay_move_live_peer(
                                    participant,
                                    participant->current_peer_id.mi,
-                                   participant->current_peer_id.mn))
+                                   be_to_host32(participant->
+                                                current_peer_id.mn)))
+                               return -1;
+               } else if (!ieee802_1x_kay_create_live_peer(
+                                  participant, participant->current_peer_id.mi,
+                                  be_to_host32(participant->
+                                               current_peer_id.mn))) {
                                return -1;
-                       ieee802_1x_kay_elect_key_server(participant);
-                       ieee802_1x_kay_decide_macsec_use(participant);
-               }
-               if (ieee802_1x_kay_is_in_potential_peer(
-                           participant, participant->current_peer_id.mi)) {
-                       ieee802_1x_kay_move_live_peer(
-                               participant, participant->current_peer_id.mi,
-                               participant->current_peer_id.mn);
-                       ieee802_1x_kay_elect_key_server(participant);
-                       ieee802_1x_kay_decide_macsec_use(participant);
                }
+
+               ieee802_1x_kay_elect_key_server(participant);
+               ieee802_1x_kay_decide_macsec_use(participant);
        }
 
        /*
@@ -3034,7 +2930,9 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
                handled[i] = FALSE;
 
        handled[0] = TRUE;
-       while (left_len > MKA_HDR_LEN + DEFAULT_ICV_LEN) {
+       for (; left_len > MKA_HDR_LEN + DEFAULT_ICV_LEN;
+            pos += body_len + MKA_HDR_LEN,
+                    left_len -= body_len + MKA_HDR_LEN) {
                hdr = (struct ieee802_1x_mka_hdr *) pos;
                body_len = get_mka_param_body_len(hdr);
                body_type = get_mka_param_body_type(hdr);
@@ -3044,28 +2942,25 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
 
                if (left_len < (MKA_HDR_LEN + body_len + DEFAULT_ICV_LEN)) {
                        wpa_printf(MSG_ERROR,
-                                  "KaY: MKA Peer Packet Body Length (%d bytes) is less than the Parameter Set Header Length (%d bytes) + the Parameter Set Body Length (%d bytes) + %d bytes of ICV",
-                                  (int) left_len, (int) MKA_HDR_LEN,
-                                  (int) body_len, DEFAULT_ICV_LEN);
-                       goto next_para_set;
+                                  "KaY: MKA Peer Packet Body Length (%zu bytes) is less than the Parameter Set Header Length (%zu bytes) + the Parameter Set Body Length (%zu bytes) + %d bytes of ICV",
+                                  left_len, MKA_HDR_LEN,
+                                  body_len, DEFAULT_ICV_LEN);
+                       continue;
                }
 
                if (handled[body_type])
-                       goto next_para_set;
+                       continue;
 
                handled[body_type] = TRUE;
-               if (mak_body_handler[body_type].body_rx) {
-                       mak_body_handler[body_type].body_rx
+               if (body_type < ARRAY_SIZE(mka_body_handler) &&
+                   mka_body_handler[body_type].body_rx) {
+                       mka_body_handler[body_type].body_rx
                                (participant, pos, left_len);
                } else {
                        wpa_printf(MSG_ERROR,
-                                  "The type %d not supported in this MKA version %d",
+                                  "The type %d is not supported in this MKA version %d",
                                   body_type, MKA_VERSION_ID);
                }
-
-next_para_set:
-               pos += body_len + MKA_HDR_LEN;
-               left_len -= body_len + MKA_HDR_LEN;
        }
 
        kay->active = TRUE;
@@ -3094,10 +2989,10 @@ static void kay_l2_receive(void *ctx, const u8 *src_addr, const u8 *buf,
        eth_hdr = (struct ieee8023_hdr *) buf;
        eapol_hdr = (struct ieee802_1x_hdr *) (eth_hdr + 1);
        if (len != sizeof(*eth_hdr) + sizeof(*eapol_hdr) +
-           ntohs(eapol_hdr->length)) {
+           be_to_host16(eapol_hdr->length)) {
                wpa_printf(MSG_MSGDUMP, "KAY: EAPOL MPDU is invalid: (%lu-%lu)",
                           (unsigned long) len,
-                          (unsigned long) ntohs(eapol_hdr->length));
+                          (unsigned long) be_to_host16(eapol_hdr->length));
                return;
        }
 
@@ -3106,7 +3001,7 @@ static void kay_l2_receive(void *ctx, const u8 *src_addr, const u8 *buf,
                           eapol_hdr->version);
                return;
        }
-       if (ntohs(eth_hdr->ethertype) != ETH_P_PAE ||
+       if (be_to_host16(eth_hdr->ethertype) != ETH_P_PAE ||
            eapol_hdr->type != IEEE802_1X_TYPE_EAPOL_MKA)
                return;
 
@@ -3147,7 +3042,7 @@ ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
 
        os_strlcpy(kay->if_name, ifname, IFNAMSIZ);
        os_memcpy(kay->actor_sci.addr, addr, ETH_ALEN);
-       kay->actor_sci.port = 0x0001;
+       kay->actor_sci.port = host_to_be16(0x0001);
        kay->actor_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
 
        /* While actor acts as a key server, shall distribute sakey */
@@ -3192,7 +3087,7 @@ ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
        wpa_printf(MSG_DEBUG, "KaY: secy init macsec done");
 
        /* init CP */
-       kay->cp = ieee802_1x_kay_alloc_cp_sm(kay);
+       kay->cp = ieee802_1x_cp_sm_init(kay);
        if (kay->cp == NULL) {
                ieee802_1x_kay_deinit(kay);
                return NULL;
@@ -3314,7 +3209,7 @@ ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn,
        default:
                participant->is_obliged_key_server = FALSE;
                participant->can_be_key_server = TRUE;
-               participant->is_key_server = FALSE;
+               participant->is_key_server = TRUE;
                participant->is_elected = FALSE;
                break;
        }
@@ -3335,9 +3230,8 @@ ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn,
        participant->retry_count = 0;
        participant->kay = kay;
 
-       if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
+       if (!reset_participant_mi(participant))
                goto fail;
-       participant->mn = 0;
 
        participant->lrx = FALSE;
        participant->ltx = FALSE;
@@ -3422,6 +3316,7 @@ ieee802_1x_kay_delete_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn)
                return;
        }
 
+       eloop_cancel_timeout(ieee802_1x_participant_timer, participant, NULL);
        dl_list_del(&participant->list);
 
        /* remove live peer */
@@ -3510,14 +3405,15 @@ ieee802_1x_kay_new_sak(struct ieee802_1x_kay *kay)
  * ieee802_1x_kay_change_cipher_suite -
  */
 int
-ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay, int cs_index)
+ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay,
+                                  unsigned int cs_index)
 {
        struct ieee802_1x_mka_participant *participant;
 
        if (!kay)
                return -1;
 
-       if ((unsigned int) cs_index >= CS_TABLE_SIZE) {
+       if (cs_index >= CS_TABLE_SIZE) {
                wpa_printf(MSG_ERROR,
                           "KaY: Configured cipher suite index is out of range");
                return -1;
index 064417e..afbaa33 100644 (file)
@@ -14,7 +14,6 @@
 #include "common/ieee802_1x_defs.h"
 
 struct macsec_init_params;
-struct ieee802_1x_cp_conf;
 
 #define MI_LEN                 12
 #define MAX_KEY_LEN            32  /* 32 bytes, 256 bits */
@@ -32,7 +31,7 @@ struct ieee802_1x_mka_ki {
 
 struct ieee802_1x_mka_sci {
        u8 addr[ETH_ALEN];
-       u16 port;
+       be16 port;
 };
 
 struct mka_key {
@@ -48,8 +47,6 @@ struct mka_key_name {
 enum mka_created_mode {
        PSK,
        EAP_EXCHANGE,
-       DISTRIBUTED,
-       CACHED,
 };
 
 struct ieee802_1x_kay_ctx {
@@ -61,7 +58,7 @@ struct ieee802_1x_kay_ctx {
        int (*macsec_deinit)(void *ctx);
        int (*enable_protect_frames)(void *ctx, Boolean enabled);
        int (*set_replay_protect)(void *ctx, Boolean enabled, u32 window);
-       int (*set_current_cipher_suite)(void *ctx, const u8 *cs, size_t cs_len);
+       int (*set_current_cipher_suite)(void *ctx, u64 cs);
        int (*enable_controlled_port)(void *ctx, Boolean enabled);
        int (*get_receive_lowest_pn)(void *ctx, u32 channel, u8 an,
                                     u32 *lowest_pn);
@@ -126,7 +123,7 @@ struct ieee802_1x_kay {
        Boolean is_obliged_key_server;
        char if_name[IFNAMSIZ];
 
-       int macsec_csindex;  /*  MACsec cipher suite table index */
+       unsigned int macsec_csindex;  /* MACsec cipher suite table index */
        int mka_algindex;  /* MKA alg table index */
 
        u32 dist_kn;
@@ -171,7 +168,7 @@ void ieee802_1x_kay_mka_participate(struct ieee802_1x_kay *kay,
                                    Boolean status);
 int ieee802_1x_kay_new_sak(struct ieee802_1x_kay *kay);
 int ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay,
-                                      int cs_index);
+                                      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,
@@ -188,7 +185,5 @@ int ieee802_1x_kay_enable_tx_sas(struct ieee802_1x_kay *kay,
 int ieee802_1x_kay_enable_rx_sas(struct ieee802_1x_kay *kay,
                                 struct ieee802_1x_mka_ki *lki);
 int ieee802_1x_kay_enable_new_info(struct ieee802_1x_kay *kay);
-int ieee802_1x_kay_cp_conf(struct ieee802_1x_kay *kay,
-                          struct ieee802_1x_cp_conf *pconf);
 
 #endif /* IEEE802_1X_KAY_H */
index bdad3a5..622282e 100644 (file)
@@ -38,7 +38,7 @@ struct ieee802_1x_kay;
 
 struct ieee802_1x_mka_peer_id {
        u8 mi[MI_LEN];
-       u32 mn;
+       be32 mn;
 };
 
 struct ieee802_1x_kay_peer {
@@ -49,21 +49,11 @@ struct ieee802_1x_kay_peer {
        Boolean is_key_server;
        u8 key_server_priority;
        Boolean macsec_desired;
-       enum macsec_cap macsec_capbility;
+       enum macsec_cap macsec_capability;
        Boolean sak_used;
        struct dl_list list;
 };
 
-struct key_conf {
-       u8 *key;
-       struct ieee802_1x_mka_ki ki;
-       enum confidentiality_offset offset;
-       u8 an;
-       Boolean tx;
-       Boolean rx;
-       int key_len; /* unit: byte */
-};
-
 struct data_key {
        u8 *key;
        int key_len;
@@ -147,7 +137,7 @@ struct receive_sa {
 };
 
 struct macsec_ciphersuite {
-       u8 id[CS_ID_LEN];
+       u64 id;
        char name[32];
        enum macsec_cap capable;
        int sak_len; /* unit: byte */
@@ -241,48 +231,48 @@ struct ieee802_1x_mka_participant {
 
 struct ieee802_1x_mka_hdr {
        /* octet 1 */
-       u32 type:8;
+       u8 type;
        /* octet 2 */
-       u32 reserve:8;
+       u8 reserve;
        /* octet 3 */
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-       u32 length:4;
-       u32 reserve1:4;
+       u8 length:4;
+       u8 reserve1:4;
 #elif __BYTE_ORDER == __BIG_ENDIAN
-       u32 reserve1:4;
-       u32 length:4;
+       u8 reserve1:4;
+       u8 length:4;
 #else
 #error "Please fix <bits/endian.h>"
 #endif
        /* octet 4 */
-       u32 length1:8;
+       u8 length1;
 };
 
 #define MKA_HDR_LEN sizeof(struct ieee802_1x_mka_hdr)
 
 struct ieee802_1x_mka_basic_body {
        /* octet 1 */
-       u32 version:8;
+       u8 version;
        /* octet 2 */
-       u32 priority:8;
+       u8 priority;
        /* octet 3 */
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-       u32 length:4;
-       u32 macsec_capbility:2;
-       u32 macsec_desired:1;
-       u32 key_server:1;
+       u8 length:4;
+       u8 macsec_capability:2;
+       u8 macsec_desired:1;
+       u8 key_server:1;
 #elif __BYTE_ORDER == __BIG_ENDIAN
-       u32 key_server:1;
-       u32 macsec_desired:1;
-       u32 macsec_capbility:2;
-       u32 length:4;
+       u8 key_server:1;
+       u8 macsec_desired:1;
+       u8 macsec_capability:2;
+       u8 length:4;
 #endif
        /* octet 4 */
-       u32 length1:8;
+       u8 length1;
 
        struct ieee802_1x_mka_sci actor_sci;
        u8 actor_mi[MI_LEN];
-       u32 actor_mn;
+       be32 actor_mn;
        u8 algo_agility[4];
 
        /* followed by CAK Name*/
@@ -291,19 +281,19 @@ struct ieee802_1x_mka_basic_body {
 
 struct ieee802_1x_mka_peer_body {
        /* octet 1 */
-       u32 type:8;
+       u8 type;
        /* octet 2 */
-       u32 reserve:8;
+       u8 reserve;
        /* octet 3 */
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-       u32 length:4;
-       u32 reserve1:4;
+       u8 length:4;
+       u8 reserve1:4;
 #elif __BYTE_ORDER == __BIG_ENDIAN
-       u32 reserve1:4;
-       u32 length:4;
+       u8 reserve1:4;
+       u8 length:4;
 #endif
        /* octet 4 */
-       u32 length1:8;
+       u8 length1;
 
        u8 peer[0];
        /* followed by Peers */
@@ -311,83 +301,83 @@ struct ieee802_1x_mka_peer_body {
 
 struct ieee802_1x_mka_sak_use_body {
        /* octet 1 */
-       u32 type:8;
+       u8 type;
        /* octet 2 */
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-       u32 orx:1;
-       u32 otx:1;
-       u32 oan:2;
-       u32 lrx:1;
-       u32 ltx:1;
-       u32 lan:2;
+       u8 orx:1;
+       u8 otx:1;
+       u8 oan:2;
+       u8 lrx:1;
+       u8 ltx:1;
+       u8 lan:2;
 #elif __BYTE_ORDER == __BIG_ENDIAN
-       u32 lan:2;
-       u32 ltx:1;
-       u32 lrx:1;
-       u32 oan:2;
-       u32 otx:1;
-       u32 orx:1;
+       u8 lan:2;
+       u8 ltx:1;
+       u8 lrx:1;
+       u8 oan:2;
+       u8 otx:1;
+       u8 orx:1;
 #endif
 
        /* octet 3 */
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-       u32 length:4;
-       u32 delay_protect:1;
-       u32 reserve:1;
-       u32 prx:1;
-       u32 ptx:1;
+       u8 length:4;
+       u8 delay_protect:1;
+       u8 reserve:1;
+       u8 prx:1;
+       u8 ptx:1;
 #elif __BYTE_ORDER == __BIG_ENDIAN
-       u32 ptx:1;
-       u32 prx:1;
-       u32 reserve:1;
-       u32 delay_protect:1;
-       u32 length:4;
+       u8 ptx:1;
+       u8 prx:1;
+       u8 reserve:1;
+       u8 delay_protect:1;
+       u8 length:4;
 #endif
 
        /* octet 4 */
-       u32 length1:8;
+       u8 length1;
 
        /* octet 5 - 16 */
        u8 lsrv_mi[MI_LEN];
        /* octet 17 - 20 */
-       u32 lkn;
+       be32 lkn;
        /* octet 21 - 24 */
-       u32 llpn;
+       be32 llpn;
 
        /* octet 25 - 36 */
        u8 osrv_mi[MI_LEN];
        /* octet 37 - 40 */
-       u32 okn;
+       be32 okn;
        /* octet 41 - 44 */
-       u32 olpn;
+       be32 olpn;
 };
 
 
 struct ieee802_1x_mka_dist_sak_body {
        /* octet 1 */
-       u32 type:8;
+       u8 type;
        /* octet 2 */
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-       u32 reserve:4;
-       u32 confid_offset:2;
-       u32 dan:2;
+       u8 reserve:4;
+       u8 confid_offset:2;
+       u8 dan:2;
 #elif __BYTE_ORDER == __BIG_ENDIAN
-       u32 dan:2;
-       u32 confid_offset:2;
-       u32 reserve:4;
+       u8 dan:2;
+       u8 confid_offset:2;
+       u8 reserve:4;
 #endif
        /* octet 3 */
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-       u32 length:4;
-       u32 reserve1:4;
+       u8 length:4;
+       u8 reserve1:4;
 #elif __BYTE_ORDER == __BIG_ENDIAN
-       u32 reserve1:4;
-       u32 length:4;
+       u8 reserve1:4;
+       u8 length:4;
 #endif
        /* octet 4 */
-       u32 length1:8;
+       u8 length1;
        /* octet 5 - 8 */
-       u32 kn;
+       be32 kn;
 
        /* for GCM-AES-128: octet 9-32: SAK
         * for other cipher suite: octet 9-16: cipher suite id, octet 17-: SAK
@@ -398,19 +388,19 @@ struct ieee802_1x_mka_dist_sak_body {
 
 struct ieee802_1x_mka_icv_body {
        /* octet 1 */
-       u32 type:8;
+       u8 type;
        /* octet 2 */
-       u32 reserve:8;
+       u8 reserve;
        /* octet 3 */
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-       u32 length:4;
-       u32 reserve1:4;
+       u8 length:4;
+       u8 reserve1:4;
 #elif __BYTE_ORDER == __BIG_ENDIAN
-       u32 reserve1:4;
-       u32 length:4;
+       u8 reserve1:4;
+       u8 length:4;
 #endif
        /* octet 4 */
-       u32 length1:8;
+       u8 length1;
 
        /* octet 5 - */
        u8 icv[0];
index fbe05dc..2d12911 100644 (file)
@@ -65,8 +65,7 @@ int secy_cp_control_replay(struct ieee802_1x_kay *kay, Boolean enabled, u32 win)
 }
 
 
-int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay,
-                                        const u8 *cs, size_t cs_len)
+int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay, u64 cs)
 {
        struct ieee802_1x_kay_ctx *ops;
 
@@ -82,7 +81,7 @@ int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay,
                return -1;
        }
 
-       return ops->set_current_cipher_suite(ops->ctx, cs, cs_len);
+       return ops->set_current_cipher_suite(ops->ctx, cs);
 }
 
 
index 295b823..f5057ee 100644 (file)
@@ -26,8 +26,7 @@ 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_replay(struct ieee802_1x_kay *kay, Boolean flag, u32 win);
-int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay,
-                                        const u8 *cs, size_t cs_len);
+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);
index 1ebfd11..407e4f8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * RADIUS message processing
- * Copyright (c) 2002-2009, 2011-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2011-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -173,6 +173,8 @@ static const struct radius_attr_type radius_attrs[] =
        { RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST },
        { RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP },
        { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 },
+       { RADIUS_ATTR_SERVICE_TYPE, "Service-Type", RADIUS_ATTR_INT32 },
+       { RADIUS_ATTR_FRAMED_IP_ADDRESS, "Framed-IP-Address", RADIUS_ATTR_IP },
        { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 },
        { RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT },
        { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST },
@@ -214,6 +216,7 @@ static const struct radius_attr_type radius_attrs[] =
          RADIUS_ATTR_INT32 },
        { RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
          RADIUS_ATTR_INT32 },
+       { RADIUS_ATTR_EGRESS_VLANID, "EGRESS-VLANID", RADIUS_ATTR_HEXDUMP },
        { RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 },
        { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
        { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
@@ -535,7 +538,8 @@ int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
 
 
 int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
-                             size_t secret_len)
+                             size_t secret_len,
+                             int require_message_authenticator)
 {
        const u8 *addr[4];
        size_t len[4];
@@ -574,7 +578,11 @@ int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
        }
 
        if (attr == NULL) {
-               /* Message-Authenticator is MAY; not required */
+               if (require_message_authenticator) {
+                       wpa_printf(MSG_WARNING,
+                                  "Missing Message-Authenticator attribute in RADIUS message");
+                       return 1;
+               }
                return 0;
        }
 
@@ -703,7 +711,7 @@ struct radius_msg * radius_msg_parse(const u8 *data, size_t len)
 
                attr = (struct radius_attr_hdr *) pos;
 
-               if (pos + attr->length > end || attr->length < sizeof(*attr))
+               if (attr->length > end - pos || attr->length < sizeof(*attr))
                        goto fail;
 
                /* TODO: check that attr->length is suitable for attr->type */
@@ -815,8 +823,9 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
                os_memcpy(msg->hdr->authenticator, req_auth,
                          sizeof(msg->hdr->authenticator));
        }
-       hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
-                wpabuf_len(msg->buf), auth);
+       if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+                    wpabuf_len(msg->buf), auth) < 0)
+               return 1;
        os_memcpy(attr + 1, orig, MD5_MAC_LEN);
        if (req_auth) {
                os_memcpy(msg->hdr->authenticator, orig_authenticator,
@@ -859,8 +868,8 @@ int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
        len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
        addr[3] = secret;
        len[3] = secret_len;
-       md5_vector(4, addr, len, hash);
-       if (os_memcmp_const(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
+       if (md5_vector(4, addr, len, hash) < 0 ||
+           os_memcmp_const(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
                wpa_printf(MSG_INFO, "Response Authenticator invalid!");
                return 1;
        }
@@ -892,25 +901,11 @@ int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
 
 /* Create Request Authenticator. The value should be unique over the lifetime
  * of the shared secret between authenticator and authentication server.
- * Use one-way MD5 hash calculated from current timestamp and some data given
- * by the caller. */
-void radius_msg_make_authenticator(struct radius_msg *msg,
-                                  const u8 *data, size_t len)
+ */
+int radius_msg_make_authenticator(struct radius_msg *msg)
 {
-       struct os_time tv;
-       long int l;
-       const u8 *addr[3];
-       size_t elen[3];
-
-       os_get_time(&tv);
-       l = os_random();
-       addr[0] = (u8 *) &tv;
-       elen[0] = sizeof(tv);
-       addr[1] = data;
-       elen[1] = len;
-       addr[2] = (u8 *) &l;
-       elen[2] = sizeof(l);
-       md5_vector(3, addr, elen, msg->hdr->authenticator);
+       return os_get_random((u8 *) &msg->hdr->authenticator,
+                            sizeof(msg->hdr->authenticator));
 }
 
 
@@ -1028,7 +1023,10 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len,
                        addr[1] = pos - MD5_MAC_LEN;
                        elen[1] = MD5_MAC_LEN;
                }
-               md5_vector(first ? 3 : 2, addr, elen, hash);
+               if (md5_vector(first ? 3 : 2, addr, elen, hash) < 0) {
+                       os_free(plain);
+                       return NULL;
+               }
                first = 0;
 
                for (i = 0; i < MD5_MAC_LEN; i++)
@@ -1210,7 +1208,11 @@ int radius_msg_add_mppe_keys(struct radius_msg *msg,
        vhdr = (struct radius_attr_vendor *) pos;
        vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY;
        pos = (u8 *) (vhdr + 1);
-       salt = os_random() | 0x8000;
+       if (os_get_random((u8 *) &salt, sizeof(salt)) < 0) {
+               os_free(buf);
+               return 0;
+       }
+       salt |= 0x8000;
        WPA_PUT_BE16(pos, salt);
        pos += 2;
        encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret,
@@ -1422,12 +1424,30 @@ struct radius_tunnel_attrs {
 };
 
 
+static int cmp_int(const void *a, const void *b)
+{
+       int x, y;
+
+       x = *((int *) a);
+       y = *((int *) b);
+       return (x - y);
+}
+
+
 /**
  * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
+ * The k tagged vlans found are sorted by vlan_id and stored in the first k
+ * items of tagged.
+ *
  * @msg: RADIUS message
- * Returns: VLAN ID for the first tunnel configuration or 0 if none is found
+ * @untagged: Pointer to store untagged vid
+ * @numtagged: Size of tagged
+ * @tagged: Pointer to store tagged list
+ *
+ * Returns: 0 if neither tagged nor untagged configuration is found, 1 otherwise
  */
-int radius_msg_get_vlanid(struct radius_msg *msg)
+int radius_msg_get_vlanid(struct radius_msg *msg, int *untagged, int numtagged,
+                         int *tagged)
 {
        struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun;
        size_t i;
@@ -1435,8 +1455,12 @@ int radius_msg_get_vlanid(struct radius_msg *msg)
        const u8 *data;
        char buf[10];
        size_t dlen;
+       int j, taggedidx = 0, vlan_id;
 
        os_memset(&tunnel, 0, sizeof(tunnel));
+       for (j = 0; j < numtagged; j++)
+               tagged[j] = 0;
+       *untagged = 0;
 
        for (i = 0; i < msg->attr_used; i++) {
                attr = radius_get_attr_hdr(msg, i);
@@ -1473,21 +1497,44 @@ int radius_msg_get_vlanid(struct radius_msg *msg)
                                break;
                        os_memcpy(buf, data, dlen);
                        buf[dlen] = '\0';
+                       vlan_id = atoi(buf);
+                       if (vlan_id <= 0)
+                               break;
                        tun->tag_used++;
-                       tun->vlanid = atoi(buf);
+                       tun->vlanid = vlan_id;
+                       break;
+               case RADIUS_ATTR_EGRESS_VLANID: /* RFC 4675 */
+                       if (attr->length != 6)
+                               break;
+                       vlan_id = WPA_GET_BE24(data + 1);
+                       if (vlan_id <= 0)
+                               break;
+                       if (data[0] == 0x32)
+                               *untagged = vlan_id;
+                       else if (data[0] == 0x31 && tagged &&
+                                taggedidx < numtagged)
+                               tagged[taggedidx++] = vlan_id;
                        break;
                }
        }
 
+       /* Use tunnel with the lowest tag for untagged VLAN id */
        for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) {
                tun = &tunnel[i];
                if (tun->tag_used &&
                    tun->type == RADIUS_TUNNEL_TYPE_VLAN &&
                    tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 &&
-                   tun->vlanid > 0)
-                       return tun->vlanid;
+                   tun->vlanid > 0) {
+                       *untagged = tun->vlanid;
+                       break;
+               }
        }
 
+       if (taggedidx)
+               qsort(tagged, taggedidx, sizeof(int), cmp_int);
+
+       if (*untagged > 0 || taggedidx)
+               return 1;
        return 0;
 }
 
@@ -1669,3 +1716,14 @@ u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs)
 
        return 0;
 }
+
+
+int radius_gen_session_id(u8 *id, size_t len)
+{
+       /*
+        * Acct-Session-Id and Acct-Multi-Session-Id should be globally and
+        * temporarily unique. A high quality random number is required
+        * therefore. This could be be improved by switching to a GUID.
+        */
+       return os_get_random(id, len);
+}
index 5977339..cd510d2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * RADIUS message processing
- * Copyright (c) 2002-2009, 2012, 2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012, 2014-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -52,6 +52,8 @@ enum { RADIUS_ATTR_USER_NAME = 1,
        RADIUS_ATTR_USER_PASSWORD = 2,
        RADIUS_ATTR_NAS_IP_ADDRESS = 4,
        RADIUS_ATTR_NAS_PORT = 5,
+       RADIUS_ATTR_SERVICE_TYPE = 6,
+       RADIUS_ATTR_FRAMED_IP_ADDRESS = 8,
        RADIUS_ATTR_FRAMED_MTU = 12,
        RADIUS_ATTR_REPLY_MESSAGE = 18,
        RADIUS_ATTR_STATE = 24,
@@ -79,6 +81,7 @@ enum { RADIUS_ATTR_USER_NAME = 1,
        RADIUS_ATTR_ACCT_INPUT_GIGAWORDS = 52,
        RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS = 53,
        RADIUS_ATTR_EVENT_TIMESTAMP = 55,
+       RADIUS_ATTR_EGRESS_VLANID = 56,
        RADIUS_ATTR_NAS_PORT_TYPE = 61,
        RADIUS_ATTR_TUNNEL_TYPE = 64,
        RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65,
@@ -108,6 +111,9 @@ enum { RADIUS_ATTR_USER_NAME = 1,
 };
 
 
+/* Service-Type values (RFC 2865, 5.6) */
+#define RADIUS_SERVICE_TYPE_FRAMED 2
+
 /* Termination-Action */
 #define RADIUS_TERMINATION_ACTION_DEFAULT 0
 #define RADIUS_TERMINATION_ACTION_RADIUS_REQUEST 1
@@ -236,7 +242,8 @@ void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
 int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
                               size_t secret_len);
 int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
-                              size_t secret_len);
+                             size_t secret_len,
+                             int require_message_authenticator);
 struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type,
                                             const u8 *data, size_t data_len);
 struct radius_msg * radius_msg_parse(const u8 *data, size_t len);
@@ -250,8 +257,7 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
                               size_t secret_len, const u8 *req_auth);
 int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
                         u8 type);
-void radius_msg_make_authenticator(struct radius_msg *msg,
-                                  const u8 *data, size_t len);
+int radius_msg_make_authenticator(struct radius_msg *msg);
 struct radius_ms_mppe_keys *
 radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
                       const u8 *secret, size_t secret_len);
@@ -274,7 +280,8 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
                                  const u8 *data, size_t data_len,
                                  const u8 *secret, size_t secret_len);
 int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
-int radius_msg_get_vlanid(struct radius_msg *msg);
+int radius_msg_get_vlanid(struct radius_msg *msg, int *untagged, int numtagged,
+                         int *tagged);
 char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
                                      const u8 *secret, size_t secret_len,
                                      struct radius_msg *sent_msg, size_t n);
@@ -319,4 +326,6 @@ int radius_copy_class(struct radius_class_data *dst,
 
 u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs);
 
+int radius_gen_session_id(u8 *id, size_t len);
+
 #endif /* RADIUS_H */
index 693f61e..06c804d 100644 (file)
@@ -226,6 +226,16 @@ struct radius_client_data {
         * next_radius_identifier - Next RADIUS message identifier to use
         */
        u8 next_radius_identifier;
+
+       /**
+        * interim_error_cb - Interim accounting error callback
+        */
+       void (*interim_error_cb)(const u8 *addr, void *ctx);
+
+       /**
+        * interim_error_cb_ctx - interim_error_cb() context data
+        */
+       void *interim_error_cb_ctx;
 };
 
 
@@ -297,6 +307,25 @@ int radius_client_register(struct radius_client_data *radius,
 }
 
 
+/**
+ * radius_client_set_interim_erro_cb - Register an interim acct error callback
+ * @radius: RADIUS client context from radius_client_init()
+ * @addr: Station address from the failed message
+ * @cb: Handler for interim accounting errors
+ * @ctx: Context pointer for handler callbacks
+ *
+ * This function is used to register a handler for processing failed
+ * transmission attempts of interim accounting update messages.
+ */
+void radius_client_set_interim_error_cb(struct radius_client_data *radius,
+                                       void (*cb)(const u8 *addr, void *ctx),
+                                       void *ctx)
+{
+       radius->interim_error_cb = cb;
+       radius->interim_error_cb_ctx = ctx;
+}
+
+
 /*
  * Returns >0 if message queue was flushed (i.e., the message that triggered
  * the error is not available anymore)
@@ -308,7 +337,7 @@ static int radius_client_handle_send_error(struct radius_client_data *radius,
        int _errno = errno;
        wpa_printf(MSG_INFO, "send[RADIUS,s=%d]: %s", s, strerror(errno));
        if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
-           _errno == EBADF || _errno == ENETUNREACH) {
+           _errno == EBADF || _errno == ENETUNREACH || _errno == EACCES) {
                hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
                               HOSTAPD_LEVEL_INFO,
                               "Send failed - maybe interface status changed -"
@@ -336,6 +365,8 @@ static int radius_client_retransmit(struct radius_client_data *radius,
        int s;
        struct wpabuf *buf;
        size_t prev_num_msgs;
+       u8 *acct_delay_time;
+       size_t acct_delay_time_len;
 
        if (entry->msg_type == RADIUS_ACCT ||
            entry->msg_type == RADIUS_ACCT_INTERIM) {
@@ -371,12 +402,52 @@ static int radius_client_retransmit(struct radius_client_data *radius,
                        conf->auth_server->retransmissions++;
                }
        }
+
+       if (entry->msg_type == RADIUS_ACCT_INTERIM) {
+               wpa_printf(MSG_DEBUG,
+                          "RADIUS: Failed to transmit interim accounting update to "
+                          MACSTR " - drop message and request a new update",
+                          MAC2STR(entry->addr));
+               if (radius->interim_error_cb)
+                       radius->interim_error_cb(entry->addr,
+                                                radius->interim_error_cb_ctx);
+               return 1;
+       }
+
        if (s < 0) {
                wpa_printf(MSG_INFO,
                           "RADIUS: No valid socket for retransmission");
                return 1;
        }
 
+       if (entry->msg_type == RADIUS_ACCT &&
+           radius_msg_get_attr_ptr(entry->msg, RADIUS_ATTR_ACCT_DELAY_TIME,
+                                   &acct_delay_time, &acct_delay_time_len,
+                                   NULL) == 0 &&
+           acct_delay_time_len == 4) {
+               struct radius_hdr *hdr;
+               u32 delay_time;
+
+               /*
+                * Need to assign a new identifier since attribute contents
+                * changes.
+                */
+               hdr = radius_msg_get_hdr(entry->msg);
+               hdr->identifier = radius_client_get_id(radius);
+
+               /* Update Acct-Delay-Time to show wait time in queue */
+               delay_time = now - entry->first_try;
+               WPA_PUT_BE32(acct_delay_time, delay_time);
+
+               wpa_printf(MSG_DEBUG,
+                          "RADIUS: Updated Acct-Delay-Time to %u for retransmission",
+                          delay_time);
+               radius_msg_finish_acct(entry->msg, entry->shared_secret,
+                                      entry->shared_secret_len);
+               if (radius->conf->msg_dumps)
+                       radius_msg_dump(entry->msg);
+       }
+
        /* retransmit; remove entry if too many attempts */
        entry->attempts++;
        hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
@@ -407,7 +478,6 @@ static int radius_client_retransmit(struct radius_client_data *radius,
 static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
 {
        struct radius_client_data *radius = eloop_ctx;
-       struct hostapd_radius_servers *conf = radius->conf;
        struct os_reltime now;
        os_time_t first;
        struct radius_msg_list *entry, *prev, *tmp;
@@ -476,10 +546,10 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
                               (long int) (first - now.sec));
        }
 
-       if (auth_failover && conf->num_auth_servers > 1)
+       if (auth_failover)
                radius_client_auth_failover(radius);
 
-       if (acct_failover && conf->num_acct_servers > 1)
+       if (acct_failover)
                radius_client_acct_failover(radius);
 }
 
@@ -625,39 +695,6 @@ static void radius_client_list_add(struct radius_client_data *radius,
 }
 
 
-static void radius_client_list_del(struct radius_client_data *radius,
-                                  RadiusType msg_type, const u8 *addr)
-{
-       struct radius_msg_list *entry, *prev, *tmp;
-
-       if (addr == NULL)
-               return;
-
-       entry = radius->msgs;
-       prev = NULL;
-       while (entry) {
-               if (entry->msg_type == msg_type &&
-                   os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
-                       if (prev)
-                               prev->next = entry->next;
-                       else
-                               radius->msgs = entry->next;
-                       tmp = entry;
-                       entry = entry->next;
-                       hostapd_logger(radius->ctx, addr,
-                                      HOSTAPD_MODULE_RADIUS,
-                                      HOSTAPD_LEVEL_DEBUG,
-                                      "Removing matching RADIUS message");
-                       radius_client_msg_free(tmp);
-                       radius->num_msgs--;
-                       continue;
-               }
-               prev = entry;
-               entry = entry->next;
-       }
-}
-
-
 /**
  * radius_client_send - Send a RADIUS request
  * @radius: RADIUS client context from radius_client_init()
@@ -669,16 +706,19 @@ static void radius_client_list_del(struct radius_client_data *radius,
  * This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or
  * accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference
  * between accounting and interim accounting messages is that the interim
- * message will override any pending interim accounting updates while a new
- * accounting message does not remove any pending messages.
+ * message will not be retransmitted. Instead, a callback is used to indicate
+ * that the transmission failed for the specific station @addr so that a new
+ * interim accounting update message can be generated with up-to-date session
+ * data instead of trying to resend old information.
  *
  * The message is added on the retransmission queue and will be retransmitted
  * automatically until a response is received or maximum number of retries
- * (RADIUS_CLIENT_MAX_RETRIES) is reached.
+ * (RADIUS_CLIENT_MAX_RETRIES) is reached. No such retries are used with
+ * RADIUS_ACCT_INTERIM, i.e., such a pending message is removed from the queue
+ * automatically on transmission failure.
  *
  * The related device MAC address can be used to identify pending messages that
- * can be removed with radius_client_flush_auth() or with interim accounting
- * updates.
+ * can be removed with radius_client_flush_auth().
  */
 int radius_client_send(struct radius_client_data *radius,
                       struct radius_msg *msg, RadiusType msg_type,
@@ -691,11 +731,6 @@ int radius_client_send(struct radius_client_data *radius,
        int s, res;
        struct wpabuf *buf;
 
-       if (msg_type == RADIUS_ACCT_INTERIM) {
-               /* Remove any pending interim acct update for the same STA. */
-               radius_client_list_del(radius, msg_type, addr);
-       }
-
        if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
                if (conf->acct_server && radius->acct_sock < 0)
                        radius_client_init_acct(radius);
@@ -1015,6 +1050,9 @@ radius_change_server(struct radius_client_data *radius,
        int sel_sock;
        struct radius_msg_list *entry;
        struct hostapd_radius_servers *conf = radius->conf;
+       struct sockaddr_in disconnect_addr = {
+               .sin_family = AF_UNSPEC,
+       };
 
        hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
                       HOSTAPD_LEVEL_INFO,
@@ -1023,6 +1061,12 @@ radius_change_server(struct radius_client_data *radius,
                       hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
                       nserv->port);
 
+       if (oserv && oserv == nserv) {
+               /* Reconnect to same server, flush */
+               if (auth)
+                       radius_client_flush(radius, 1);
+       }
+
        if (oserv && oserv != nserv &&
            (nserv->shared_secret_len != oserv->shared_secret_len ||
             os_memcmp(nserv->shared_secret, oserv->shared_secret,
@@ -1125,6 +1169,11 @@ 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;
@@ -1587,11 +1636,16 @@ static int radius_client_dump_acct_server(char *buf, size_t buflen,
 int radius_client_get_mib(struct radius_client_data *radius, char *buf,
                          size_t buflen)
 {
-       struct hostapd_radius_servers *conf = radius->conf;
+       struct hostapd_radius_servers *conf;
        int i;
        struct hostapd_radius_server *serv;
        int count = 0;
 
+       if (!radius)
+               return 0;
+
+       conf = radius->conf;
+
        if (conf->auth_servers) {
                for (i = 0; i < conf->num_auth_servers; i++) {
                        serv = &conf->auth_servers[i];
index 3db16aa..8ca0874 100644 (file)
@@ -241,6 +241,9 @@ int radius_client_register(struct radius_client_data *radius,
                            const u8 *shared_secret, size_t shared_secret_len,
                            void *data),
                           void *data);
+void radius_client_set_interim_error_cb(struct radius_client_data *radius,
+                                       void (*cb)(const u8 *addr, void *ctx),
+                                       void *ctx);
 int radius_client_send(struct radius_client_data *radius,
                       struct radius_msg *msg,
                       RadiusType msg_type, const u8 *addr);
index b7d991b..8a3d7e0 100644 (file)
@@ -23,6 +23,7 @@ struct radius_das_data {
        struct hostapd_ip_addr client_addr;
        unsigned int time_window;
        int require_event_timestamp;
+       int require_message_authenticator;
        void *ctx;
        enum radius_das_res (*disconnect)(void *ctx,
                                          struct radius_das_attrs *attr);
@@ -234,9 +235,11 @@ static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
                radius_msg_dump(msg);
 
        if (radius_msg_verify_das_req(msg, das->shared_secret,
-                                      das->shared_secret_len)) {
-               wpa_printf(MSG_DEBUG, "DAS: Invalid authenticator in packet "
-                          "from %s:%d - drop", abuf, from_port);
+                                      das->shared_secret_len,
+                                      das->require_message_authenticator)) {
+               wpa_printf(MSG_DEBUG,
+                          "DAS: Invalid authenticator or Message-Authenticator in packet from %s:%d - drop",
+                          abuf, from_port);
                goto fail;
        }
 
@@ -362,6 +365,8 @@ radius_das_init(struct radius_das_conf *conf)
 
        das->time_window = conf->time_window;
        das->require_event_timestamp = conf->require_event_timestamp;
+       das->require_message_authenticator =
+               conf->require_message_authenticator;
        das->ctx = conf->ctx;
        das->disconnect = conf->disconnect;
 
index ce731d4..9863fdc 100644 (file)
@@ -44,6 +44,7 @@ struct radius_das_conf {
        const struct hostapd_ip_addr *client_addr;
        unsigned int time_window;
        int require_event_timestamp;
+       int require_message_authenticator;
        void *ctx;
        enum radius_das_res (*disconnect)(void *ctx,
                                          struct radius_das_attrs *attr);
index ef7b683..3d8d122 100644 (file)
@@ -15,7 +15,7 @@
 #include "wpa_i.h"
 #include "pmksa_cache.h"
 
-#ifdef IEEE8021X_EAPOL
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
 
 static const int pmksa_cache_max_entries = 32;
 
@@ -109,6 +109,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
  * @pmk: The new pairwise master key
  * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
+ * @pmkid: Calculated PMKID
  * @kck: Key confirmation key or %NULL if not yet derived
  * @kck_len: KCK length in bytes
  * @aa: Authenticator address
@@ -124,13 +125,13 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
  */
 struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
-               const u8 *kck, size_t kck_len,
+               const u8 *pmkid, const u8 *kck, size_t kck_len,
                const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
 {
        struct rsn_pmksa_cache_entry *entry, *pos, *prev;
        struct os_reltime now;
 
-       if (pmk_len > PMK_LEN)
+       if (pmk_len > PMK_LEN_MAX)
                return NULL;
 
        if (wpa_key_mgmt_suite_b(akmp) && !kck)
@@ -141,7 +142,9 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
                return NULL;
        os_memcpy(entry->pmk, pmk, pmk_len);
        entry->pmk_len = pmk_len;
-       if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+       if (pmkid)
+               os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
+       else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
                rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
        else if (wpa_key_mgmt_suite_b(akmp))
                rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
@@ -344,7 +347,7 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
        struct rsn_pmksa_cache_entry *new_entry;
 
        new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
-                                   NULL, 0,
+                                   NULL, NULL, 0,
                                    aa, pmksa->sm->own_addr,
                                    old_entry->network_ctx, old_entry->akmp);
        if (new_entry == NULL)
index f8e040e..daede6d 100644 (file)
@@ -15,7 +15,7 @@
 struct rsn_pmksa_cache_entry {
        struct rsn_pmksa_cache_entry *next;
        u8 pmkid[PMKID_LEN];
-       u8 pmk[PMK_LEN];
+       u8 pmk[PMK_LEN_MAX];
        size_t pmk_len;
        os_time_t expiration;
        int akmp; /* WPA_KEY_MGMT_* */
@@ -44,7 +44,7 @@ enum pmksa_free_reason {
        PMKSA_EXPIRE,
 };
 
-#ifdef IEEE8021X_EAPOL
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
 
 struct rsn_pmksa_cache *
 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
@@ -57,7 +57,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
 int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
 struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
-               const u8 *kck, size_t kck_len,
+               const u8 *pmkid, const u8 *kck, size_t kck_len,
                const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
 struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
 void pmksa_cache_clear_current(struct wpa_sm *sm);
@@ -105,7 +105,7 @@ static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf,
 
 static inline struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
-               const u8 *kck, size_t kck_len,
+               const u8 *pmkid, const u8 *kck, size_t kck_len,
                const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
 {
        return NULL;
index c6534af..4c9a4fb 100644 (file)
@@ -18,7 +18,7 @@
 #include "wpa_i.h"
 
 
-#ifdef IEEE8021X_EAPOL
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
 
 #define PMKID_CANDIDATE_PRIO_SCAN 1000
 
@@ -93,7 +93,7 @@ static void rsn_preauth_eapol_cb(struct eapol_sm *eapol,
                        wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from pre-auth",
                                        pmk, pmk_len);
                        sm->pmk_len = pmk_len;
-                       pmksa_cache_add(sm->pmksa, pmk, pmk_len,
+                       pmksa_cache_add(sm->pmksa, pmk, pmk_len, NULL,
                                        NULL, 0,
                                        sm->preauth_bssid, sm->own_addr,
                                        sm->network_ctx,
@@ -538,4 +538,4 @@ int rsn_preauth_in_progress(struct wpa_sm *sm)
        return sm->preauth_eapol != NULL;
 }
 
-#endif /* IEEE8021X_EAPOL */
+#endif /* IEEE8021X_EAPOL && !CONFIG_NO_WPA */
index 277f066..8caf3ee 100644 (file)
@@ -11,7 +11,7 @@
 
 struct wpa_scan_results;
 
-#ifdef IEEE8021X_EAPOL
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
 
 void pmksa_candidate_free(struct wpa_sm *sm);
 int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
@@ -27,7 +27,7 @@ int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
                           int verbose);
 int rsn_preauth_in_progress(struct wpa_sm *sm);
 
-#else /* IEEE8021X_EAPOL */
+#else /* IEEE8021X_EAPOL && !CONFIG_NO_WPA */
 
 static inline void pmksa_candidate_free(struct wpa_sm *sm)
 {
@@ -74,6 +74,6 @@ static inline int rsn_preauth_in_progress(struct wpa_sm *sm)
        return 0;
 }
 
-#endif /* IEEE8021X_EAPOL */
+#endif /* IEEE8021X_EAPOL && !CONFIG_NO_WPA */
 
 #endif /* PREAUTH_H */
index 722c20a..e424168 100644 (file)
@@ -627,9 +627,15 @@ static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx)
         */
 
        if (peer->initiator) {
+               u8 addr[ETH_ALEN];
+
                wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR
                           " - try to renew", MAC2STR(peer->addr));
-               wpa_tdls_start(sm, peer->addr);
+               /* cache the peer address before do_teardown */
+               os_memcpy(addr, peer->addr, ETH_ALEN);
+               wpa_tdls_do_teardown(sm, peer,
+                                    WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+               wpa_tdls_start(sm, addr);
        } else {
                wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR
                           " - tear down", MAC2STR(peer->addr));
@@ -2170,6 +2176,14 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
                           "ignore TPK M2 from " MACSTR, MAC2STR(src_addr));
                return -1;
        }
+
+       if (peer->tpk_success) {
+               wpa_printf(MSG_INFO, "TDLS: Ignore incoming TPK M2 retry, from "
+                          MACSTR " as TPK M3 was already sent",
+                          MAC2STR(src_addr));
+               return 0;
+       }
+
        wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST);
 
        if (len < 3 + 2 + 1) {
@@ -2325,7 +2339,7 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
                    kde.ftie, sizeof(*ftie));
        ftie = (struct wpa_tdls_ftie *) kde.ftie;
 
-       if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) {
+       if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0) {
                wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M2 does "
                           "not match with FTIE SNonce used in TPK M1");
                /* Silently discard the frame */
@@ -2386,7 +2400,7 @@ skip_rsn:
        wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Confirm / "
                   "TPK Handshake Message 3");
        if (wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer) < 0)
-               goto error;
+               goto error_no_msg;
 
        if (!peer->tpk_success) {
                /*
@@ -2407,6 +2421,7 @@ skip_rsn:
 error:
        wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 1,
                            status);
+error_no_msg:
        wpa_tdls_disable_peer_link(sm, peer);
        return -1;
 }
@@ -2503,13 +2518,13 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
                goto error;
        }
 
-       if (!os_memcmp(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN) == 0) {
+       if (os_memcmp(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN) != 0) {
                wpa_printf(MSG_INFO, "TDLS: FTIE ANonce in TPK M3 does "
                           "not match with FTIE ANonce used in TPK M2");
                goto error;
        }
 
-       if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) {
+       if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0) {
                wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M3 does not "
                           "match with FTIE SNonce used in TPK M1");
                goto error;
index a9f255e..3c47879 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * WPA Supplicant - WPA state machine and EAPOL-Key processing
  * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright(c) 2015 Intel Deutschland GmbH
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -23,6 +24,9 @@
 #include "peerkey.h"
 
 
+static const u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+
 /**
  * wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
  * @msg: EAPOL-Key message
  * @msg_len: Length of message
  * @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written
+ * Returns: >= 0 on success, < 0 on failure
  */
-void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
-                       int ver, const u8 *dest, u16 proto,
-                       u8 *msg, size_t msg_len, u8 *key_mic)
+int wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
+                      int ver, const u8 *dest, u16 proto,
+                      u8 *msg, size_t msg_len, u8 *key_mic)
 {
+       int ret = -1;
        size_t mic_len = wpa_mic_len(sm->key_mgmt);
 
        if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) {
@@ -69,10 +75,11 @@ void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
        wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, kck_len);
        wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, mic_len);
        wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len);
-       wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
+       ret = wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
        eapol_sm_notify_tx_eapol_key(sm->eapol);
 out:
        os_free(msg);
+       return ret;
 }
 
 
@@ -124,7 +131,7 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
                EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
        key_info = WPA_KEY_INFO_REQUEST | ver;
        if (sm->ptk_set)
-               key_info |= WPA_KEY_INFO_MIC;
+               key_info |= WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
        if (error)
                key_info |= WPA_KEY_INFO_ERROR;
        if (pairwise)
@@ -206,15 +213,21 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
 #endif /* CONFIG_IEEE80211R */
        } else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) {
                int res, pmk_len;
-               pmk_len = PMK_LEN;
-               res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN);
+
+               if (sm->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+                       pmk_len = PMK_LEN_SUITE_B_192;
+               else
+                       pmk_len = PMK_LEN;
+               res = eapol_sm_get_key(sm->eapol, sm->pmk, pmk_len);
                if (res) {
-                       /*
-                        * EAP-LEAP is an exception from other EAP methods: it
-                        * uses only 16-byte PMK.
-                        */
-                       res = eapol_sm_get_key(sm->eapol, sm->pmk, 16);
-                       pmk_len = 16;
+                       if (pmk_len == PMK_LEN) {
+                               /*
+                                * EAP-LEAP is an exception from other EAP
+                                * methods: it uses only 16-byte PMK.
+                                */
+                               res = eapol_sm_get_key(sm->eapol, sm->pmk, 16);
+                               pmk_len = 16;
+                       }
                } else {
 #ifdef CONFIG_IEEE80211R
                        u8 buf[2 * PMK_LEN];
@@ -236,7 +249,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
                            !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
                            !wpa_key_mgmt_ft(sm->key_mgmt)) {
                                sa = pmksa_cache_add(sm->pmksa,
-                                                    sm->pmk, pmk_len,
+                                                    sm->pmk, pmk_len, NULL,
                                                     NULL, 0,
                                                     src_addr, sm->own_addr,
                                                     sm->network_ctx,
@@ -257,7 +270,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
                                 * much we can do here without knowing what
                                 * exactly caused the server to misbehave.
                                 */
-                               wpa_dbg(sm->ctx->msg_ctx, MSG_INFO,
+                               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
                                        "RSN: PMKID mismatch - authentication server may have derived different MSK?!");
                                return -1;
                        }
@@ -318,7 +331,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
  * @wpa_ie: WPA/RSN IE
  * @wpa_ie_len: Length of the WPA/RSN IE
  * @ptk: PTK to use for keyed hash and encryption
- * Returns: 0 on success, -1 on failure
+ * Returns: >= 0 on success, < 0 on failure
  */
 int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
                               const struct wpa_eapol_key *key,
@@ -351,13 +364,12 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
                if (rsn_ie_buf == NULL)
                        return -1;
                os_memcpy(rsn_ie_buf, wpa_ie, wpa_ie_len);
-               res = wpa_insert_pmkid(rsn_ie_buf, wpa_ie_len,
+               res = wpa_insert_pmkid(rsn_ie_buf, &wpa_ie_len,
                                       sm->pmk_r1_name);
                if (res < 0) {
                        os_free(rsn_ie_buf);
                        return -1;
                }
-               wpa_ie_len += res;
 
                if (sm->assoc_resp_ies) {
                        os_memcpy(rsn_ie_buf + wpa_ie_len, sm->assoc_resp_ies,
@@ -409,10 +421,8 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
        os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
 
        wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
-       wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL,
-                          rbuf, rlen, key_mic);
-
-       return 0;
+       return wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst,
+                                 ETH_P_EAPOL, rbuf, rlen, key_mic);
 }
 
 
@@ -500,6 +510,7 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
                os_memset(buf, 0, sizeof(buf));
        }
        sm->tptk_set = 1;
+       sm->tk_to_set = 1;
 
        kde = sm->assoc_wpa_ie;
        kde_len = sm->assoc_wpa_ie_len;
@@ -525,7 +536,7 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
 #endif /* CONFIG_P2P */
 
        if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce,
-                                      kde, kde_len, ptk))
+                                      kde, kde_len, ptk) < 0)
                goto failed;
 
        os_free(kde_buf);
@@ -603,7 +614,12 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
        int keylen, rsclen;
        enum wpa_alg alg;
        const u8 *key_rsc;
-       u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+       if (!sm->tk_to_set) {
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "WPA: Do not re-install same PTK to the driver");
+               return 0;
+       }
 
        wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
                "WPA: Installing PTK to the driver");
@@ -643,6 +659,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
 
        /* TK is not needed anymore in supplicant */
        os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
+       sm->tk_to_set = 0;
 
        if (sm->wpa_ptk_rekey) {
                eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
@@ -753,12 +770,43 @@ static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm,
 }
 
 
+static int wpa_supplicant_rsc_relaxation(const struct wpa_sm *sm,
+                                        const u8 *rsc)
+{
+       int rsclen;
+
+       if (!sm->wpa_rsc_relaxation)
+               return 0;
+
+       rsclen = wpa_cipher_rsc_len(sm->group_cipher);
+
+       /*
+        * Try to detect RSC (endian) corruption issue where the AP sends
+        * the RSC bytes in EAPOL-Key message in the wrong order, both if
+        * it's actually a 6-byte field (as it should be) and if it treats
+        * it as an 8-byte field.
+        * An AP model known to have this bug is the Sapido RB-1632.
+        */
+       if (rsclen == 6 && ((rsc[5] && !rsc[0]) || rsc[6] || rsc[7])) {
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "RSC %02x%02x%02x%02x%02x%02x%02x%02x is likely bogus, using 0",
+                       rsc[0], rsc[1], rsc[2], rsc[3],
+                       rsc[4], rsc[5], rsc[6], rsc[7]);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+
 static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
                                       const struct wpa_eapol_key *key,
                                       const u8 *gtk, size_t gtk_len,
                                       int key_info)
 {
        struct wpa_gtk_data gd;
+       const u8 *key_rsc;
 
        /*
         * IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames - Figure 43x
@@ -784,11 +832,15 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
        os_memcpy(gd.gtk, gtk, gtk_len);
        gd.gtk_len = gtk_len;
 
+       key_rsc = key->key_rsc;
+       if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc))
+               key_rsc = null_rsc;
+
        if (sm->group_cipher != WPA_CIPHER_GTK_NOT_USED &&
            (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
                                               gtk_len, gtk_len,
                                               &gd.key_rsc_len, &gd.alg) ||
-            wpa_supplicant_install_gtk(sm, &gd, key->key_rsc))) {
+            wpa_supplicant_install_gtk(sm, &gd, key_rsc))) {
                wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
                        "RSN: Failed to install GTK");
                os_memset(&gd, 0, sizeof(gd));
@@ -989,8 +1041,8 @@ static int wpa_supplicant_validate_ie_ft(struct wpa_sm *sm,
        if (sm->assoc_resp_ies) {
                pos = sm->assoc_resp_ies;
                end = pos + sm->assoc_resp_ies_len;
-               while (pos + 2 < end) {
-                       if (pos + 2 + pos[1] > end)
+               while (end - pos > 2) {
+                       if (2 + pos[1] > end - pos)
                                break;
                        switch (*pos) {
                        case WLAN_EID_MOBILITY_DOMAIN:
@@ -1086,7 +1138,7 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
  * @ver: Version bits from EAPOL-Key Key Info
  * @key_info: Key Info
  * @ptk: PTK to use for keyed hash and encryption
- * Returns: 0 on success, -1 on failure
+ * Returns: >= 0 on success, < 0 on failure
  */
 int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
                               const struct wpa_eapol_key *key,
@@ -1126,10 +1178,8 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
                WPA_PUT_BE16(reply->key_data_length, 0);
 
        wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
-       wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL,
-                          rbuf, rlen, key_mic);
-
-       return 0;
+       return wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst,
+                                 ETH_P_EAPOL, rbuf, rlen, key_mic);
 }
 
 
@@ -1202,7 +1252,7 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
 #endif /* CONFIG_P2P */
 
        if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
-                                      &sm->ptk)) {
+                                      &sm->ptk) < 0) {
                goto failed;
        }
 
@@ -1247,7 +1297,7 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
        if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt)) {
                struct rsn_pmksa_cache_entry *sa;
 
-               sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len,
+               sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len, NULL,
                                     sm->ptk.kck, sm->ptk.kck_len,
                                     sm->bssid, sm->own_addr,
                                     sm->network_ctx, sm->key_mgmt);
@@ -1437,10 +1487,8 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
                WPA_PUT_BE16(reply->key_data_length, 0);
 
        wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
-       wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, sm->bssid,
-                          ETH_P_EAPOL, rbuf, rlen, key_mic);
-
-       return 0;
+       return wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver,
+                                 sm->bssid, ETH_P_EAPOL, rbuf, rlen, key_mic);
 }
 
 
@@ -1453,6 +1501,7 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
        u16 key_info;
        int rekey, ret;
        struct wpa_gtk_data gd;
+       const u8 *key_rsc;
 
        if (!sm->msg_3_of_4_ok) {
                wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -1483,8 +1532,12 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
        if (ret)
                goto failed;
 
-       if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc) ||
-           wpa_supplicant_send_2_of_2(sm, key, ver, key_info))
+       key_rsc = key->key_rsc;
+       if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc))
+               key_rsc = null_rsc;
+
+       if (wpa_supplicant_install_gtk(sm, &gd, key_rsc) ||
+           wpa_supplicant_send_2_of_2(sm, key, ver, key_info) < 0)
                goto failed;
        os_memset(&gd, 0, sizeof(gd));
 
@@ -1617,14 +1670,14 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
                }
                if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, *key_data_len / 8,
                               key_data, buf)) {
-                       os_free(buf);
+                       bin_clear_free(buf, *key_data_len);
                        wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                                "WPA: AES unwrap failed - "
                                "could not decrypt EAPOL-Key key data");
                        return -1;
                }
                os_memcpy(key_data, buf, *key_data_len);
-               os_free(buf);
+               bin_clear_free(buf, *key_data_len);
                WPA_PUT_BE16(key->key_data_length, *key_data_len);
        } else {
                wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -2237,6 +2290,9 @@ void wpa_sm_deinit(struct wpa_sm *sm)
 #ifdef CONFIG_IEEE80211R
        os_free(sm->assoc_resp_ies);
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_TESTING_OPTIONS
+       wpabuf_free(sm->test_assoc_ie);
+#endif /* CONFIG_TESTING_OPTIONS */
        os_free(sm);
 }
 
@@ -2335,12 +2391,13 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
  * @pmk: The new PMK
  * @pmk_len: The length of the new PMK in bytes
+ * @pmkid: Calculated PMKID
  * @bssid: AA to add into PMKSA cache or %NULL to not cache the PMK
  *
  * Configure the PMK for WPA state machine.
  */
 void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
-                   const u8 *bssid)
+                   const u8 *pmkid, const u8 *bssid)
 {
        if (sm == NULL)
                return;
@@ -2355,7 +2412,7 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
 #endif /* CONFIG_IEEE80211R */
 
        if (bssid) {
-               pmksa_cache_add(sm->pmksa, pmk, pmk_len, NULL, 0,
+               pmksa_cache_add(sm->pmksa, pmk, pmk_len, pmkid, NULL, 0,
                                bssid, sm->own_addr,
                                sm->network_ctx, sm->key_mgmt);
        }
@@ -2439,6 +2496,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
                        sm->ssid_len = 0;
                sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
                sm->p2p = config->p2p;
+               sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation;
        } else {
                sm->network_ctx = NULL;
                sm->peerkey_enabled = 0;
@@ -2449,6 +2507,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
                sm->ssid_len = 0;
                sm->wpa_ptk_rekey = 0;
                sm->p2p = 0;
+               sm->wpa_rsc_relaxation = 0;
        }
 }
 
@@ -2636,6 +2695,17 @@ int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
        if (sm == NULL)
                return -1;
 
+#ifdef CONFIG_TESTING_OPTIONS
+       if (sm->test_assoc_ie) {
+               wpa_printf(MSG_DEBUG,
+                          "TESTING: Replace association WPA/RSN IE");
+               if (*wpa_ie_len < wpabuf_len(sm->test_assoc_ie))
+                       return -1;
+               os_memcpy(wpa_ie, wpabuf_head(sm->test_assoc_ie),
+                         wpabuf_len(sm->test_assoc_ie));
+               res = wpabuf_len(sm->test_assoc_ie);
+       } else
+#endif /* CONFIG_TESTING_OPTIONS */
        res = wpa_gen_wpa_ie(sm, wpa_ie, *wpa_ie_len);
        if (res < 0)
                return -1;
@@ -2975,3 +3045,12 @@ void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm,
        }
        sm->ptk_set = 1;
 }
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf)
+{
+       wpabuf_free(sm->test_assoc_ie);
+       sm->test_assoc_ie = buf;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
index e163b70..0b7477f 100644 (file)
@@ -104,6 +104,7 @@ struct rsn_supp_config {
        size_t ssid_len;
        int wpa_ptk_rekey;
        int p2p;
+       int wpa_rsc_relaxation;
 };
 
 #ifndef CONFIG_NO_WPA
@@ -113,7 +114,7 @@ void wpa_sm_deinit(struct wpa_sm *sm);
 void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid);
 void wpa_sm_notify_disassoc(struct wpa_sm *sm);
 void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
-                   const u8 *bssid);
+                   const u8 *pmkid, const u8 *bssid);
 void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm);
 void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth);
 void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx);
@@ -180,7 +181,8 @@ static inline void wpa_sm_notify_disassoc(struct wpa_sm *sm)
 }
 
 static inline void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk,
-                                 size_t pmk_len)
+                                 size_t pmk_len, const u8 *pmkid,
+                                 const u8 *bssid)
 {
 }
 
@@ -320,7 +322,8 @@ static inline void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm,
 }
 
 static inline void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck,
-                                         const u8 *ptk_kek)
+                                         size_t ptk_kck_len,
+                                         const u8 *ptk_kek, size_t ptk_kek_len)
 {
 }
 
@@ -415,7 +418,12 @@ int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr,
                                u8 oper_class,
                                struct hostapd_freq_params *freq_params);
 int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr);
+#ifdef CONFIG_TDLS_TESTING
+extern unsigned int tdls_testing;
+#endif /* CONFIG_TDLS_TESTING */
+
 
 int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
+void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf);
 
 #endif /* WPA_H */
index 965a9c1..f653ba6 100644 (file)
@@ -19,11 +19,12 @@ struct wpa_eapol_key;
  * struct wpa_sm - Internal WPA state machine data
  */
 struct wpa_sm {
-       u8 pmk[PMK_LEN];
+       u8 pmk[PMK_LEN_MAX];
        size_t pmk_len;
        struct wpa_ptk ptk, tptk;
        int ptk_set, tptk_set;
        unsigned int msg_3_of_4_ok:1;
+       unsigned int tk_to_set:1;
        u8 snonce[WPA_NONCE_LEN];
        u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */
        int renew_snonce;
@@ -60,6 +61,7 @@ struct wpa_sm {
        size_t ssid_len;
        int wpa_ptk_rekey;
        int p2p;
+       int wpa_rsc_relaxation;
 
        u8 own_addr[ETH_ALEN];
        const char *ifname;
@@ -132,6 +134,10 @@ struct wpa_sm {
 #ifdef CONFIG_P2P
        u8 p2p_ip_addr[3 * 4];
 #endif /* CONFIG_P2P */
+
+#ifdef CONFIG_TESTING_OPTIONS
+       struct wpabuf *test_assoc_ie;
+#endif /* CONFIG_TESTING_OPTIONS */
 };
 
 
@@ -342,16 +348,14 @@ wpa_sm_tdls_disable_channel_switch(struct wpa_sm *sm, const u8 *addr)
 static inline int wpa_sm_key_mgmt_set_pmk(struct wpa_sm *sm,
                                          const u8 *pmk, size_t pmk_len)
 {
-       if (!sm->proactive_key_caching)
-               return 0;
        if (!sm->ctx->key_mgmt_set_pmk)
                return -1;
        return sm->ctx->key_mgmt_set_pmk(sm->ctx->ctx, pmk, pmk_len);
 }
 
-void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
-                       int ver, const u8 *dest, u16 proto,
-                       u8 *msg, size_t msg_len, u8 *key_mic);
+int wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
+                      int ver, const u8 *dest, u16 proto,
+                      u8 *msg, size_t msg_len, u8 *key_mic);
 int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
                               const struct wpa_eapol_key *key,
                               int ver, const u8 *nonce,
index 0c37b35..c44844e 100644 (file)
@@ -378,7 +378,7 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
                return 0;
        }
 
-       if (pos + 1 + RSN_SELECTOR_LEN < end &&
+       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;
@@ -491,13 +491,13 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
        int ret = 0;
 
        os_memset(ie, 0, sizeof(*ie));
-       for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
+       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 (pos + 2 + pos[1] > end) {
+               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));
index 27cdfca..52a890a 100644 (file)
@@ -24,6 +24,7 @@ LIB_OBJS= \
        tlsv1_client.o \
        tlsv1_client_read.o \
        tlsv1_client_write.o \
+       tlsv1_client_ocsp.o \
        tlsv1_common.o \
        tlsv1_cred.o \
        tlsv1_record.o \
index 7475007..6bd7df5 100644 (file)
@@ -20,6 +20,7 @@
 #define ASN1_TAG_EXTERNAL      0x08 /* not yet parsed */
 #define ASN1_TAG_REAL          0x09 /* not yet parsed */
 #define ASN1_TAG_ENUMERATED    0x0A /* not yet parsed */
+#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_SEQUENCE      0x10 /* shall be constructed */
@@ -35,7 +36,8 @@
 #define ASN1_TAG_VISIBLESTRING 0x1A
 #define ASN1_TAG_GENERALSTRING 0x1B /* not yet parsed */
 #define ASN1_TAG_UNIVERSALSTRING       0x1C /* not yet parsed */
-#define ASN1_TAG_BMPSTRING     0x1D /* not yet parsed */
+#define ASN1_TAG_CHARACTERSTRING       0x1D /* not yet parsed */
+#define ASN1_TAG_BMPSTRING     0x1E /* not yet parsed */
 
 #define ASN1_CLASS_UNIVERSAL           0
 #define ASN1_CLASS_APPLICATION         1
index 8a93483..a2ad83b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * PKCS #5 (Password-based Encryption)
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2015, 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,7 @@
 #include "common.h"
 #include "crypto/crypto.h"
 #include "crypto/md5.h"
+#include "crypto/sha1.h"
 #include "asn1.h"
 #include "pkcs5.h"
 
 struct pkcs5_params {
        enum pkcs5_alg {
                PKCS5_ALG_UNKNOWN,
-               PKCS5_ALG_MD5_DES_CBC
+               PKCS5_ALG_MD5_DES_CBC,
+               PKCS5_ALG_PBES2,
+               PKCS5_ALG_SHA1_3DES_CBC,
        } alg;
-       u8 salt[8];
+       u8 salt[64];
        size_t salt_len;
        unsigned int iter_count;
+       enum pbes2_enc_alg {
+               PBES2_ENC_ALG_UNKNOWN,
+               PBES2_ENC_ALG_DES_EDE3_CBC,
+       } enc_alg;
+       u8 iv[8];
+       size_t iv_len;
 };
 
 
+static int oid_is_rsadsi(struct asn1_oid *oid)
+{
+       return oid->len >= 4 &&
+               oid->oid[0] == 1 /* iso */ &&
+               oid->oid[1] == 2 /* member-body */ &&
+               oid->oid[2] == 840 /* us */ &&
+               oid->oid[3] == 113549 /* rsadsi */;
+}
+
+
+static int pkcs5_is_oid(struct asn1_oid *oid, unsigned long alg)
+{
+       return oid->len == 7 &&
+               oid_is_rsadsi(oid) &&
+               oid->oid[4] == 1 /* pkcs */ &&
+               oid->oid[5] == 5 /* pkcs-5 */ &&
+               oid->oid[6] == alg;
+}
+
+
+static int enc_alg_is_oid(struct asn1_oid *oid, unsigned long alg)
+{
+       return oid->len == 6 &&
+               oid_is_rsadsi(oid) &&
+               oid->oid[4] == 3 /* encryptionAlgorithm */ &&
+               oid->oid[5] == alg;
+}
+
+
+static int pkcs12_is_pbe_oid(struct asn1_oid *oid, unsigned long alg)
+{
+       return oid->len == 8 &&
+               oid_is_rsadsi(oid) &&
+               oid->oid[4] == 1 /* pkcs */ &&
+               oid->oid[5] == 12 /* pkcs-12 */ &&
+               oid->oid[6] == 1 /* pkcs-12PbeIds */ &&
+               oid->oid[7] == alg;
+}
+
+
 static enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
 {
-       if (oid->len == 7 &&
-           oid->oid[0] == 1 /* iso */ &&
-           oid->oid[1] == 2 /* member-body */ &&
-           oid->oid[2] == 840 /* us */ &&
-           oid->oid[3] == 113549 /* rsadsi */ &&
-           oid->oid[4] == 1 /* pkcs */ &&
-           oid->oid[5] == 5 /* pkcs-5 */ &&
-           oid->oid[6] == 3 /* pbeWithMD5AndDES-CBC */)
+       if (pkcs5_is_oid(oid, 3)) /* pbeWithMD5AndDES-CBC (PBES1) */
                return PKCS5_ALG_MD5_DES_CBC;
-
+       if (pkcs12_is_pbe_oid(oid, 3)) /* pbeWithSHAAnd3-KeyTripleDES-CBC */
+               return PKCS5_ALG_SHA1_3DES_CBC;
+       if (pkcs5_is_oid(oid, 13)) /* id-PBES2 (PBES2) */
+               return PKCS5_ALG_PBES2;
        return PKCS5_ALG_UNKNOWN;
 }
 
 
+static int pkcs5_get_params_pbes2(struct pkcs5_params *params, const u8 *pos,
+                                 const u8 *enc_alg_end)
+{
+       struct asn1_hdr hdr;
+       const u8 *end, *kdf_end;
+       struct asn1_oid oid;
+       char obuf[80];
+
+       /*
+        * RFC 2898, Ch. A.4
+        *
+        * PBES2-params ::= SEQUENCE {
+        *     keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
+        *     encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
+        *
+        * PBES2-KDFs ALGORITHM-IDENTIFIER ::=
+        *     { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... }
+        */
+
+       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);
+               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);
+               return -1;
+       }
+
+       pos = hdr.payload;
+       kdf_end = end = hdr.payload + hdr.length;
+
+       if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+               wpa_printf(MSG_DEBUG,
+                          "PKCS #5: Failed to parse OID (keyDerivationFunc algorithm)");
+               return -1;
+       }
+
+       asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+       wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 keyDerivationFunc algorithm %s",
+                  obuf);
+       if (!pkcs5_is_oid(&oid, 12)) /* id-PBKDF2 */ {
+               wpa_printf(MSG_DEBUG,
+                          "PKCS #5: Unsupported PBES2 keyDerivationFunc algorithm %s",
+                          obuf);
+               return -1;
+       }
+
+       /*
+        * RFC 2898, C.
+        *
+        * PBKDF2-params ::= SEQUENCE {
+        *     salt CHOICE {
+        *       specified OCTET STRING,
+        *       otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
+        *     },
+        *     iterationCount INTEGER (1..MAX),
+        *     keyLength INTEGER (1..MAX) OPTIONAL,
+        *     prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT
+        *     algid-hmacWithSHA1
+        * }
+        */
+
+       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);
+               return -1;
+       }
+
+       pos = hdr.payload;
+       end = hdr.payload + hdr.length;
+
+       /* 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 ||
+           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);
+               return -1;
+       }
+       pos = hdr.payload + hdr.length;
+       os_memcpy(params->salt, hdr.payload, hdr.length);
+       params->salt_len = hdr.length;
+       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);
+               return -1;
+       }
+       if (hdr.length == 1) {
+               params->iter_count = *hdr.payload;
+       } else if (hdr.length == 2) {
+               params->iter_count = WPA_GET_BE16(hdr.payload);
+       } else if (hdr.length == 4) {
+               params->iter_count = WPA_GET_BE32(hdr.payload);
+       } else {
+               wpa_hexdump(MSG_DEBUG,
+                           "PKCS #5: Unsupported INTEGER value (iterationCount)",
+                           hdr.payload, hdr.length);
+               return -1;
+       }
+       wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x",
+                  params->iter_count);
+       if (params->iter_count == 0 || params->iter_count > 0xffff) {
+               wpa_printf(MSG_INFO, "PKCS #5: Unsupported iterationCount=0x%x",
+                          params->iter_count);
+               return -1;
+       }
+
+       /* For now, ignore optional keyLength and prf */
+
+       pos = kdf_end;
+
+       /* 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);
+               return -1;
+       }
+
+       pos = hdr.payload;
+       end = hdr.payload + hdr.length;
+
+       if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+               wpa_printf(MSG_DEBUG,
+                          "PKCS #5: Failed to parse OID (encryptionScheme algorithm)");
+               return -1;
+       }
+
+       asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+       wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 encryptionScheme algorithm %s",
+                  obuf);
+       if (enc_alg_is_oid(&oid, 7)) {
+               params->enc_alg = PBES2_ENC_ALG_DES_EDE3_CBC;
+       } else {
+               wpa_printf(MSG_DEBUG,
+                          "PKCS #5: Unsupported PBES2 encryptionScheme algorithm %s",
+                          obuf);
+               return -1;
+       }
+
+       /*
+        * RFC 2898, B.2.2:
+        * The parameters field associated with this OID in an
+        * AlgorithmIdentifier shall have type OCTET STRING (SIZE(8)),
+        * 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);
+               return -1;
+       }
+       os_memcpy(params->iv, hdr.payload, hdr.length);
+       params->iv_len = hdr.length;
+       wpa_hexdump(MSG_DEBUG, "PKCS #5: IV", params->iv, params->iv_len);
+
+       return 0;
+}
+
+
 static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
                            struct pkcs5_params *params)
 {
@@ -71,11 +303,23 @@ static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
                return -1;
        }
 
+       if (params->alg == PKCS5_ALG_PBES2)
+               return pkcs5_get_params_pbes2(params, pos, enc_alg_end);
+
+       /* PBES1 */
+
        /*
         * PKCS#5, Section 8
         * PBEParameter ::= SEQUENCE {
         *   salt OCTET STRING SIZE(8),
         *   iterationCount INTEGER }
+        *
+        * Note: The same implementation can be used to parse the PKCS #12
+        * version described in RFC 7292, C:
+        * pkcs-12PbeParams ::= SEQUENCE {
+        *     salt        OCTET STRING,
+        *     iterations  INTEGER
+        * }
         */
 
        if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
@@ -89,11 +333,11 @@ static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
        pos = hdr.payload;
        end = hdr.payload + hdr.length;
 
-       /* salt OCTET STRING SIZE(8) */
+       /* 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 != 8) {
+           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);
@@ -136,6 +380,174 @@ static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
 }
 
 
+static struct crypto_cipher *
+pkcs5_crypto_init_pbes2(struct pkcs5_params *params, const char *passwd)
+{
+       u8 key[24];
+
+       if (params->enc_alg != PBES2_ENC_ALG_DES_EDE3_CBC ||
+           params->iv_len != 8)
+               return NULL;
+
+       wpa_hexdump_ascii_key(MSG_DEBUG, "PKCS #5: PBES2 password for PBKDF2",
+                             passwd, os_strlen(passwd));
+       wpa_hexdump(MSG_DEBUG, "PKCS #5: PBES2 salt for PBKDF2",
+                   params->salt, params->salt_len);
+       wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 PBKDF2 iterations: %u",
+                  params->iter_count);
+       if (pbkdf2_sha1(passwd, params->salt, params->salt_len,
+                       params->iter_count, key, sizeof(key)) < 0)
+               return NULL;
+       wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES EDE3 key", key, sizeof(key));
+       wpa_hexdump(MSG_DEBUG, "PKCS #5: DES IV", params->iv, params->iv_len);
+
+       return crypto_cipher_init(CRYPTO_CIPHER_ALG_3DES, params->iv,
+                                 key, sizeof(key));
+}
+
+
+static void add_byte_array_mod(u8 *a, const u8 *b, size_t len)
+{
+       size_t i;
+       unsigned int carry = 0;
+
+       for (i = len - 1; i < len; i--) {
+               carry = carry + a[i] + b[i];
+               a[i] = carry & 0xff;
+               carry >>= 8;
+       }
+}
+
+
+static int pkcs12_key_gen(const u8 *pw, size_t pw_len, const u8 *salt,
+                         size_t salt_len, u8 id, unsigned int iter,
+                         size_t out_len, u8 *out)
+{
+       unsigned int u, v, S_len, P_len, i;
+       u8 *D = NULL, *I = NULL, *B = NULL, *pos;
+       int res = -1;
+
+       /* RFC 7292, B.2 */
+       u = SHA1_MAC_LEN;
+       v = 64;
+
+       /* D = copies of ID */
+       D = os_malloc(v);
+       if (!D)
+               goto done;
+       os_memset(D, id, v);
+
+       /* S = copies of salt; P = copies of password, I = S || P */
+       S_len = v * ((salt_len + v - 1) / v);
+       P_len = v * ((pw_len + v - 1) / v);
+       I = os_malloc(S_len + P_len);
+       if (!I)
+               goto done;
+       pos = I;
+       if (salt_len) {
+               for (i = 0; i < S_len; i++)
+                       *pos++ = salt[i % salt_len];
+       }
+       if (pw_len) {
+               for (i = 0; i < P_len; i++)
+                       *pos++ = pw[i % pw_len];
+       }
+
+       B = os_malloc(v);
+       if (!B)
+               goto done;
+
+       for (;;) {
+               u8 hash[SHA1_MAC_LEN];
+               const u8 *addr[2];
+               size_t len[2];
+
+               addr[0] = D;
+               len[0] = v;
+               addr[1] = I;
+               len[1] = S_len + P_len;
+               if (sha1_vector(2, addr, len, hash) < 0)
+                       goto done;
+
+               addr[0] = hash;
+               len[0] = SHA1_MAC_LEN;
+               for (i = 1; i < iter; i++) {
+                       if (sha1_vector(1, addr, len, hash) < 0)
+                               goto done;
+               }
+
+               if (out_len <= u) {
+                       os_memcpy(out, hash, out_len);
+                       res = 0;
+                       goto done;
+               }
+
+               os_memcpy(out, hash, u);
+               out += u;
+               out_len -= u;
+
+               /* I_j = (I_j + B + 1) mod 2^(v*8) */
+               /* B = copies of Ai (final hash value) */
+               for (i = 0; i < v; i++)
+                       B[i] = hash[i % u];
+               inc_byte_array(B, v);
+               for (i = 0; i < S_len + P_len; i += v)
+                       add_byte_array_mod(&I[i], B, v);
+       }
+
+done:
+       os_free(B);
+       os_free(I);
+       os_free(D);
+       return res;
+}
+
+
+#define PKCS12_ID_ENC 1
+#define PKCS12_ID_IV 2
+#define PKCS12_ID_MAC 3
+
+static struct crypto_cipher *
+pkcs12_crypto_init_sha1(struct pkcs5_params *params, const char *passwd)
+{
+       unsigned int i;
+       u8 *pw;
+       size_t pw_len;
+       u8 key[24];
+       u8 iv[8];
+
+       if (params->alg != PKCS5_ALG_SHA1_3DES_CBC)
+               return NULL;
+
+       pw_len = passwd ? os_strlen(passwd) : 0;
+       pw = os_malloc(2 * (pw_len + 1));
+       if (!pw)
+               return NULL;
+       if (pw_len) {
+               for (i = 0; i <= pw_len; i++)
+                       WPA_PUT_BE16(&pw[2 * i], passwd[i]);
+               pw_len = 2 * (pw_len + 1);
+       }
+
+       if (pkcs12_key_gen(pw, pw_len, params->salt, params->salt_len,
+                          PKCS12_ID_ENC, params->iter_count,
+                          sizeof(key), key) < 0 ||
+           pkcs12_key_gen(pw, pw_len, params->salt, params->salt_len,
+                          PKCS12_ID_IV, params->iter_count,
+                          sizeof(iv), iv) < 0) {
+               os_free(pw);
+               return NULL;
+       }
+
+       os_free(pw);
+
+       wpa_hexdump_key(MSG_DEBUG, "PKCS #12: DES key", key, sizeof(key));
+       wpa_hexdump_key(MSG_DEBUG, "PKCS #12: DES IV", iv, sizeof(iv));
+
+       return crypto_cipher_init(CRYPTO_CIPHER_ALG_3DES, iv, key, sizeof(key));
+}
+
+
 static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
                                                const char *passwd)
 {
@@ -144,6 +556,12 @@ static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
        const u8 *addr[2];
        size_t len[2];
 
+       if (params->alg == PKCS5_ALG_PBES2)
+               return pkcs5_crypto_init_pbes2(params, passwd);
+
+       if (params->alg == PKCS5_ALG_SHA1_3DES_CBC)
+               return pkcs12_crypto_init_sha1(params, passwd);
+
        if (params->alg != PKCS5_ALG_MD5_DES_CBC)
                return NULL;
 
index a6f0587..9bc0d21 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, 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,7 @@
 #include "common.h"
 #include "crypto/sha1.h"
 #include "crypto/tls.h"
+#include "x509v3.h"
 #include "tlsv1_common.h"
 #include "tlsv1_record.h"
 #include "tlsv1_client.h"
@@ -110,7 +111,6 @@ int tls_derive_keys(struct tlsv1_client *conn,
                pos += conn->rl.iv_size;
                /* server_write_IV */
                os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
-               pos += conn->rl.iv_size;
        } else {
                /*
                 * Use IV field to set the mask value for TLS v1.1. A fixed
@@ -494,6 +494,7 @@ void tlsv1_client_deinit(struct tlsv1_client *conn)
        tlsv1_client_free_dh(conn);
        tlsv1_cred_free(conn->cred);
        wpabuf_free(conn->partial_input);
+       x509_certificate_chain_free(conn->server_cert);
        os_free(conn);
 }
 
@@ -691,18 +692,16 @@ int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
        if (data == NULL || data_len == 0)
                return 0;
 
-       pos = conn->client_hello_ext = os_malloc(6 + data_len);
+       pos = conn->client_hello_ext = os_malloc(4 + data_len);
        if (pos == NULL)
                return -1;
 
-       WPA_PUT_BE16(pos, 4 + data_len);
-       pos += 2;
        WPA_PUT_BE16(pos, ext_type);
        pos += 2;
        WPA_PUT_BE16(pos, data_len);
        pos += 2;
        os_memcpy(pos, data, data_len);
-       conn->client_hello_ext_len = 6 + data_len;
+       conn->client_hello_ext_len = 4 + data_len;
 
        if (ext_type == TLS_EXT_PAC_OPAQUE) {
                conn->session_ticket_included = 1;
@@ -813,9 +812,14 @@ int tlsv1_client_set_cred(struct tlsv1_client *conn,
 }
 
 
-void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled)
+/**
+ * tlsv1_client_set_flags - Set connection flags
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @flags: TLS_CONN_* bitfield
+ */
+void tlsv1_client_set_flags(struct tlsv1_client *conn, unsigned int flags)
 {
-       conn->disable_time_checks = !enabled;
+       conn->flags = flags;
 }
 
 
@@ -828,3 +832,38 @@ void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
        conn->session_ticket_cb = cb;
        conn->session_ticket_cb_ctx = ctx;
 }
+
+
+void tlsv1_client_set_cb(struct tlsv1_client *conn,
+                        void (*event_cb)(void *ctx, enum tls_event ev,
+                                         union tls_event_data *data),
+                        void *cb_ctx,
+                        int cert_in_cb)
+{
+       conn->event_cb = event_cb;
+       conn->cb_ctx = cb_ctx;
+       conn->cert_in_cb = !!cert_in_cb;
+}
+
+
+int tlsv1_client_get_version(struct tlsv1_client *conn, char *buf,
+                            size_t buflen)
+{
+       if (!conn)
+               return -1;
+       switch (conn->rl.tls_version) {
+       case TLS_VERSION_1:
+               os_strlcpy(buf, "TLSv1", buflen);
+               break;
+       case TLS_VERSION_1_1:
+               os_strlcpy(buf, "TLSv1.1", buflen);
+               break;
+       case TLS_VERSION_1_2:
+               os_strlcpy(buf, "TLSv1.2", buflen);
+               break;
+       default:
+               return -1;
+       }
+
+       return 0;
+}
index a4e25e9..40fa6c7 100644 (file)
@@ -41,7 +41,7 @@ int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn);
 int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers);
 int tlsv1_client_set_cred(struct tlsv1_client *conn,
                          struct tlsv1_credentials *cred);
-void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled);
+void tlsv1_client_set_flags(struct tlsv1_client *conn, unsigned int flags);
 
 typedef int (*tlsv1_client_session_ticket_cb)
 (void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
@@ -51,4 +51,12 @@ void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
                                        tlsv1_client_session_ticket_cb cb,
                                        void *ctx);
 
+void tlsv1_client_set_cb(struct tlsv1_client *conn,
+                        void (*event_cb)(void *ctx, enum tls_event ev,
+                                         union tls_event_data *data),
+                        void *cb_ctx,
+                        int cert_in_cb);
+int tlsv1_client_get_version(struct tlsv1_client *conn, char *buf,
+                            size_t buflen);
+
 #endif /* TLSV1_CLIENT_H */
index 55fdcf8..12ec8df 100644 (file)
@@ -29,11 +29,14 @@ struct tlsv1_client {
        u8 alert_level;
        u8 alert_description;
 
+       unsigned int flags; /* TLS_CONN_* bitfield */
+
        unsigned int certificate_requested:1;
        unsigned int session_resumed:1;
        unsigned int session_ticket_included:1;
        unsigned int use_session_ticket:1;
-       unsigned int disable_time_checks:1;
+       unsigned int cert_in_cb:1;
+       unsigned int ocsp_resp_received:1;
 
        struct crypto_public_key *server_rsa_key;
 
@@ -64,6 +67,12 @@ struct tlsv1_client {
        void *session_ticket_cb_ctx;
 
        struct wpabuf *partial_input;
+
+       void (*event_cb)(void *ctx, enum tls_event ev,
+                        union tls_event_data *data);
+       void *cb_ctx;
+
+       struct x509_certificate *server_cert;
 };
 
 
@@ -81,4 +90,11 @@ int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
                                   const u8 *buf, size_t *len,
                                   u8 **out_data, size_t *out_len);
 
+enum tls_ocsp_result {
+       TLS_OCSP_NO_RESPONSE, TLS_OCSP_INVALID, TLS_OCSP_GOOD, TLS_OCSP_REVOKED
+};
+
+enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn,
+                                              const u8 *resp, size_t len);
+
 #endif /* TLSV1_CLIENT_I_H */
diff --git a/libeap/src/tls/tlsv1_client_ocsp.c b/libeap/src/tls/tlsv1_client_ocsp.c
new file mode 100644 (file)
index 0000000..1d7b68c
--- /dev/null
@@ -0,0 +1,803 @@
+/*
+ * TLSv1 client - OCSP
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/tls.h"
+#include "crypto/sha1.h"
+#include "asn1.h"
+#include "x509v3.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_client.h"
+#include "tlsv1_client_i.h"
+
+
+/* RFC 6960, 4.2.1: OCSPResponseStatus ::= ENUMERATED */
+enum ocsp_response_status {
+       OCSP_RESP_STATUS_SUCCESSFUL = 0,
+       OCSP_RESP_STATUS_MALFORMED_REQ = 1,
+       OCSP_RESP_STATUS_INT_ERROR = 2,
+       OCSP_RESP_STATUS_TRY_LATER = 3,
+       /* 4 not used */
+       OCSP_RESP_STATUS_SIG_REQUIRED = 5,
+       OCSP_RESP_STATUS_UNAUTHORIZED = 6,
+};
+
+
+static int is_oid_basic_ocsp_resp(struct asn1_oid *oid)
+{
+       return oid->len == 10 &&
+               oid->oid[0] == 1 /* iso */ &&
+               oid->oid[1] == 3 /* identified-organization */ &&
+               oid->oid[2] == 6 /* dod */ &&
+               oid->oid[3] == 1 /* internet */ &&
+               oid->oid[4] == 5 /* security */ &&
+               oid->oid[5] == 5 /* mechanisms */ &&
+               oid->oid[6] == 7 /* id-pkix */ &&
+               oid->oid[7] == 48 /* id-ad */ &&
+               oid->oid[8] == 1 /* id-pkix-ocsp */ &&
+               oid->oid[9] == 1 /* id-pkix-ocsp-basic */;
+}
+
+
+static int ocsp_responder_id_match(struct x509_certificate *signer,
+                                  struct x509_name *name, const u8 *key_hash)
+{
+       if (key_hash) {
+               u8 hash[SHA1_MAC_LEN];
+               const u8 *addr[1] = { signer->public_key };
+               size_t len[1] = { signer->public_key_len };
+
+               if (sha1_vector(1, addr, len, hash) < 0)
+                       return 0;
+               return os_memcmp(hash, key_hash, SHA1_MAC_LEN) == 0;
+       }
+
+       return x509_name_compare(&signer->subject, name) == 0;
+}
+
+
+static unsigned int ocsp_hash_data(struct asn1_oid *alg, const u8 *data,
+                                  size_t data_len, u8 *hash)
+{
+       const u8 *addr[1] = { data };
+       size_t len[1] = { data_len };
+       char buf[100];
+
+       if (x509_sha1_oid(alg)) {
+               if (sha1_vector(1, addr, len, hash) < 0)
+                       return 0;
+               wpa_hexdump(MSG_MSGDUMP, "OCSP: Hash (SHA1)", hash, 20);
+               return 20;
+       }
+
+       if (x509_sha256_oid(alg)) {
+               if (sha256_vector(1, addr, len, hash) < 0)
+                       return 0;
+               wpa_hexdump(MSG_MSGDUMP, "OCSP: Hash (SHA256)", hash, 32);
+               return 32;
+       }
+
+       if (x509_sha384_oid(alg)) {
+               if (sha384_vector(1, addr, len, hash) < 0)
+                       return 0;
+               wpa_hexdump(MSG_MSGDUMP, "OCSP: Hash (SHA384)", hash, 48);
+               return 48;
+       }
+
+       if (x509_sha512_oid(alg)) {
+               if (sha512_vector(1, addr, len, hash) < 0)
+                       return 0;
+               wpa_hexdump(MSG_MSGDUMP, "OCSP: Hash (SHA512)", hash, 64);
+               return 64;
+       }
+
+
+       asn1_oid_to_str(alg, buf, sizeof(buf));
+       wpa_printf(MSG_DEBUG, "OCSP: Could not calculate hash with alg %s",
+                  buf);
+       return 0;
+}
+
+
+static int tls_process_ocsp_single_response(struct tlsv1_client *conn,
+                                           struct x509_certificate *cert,
+                                           struct x509_certificate *issuer,
+                                           const u8 *resp, size_t len,
+                                           enum tls_ocsp_result *res)
+{
+       struct asn1_hdr hdr;
+       const u8 *pos, *end;
+       struct x509_algorithm_identifier alg;
+       const u8 *name_hash, *key_hash;
+       size_t name_hash_len, key_hash_len;
+       const u8 *serial_number;
+       size_t serial_number_len;
+       u8 hash[64];
+       unsigned int hash_len;
+       unsigned int cert_status;
+       os_time_t update;
+       struct os_time now;
+
+       wpa_hexdump(MSG_MSGDUMP, "OCSP: SingleResponse", resp, len);
+
+       /*
+        * SingleResponse ::= SEQUENCE {
+        *    certID                       CertID,
+        *    certStatus                   CertStatus,
+        *    thisUpdate                   GeneralizedTime,
+        *    nextUpdate         [0]       EXPLICIT GeneralizedTime OPTIONAL,
+        *    singleExtensions   [1]       EXPLICIT Extensions OPTIONAL }
+        */
+
+       /* 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);
+               return -1;
+       }
+       pos = hdr.payload;
+       end = hdr.payload + hdr.length;
+
+       /*
+        * CertID ::= SEQUENCE {
+        *    hashAlgorithm           AlgorithmIdentifier,
+        *    issuerNameHash          OCTET STRING,
+        *    issuerKeyHash           OCTET STRING,
+        *    serialNumber            CertificateSerialNumber }
+        */
+
+       /* hashAlgorithm  AlgorithmIdentifier */
+       if (x509_parse_algorithm_identifier(pos, end - pos, &alg, &pos))
+               return -1;
+
+       /* 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);
+               return -1;
+       }
+       name_hash = hdr.payload;
+       name_hash_len = hdr.length;
+       wpa_hexdump(MSG_DEBUG, "OCSP: issuerNameHash",
+                   name_hash, name_hash_len);
+       pos = hdr.payload + hdr.length;
+
+       wpa_hexdump(MSG_DEBUG, "OCSP: Issuer subject DN",
+                   issuer->subject_dn, issuer->subject_dn_len);
+       hash_len = ocsp_hash_data(&alg.oid, issuer->subject_dn,
+                                 issuer->subject_dn_len, hash);
+       if (hash_len == 0 || name_hash_len != hash_len ||
+           os_memcmp(name_hash, hash, hash_len) != 0) {
+               wpa_printf(MSG_DEBUG, "OCSP: issuerNameHash mismatch");
+               wpa_hexdump(MSG_DEBUG, "OCSP: Calculated issuerNameHash",
+                           hash, hash_len);
+               return -1;
+       }
+
+       /* 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);
+               return -1;
+       }
+       key_hash = hdr.payload;
+       key_hash_len = hdr.length;
+       wpa_hexdump(MSG_DEBUG, "OCSP: issuerKeyHash", key_hash, key_hash_len);
+       pos = hdr.payload + hdr.length;
+
+       hash_len = ocsp_hash_data(&alg.oid, issuer->public_key,
+                                 issuer->public_key_len, hash);
+       if (hash_len == 0 || key_hash_len != hash_len ||
+           os_memcmp(key_hash, hash, hash_len) != 0) {
+               wpa_printf(MSG_DEBUG, "OCSP: issuerKeyHash mismatch");
+               wpa_hexdump(MSG_DEBUG, "OCSP: Calculated issuerKeyHash",
+                           hash, hash_len);
+               return -1;
+       }
+
+       /* serialNumber CertificateSerialNumber ::= INTEGER */
+       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_UNIVERSAL ||
+           hdr.tag != ASN1_TAG_INTEGER ||
+           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);
+               return -1;
+       }
+       serial_number = hdr.payload;
+       serial_number_len = hdr.length;
+       while (serial_number_len > 0 && serial_number[0] == 0) {
+               serial_number++;
+               serial_number_len--;
+       }
+       wpa_hexdump(MSG_MSGDUMP, "OCSP: serialNumber", serial_number,
+                   serial_number_len);
+
+       if (serial_number_len != cert->serial_number_len ||
+           os_memcmp(serial_number, cert->serial_number,
+                     serial_number_len) != 0) {
+               wpa_printf(MSG_DEBUG, "OCSP: serialNumber mismatch");
+               return -1;
+       }
+
+       pos = end;
+       end = resp + len;
+
+       /* certStatus CertStatus ::= CHOICE */
+       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);
+               return -1;
+       }
+       cert_status = hdr.tag;
+       wpa_printf(MSG_DEBUG, "OCSP: certStatus=%u", cert_status);
+       wpa_hexdump(MSG_DEBUG, "OCSP: CertStatus additional data",
+                   hdr.payload, hdr.length);
+       pos = hdr.payload + hdr.length;
+
+       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 ||
+           x509_parse_time(hdr.payload, hdr.length, hdr.tag, &update) < 0) {
+               wpa_printf(MSG_DEBUG, "OCSP: Failed to parse thisUpdate");
+               return -1;
+       }
+       wpa_printf(MSG_DEBUG, "OCSP: thisUpdate %lu", (unsigned long) update);
+       pos = hdr.payload + hdr.length;
+       if ((unsigned long) now.sec < (unsigned long) update) {
+               wpa_printf(MSG_DEBUG,
+                          "OCSP: thisUpdate time in the future (response not yet valid)");
+               return -1;
+       }
+
+       /* nextUpdate  [0]  EXPLICIT GeneralizedTime OPTIONAL */
+       if (pos < end) {
+               if (asn1_get_next(pos, end - pos, &hdr) < 0)
+                       return -1;
+               if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC && hdr.tag == 0) {
+                       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 ||
+                           x509_parse_time(hdr.payload, hdr.length, hdr.tag,
+                                           &update) < 0) {
+                               wpa_printf(MSG_DEBUG,
+                                          "OCSP: Failed to parse nextUpdate");
+                               return -1;
+                       }
+                       wpa_printf(MSG_DEBUG, "OCSP: nextUpdate %lu",
+                                  (unsigned long) update);
+                       pos = next;
+                       if ((unsigned long) now.sec > (unsigned long) update) {
+                               wpa_printf(MSG_DEBUG, "OCSP: nextUpdate time in the past (response has expired)");
+                               return -1;
+                       }
+               }
+       }
+
+       /* singleExtensions  [1]  EXPLICIT Extensions OPTIONAL */
+       if (pos < end) {
+               wpa_hexdump(MSG_MSGDUMP, "OCSP: singleExtensions",
+                           pos, end - pos);
+               /* Ignore for now */
+       }
+
+       if (cert_status == 0 /* good */)
+               *res = TLS_OCSP_GOOD;
+       else if (cert_status == 1 /* revoked */)
+               *res = TLS_OCSP_REVOKED;
+       else
+               return -1;
+       return 0;
+}
+
+
+static enum tls_ocsp_result
+tls_process_ocsp_responses(struct tlsv1_client *conn,
+                          struct x509_certificate *cert,
+                          struct x509_certificate *issuer, const u8 *resp,
+                          size_t len)
+{
+       struct asn1_hdr hdr;
+       const u8 *pos, *end;
+       enum tls_ocsp_result res;
+
+       pos = resp;
+       end = resp + len;
+       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);
+                       return TLS_OCSP_INVALID;
+               }
+               if (tls_process_ocsp_single_response(conn, cert, issuer,
+                                                    hdr.payload, hdr.length,
+                                                    &res) == 0)
+                       return res;
+               pos = hdr.payload + hdr.length;
+       }
+
+       wpa_printf(MSG_DEBUG,
+                  "OCSP: Did not find a response matching the server certificate");
+       return TLS_OCSP_NO_RESPONSE;
+}
+
+
+static enum tls_ocsp_result
+tls_process_basic_ocsp_response(struct tlsv1_client *conn,
+                               struct x509_certificate *srv_cert,
+                               const u8 *resp, size_t len)
+{
+       struct asn1_hdr hdr;
+       const u8 *pos, *end;
+       const u8 *resp_data, *sign_value, *key_hash = NULL, *responses;
+       const u8 *resp_data_signed;
+       size_t resp_data_len, sign_value_len, responses_len;
+       size_t resp_data_signed_len;
+       struct x509_algorithm_identifier alg;
+       struct x509_certificate *certs = NULL, *last_cert = NULL;
+       struct x509_certificate *issuer, *signer;
+       struct x509_name name; /* used if key_hash == NULL */
+       char buf[100];
+       os_time_t produced_at;
+       enum tls_ocsp_result res;
+
+       wpa_hexdump(MSG_MSGDUMP, "OCSP: BasicOCSPResponse", resp, len);
+
+       os_memset(&name, 0, sizeof(name));
+
+       /*
+        * RFC 6960, 4.2.1:
+        * BasicOCSPResponse       ::= SEQUENCE {
+        *    tbsResponseData      ResponseData,
+        *    signatureAlgorithm   AlgorithmIdentifier,
+        *    signature            BIT STRING,
+        *    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);
+               return TLS_OCSP_INVALID;
+       }
+       pos = hdr.payload;
+       end = hdr.payload + hdr.length;
+
+       /* 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);
+               return TLS_OCSP_INVALID;
+       }
+       resp_data = hdr.payload;
+       resp_data_len = hdr.length;
+       resp_data_signed = pos;
+       pos = hdr.payload + hdr.length;
+       resp_data_signed_len = pos - resp_data_signed;
+
+       /* signatureAlgorithm  AlgorithmIdentifier */
+       if (x509_parse_algorithm_identifier(pos, end - pos, &alg, &pos))
+               return TLS_OCSP_INVALID;
+
+       /* 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);
+               return TLS_OCSP_INVALID;
+       }
+       if (hdr.length < 1)
+               return TLS_OCSP_INVALID;
+       pos = hdr.payload;
+       if (*pos) {
+               wpa_printf(MSG_DEBUG, "OCSP: BITSTRING - %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
+                * not a multiple of eight.
+                */
+               return TLS_OCSP_INVALID;
+       }
+       sign_value = pos + 1;
+       sign_value_len = hdr.length - 1;
+       pos += hdr.length;
+       wpa_hexdump(MSG_MSGDUMP, "OCSP: signature", sign_value, sign_value_len);
+
+       /* 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);
+                       return TLS_OCSP_INVALID;
+               }
+               wpa_hexdump(MSG_MSGDUMP, "OCSP: certs",
+                           hdr.payload, hdr.length);
+               pos = hdr.payload;
+               end = hdr.payload + hdr.length;
+               while (pos < end) {
+                       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);
+                               goto fail;
+                       }
+
+                       cert = x509_certificate_parse(hdr.payload, hdr.length);
+                       if (!cert)
+                               goto fail;
+                       if (last_cert) {
+                               last_cert->next = cert;
+                               last_cert = cert;
+                       } else {
+                               last_cert = certs = cert;
+                       }
+                       pos = hdr.payload + hdr.length;
+               }
+       }
+
+       /*
+        * ResponseData ::= SEQUENCE {
+        *    version              [0] EXPLICIT Version DEFAULT v1,
+        *    responderID              ResponderID,
+        *    producedAt               GeneralizedTime,
+        *    responses                SEQUENCE OF SingleResponse,
+        *    responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
+        */
+       pos = resp_data;
+       end = resp_data + resp_data_len;
+       wpa_hexdump(MSG_MSGDUMP, "OCSP: ResponseData", pos, end - pos);
+
+       /*
+        * 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.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);
+                       goto fail;
+               }
+               wpa_printf(MSG_DEBUG, "OCSP: ResponseData version %u",
+                          hdr.payload[0]);
+               if (hdr.payload[0] != 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "OCSP: Unsupported ResponseData version %u",
+                                  hdr.payload[0]);
+                       goto no_resp;
+               }
+               pos = hdr.payload + hdr.length;
+       } else {
+               wpa_printf(MSG_DEBUG,
+                          "OCSP: Default ResponseData version (v1)");
+       }
+
+       /*
+        * ResponderID ::= CHOICE {
+        *    byName              [1] Name,
+        *    byKey               [2] KeyHash }
+        */
+       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);
+               goto fail;
+       }
+
+       if (hdr.tag == 1) {
+               /* Name */
+               if (x509_parse_name(hdr.payload, hdr.length, &name, &pos) < 0)
+                       goto fail;
+               x509_name_string(&name, buf, sizeof(buf));
+               wpa_printf(MSG_DEBUG, "OCSP: ResponderID byName Name: %s", buf);
+       } 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);
+                       goto fail;
+               }
+               key_hash = hdr.payload;
+               wpa_hexdump(MSG_DEBUG, "OCSP: ResponderID byKey KeyHash",
+                           key_hash, hdr.length);
+               if (hdr.length != SHA1_MAC_LEN) {
+                       wpa_printf(MSG_DEBUG,
+                                  "OCSP: Unexpected byKey KeyHash length %u - expected %u for SHA-1",
+                                  hdr.length, SHA1_MAC_LEN);
+                       goto fail;
+               }
+               pos = hdr.payload + hdr.length;
+       } else {
+               wpa_printf(MSG_DEBUG, "OCSP: Unexpected ResponderID CHOICE %u",
+                          hdr.tag);
+               goto fail;
+       }
+
+       /* producedAt  GeneralizedTime */
+       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_UNIVERSAL ||
+           hdr.tag != ASN1_TAG_GENERALIZEDTIME ||
+           x509_parse_time(hdr.payload, hdr.length, hdr.tag,
+                           &produced_at) < 0) {
+               wpa_printf(MSG_DEBUG, "OCSP: Failed to parse producedAt");
+               goto fail;
+       }
+       wpa_printf(MSG_DEBUG, "OCSP: producedAt %lu",
+                  (unsigned long) produced_at);
+       pos = hdr.payload + hdr.length;
+
+       /* 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);
+               goto fail;
+       }
+       responses = hdr.payload;
+       responses_len = hdr.length;
+       wpa_hexdump(MSG_MSGDUMP, "OCSP: responses", responses, responses_len);
+       pos = hdr.payload + hdr.length;
+
+       if (pos < end) {
+               /* responseExtensions  [1] EXPLICIT Extensions OPTIONAL */
+               wpa_hexdump(MSG_MSGDUMP, "OCSP: responseExtensions",
+                           pos, end - pos);
+               /* Ignore for now. */
+       }
+
+       if (!srv_cert) {
+               wpa_printf(MSG_DEBUG,
+                          "OCSP: Server certificate not known - cannot check OCSP response");
+               goto no_resp;
+       }
+
+       if (srv_cert->next) {
+               /* Issuer has already been verified in the chain */
+               issuer = srv_cert->next;
+       } else {
+               /* Find issuer from the set of trusted certificates */
+               for (issuer = conn->cred ? conn->cred->trusted_certs : NULL;
+                    issuer; issuer = issuer->next) {
+                       if (x509_name_compare(&srv_cert->issuer,
+                                             &issuer->subject) == 0)
+                               break;
+               }
+       }
+       if (!issuer) {
+               wpa_printf(MSG_DEBUG,
+                          "OCSP: Server certificate issuer not known - cannot check OCSP response");
+               goto no_resp;
+       }
+
+       if (ocsp_responder_id_match(issuer, &name, key_hash)) {
+               wpa_printf(MSG_DEBUG,
+                          "OCSP: Server certificate issuer certificate matches ResponderID");
+               signer = issuer;
+       } else {
+               for (signer = certs; signer; signer = signer->next) {
+                       if (!ocsp_responder_id_match(signer, &name, key_hash) ||
+                           x509_name_compare(&srv_cert->issuer,
+                                             &issuer->subject) != 0 ||
+                           !(signer->ext_key_usage &
+                             X509_EXT_KEY_USAGE_OCSP) ||
+                           x509_certificate_check_signature(issuer, signer) <
+                           0)
+                               continue;
+                       wpa_printf(MSG_DEBUG,
+                                  "OCSP: An extra certificate from the response matches ResponderID and is trusted as an OCSP signer");
+                       break;
+               }
+               if (!signer) {
+                       wpa_printf(MSG_DEBUG,
+                                  "OCSP: Could not find OCSP signer certificate");
+                       goto no_resp;
+               }
+       }
+
+       x509_free_name(&name);
+       os_memset(&name, 0, sizeof(name));
+       x509_certificate_chain_free(certs);
+       certs = NULL;
+
+       if (x509_check_signature(signer, &alg, sign_value, sign_value_len,
+                                resp_data_signed, resp_data_signed_len) < 0) {
+                   wpa_printf(MSG_DEBUG, "OCSP: Invalid signature");
+                   return TLS_OCSP_INVALID;
+       }
+
+       res = tls_process_ocsp_responses(conn, srv_cert, issuer,
+                                        responses, responses_len);
+       if (res == TLS_OCSP_REVOKED)
+               srv_cert->ocsp_revoked = 1;
+       else if (res == TLS_OCSP_GOOD)
+               srv_cert->ocsp_good = 1;
+       return res;
+
+no_resp:
+       x509_free_name(&name);
+       x509_certificate_chain_free(certs);
+       return TLS_OCSP_NO_RESPONSE;
+
+fail:
+       x509_free_name(&name);
+       x509_certificate_chain_free(certs);
+       return TLS_OCSP_INVALID;
+}
+
+
+enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn,
+                                              const u8 *resp, size_t len)
+{
+       struct asn1_hdr hdr;
+       const u8 *pos, *end;
+       u8 resp_status;
+       struct asn1_oid oid;
+       char obuf[80];
+       struct x509_certificate *cert;
+       enum tls_ocsp_result res = TLS_OCSP_NO_RESPONSE;
+       enum tls_ocsp_result res_first = res;
+
+       wpa_hexdump(MSG_MSGDUMP, "TLSv1: OCSPResponse", resp, len);
+
+       /*
+        * RFC 6960, 4.2.1:
+        * OCSPResponse ::= SEQUENCE {
+        *    responseStatus  OCSPResponseStatus,
+        *    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);
+               return TLS_OCSP_INVALID;
+       }
+       pos = hdr.payload;
+       end = hdr.payload + hdr.length;
+
+       /* 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);
+               return TLS_OCSP_INVALID;
+       }
+       resp_status = hdr.payload[0];
+       wpa_printf(MSG_DEBUG, "OCSP: responseStatus %u", resp_status);
+       pos = hdr.payload + hdr.length;
+       if (resp_status != OCSP_RESP_STATUS_SUCCESSFUL) {
+               wpa_printf(MSG_DEBUG, "OCSP: No stapling result");
+               return TLS_OCSP_NO_RESPONSE;
+       }
+
+       /* responseBytes   [0] EXPLICIT ResponseBytes OPTIONAL */
+       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);
+               return TLS_OCSP_INVALID;
+       }
+
+       /*
+        * ResponseBytes ::= SEQUENCE {
+        *     responseType   OBJECT IDENTIFIER,
+        *     response       OCTET STRING }
+        */
+
+       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);
+               return TLS_OCSP_INVALID;
+       }
+       pos = hdr.payload;
+       end = hdr.payload + hdr.length;
+
+       /* responseType   OBJECT IDENTIFIER */
+       if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+               wpa_printf(MSG_DEBUG,
+                          "OCSP: Failed to parse OID (responseType)");
+               return TLS_OCSP_INVALID;
+       }
+       asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+       wpa_printf(MSG_DEBUG, "OCSP: responseType %s", obuf);
+       if (!is_oid_basic_ocsp_resp(&oid)) {
+               wpa_printf(MSG_DEBUG, "OCSP: Ignore unsupported response type");
+               return TLS_OCSP_NO_RESPONSE;
+       }
+
+       /* 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);
+               return TLS_OCSP_INVALID;
+       }
+
+       cert = conn->server_cert;
+       while (cert) {
+               if (!cert->ocsp_good && !cert->ocsp_revoked) {
+                       char sbuf[128];
+
+                       x509_name_string(&cert->subject, sbuf, sizeof(sbuf));
+                       wpa_printf(MSG_DEBUG,
+                                  "OCSP: Trying to find certificate status for %s",
+                                  sbuf);
+
+                       res = tls_process_basic_ocsp_response(conn, cert,
+                                                             hdr.payload,
+                                                             hdr.length);
+                       if (cert == conn->server_cert)
+                               res_first = res;
+               }
+               if (res == TLS_OCSP_REVOKED || cert->issuer_trusted)
+                       break;
+               cert = cert->next;
+       }
+       return res == TLS_OCSP_REVOKED ? res : res_first;
+}
index 9ce9680..244c3cb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * TLSv1 client - read handshake message
- * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -27,6 +27,54 @@ static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
                                         const u8 *in_data, size_t *in_len);
 
 
+static int tls_version_disabled(struct tlsv1_client *conn, u16 ver)
+{
+       return (((conn->flags & TLS_CONN_DISABLE_TLSv1_0) &&
+                ver == TLS_VERSION_1) ||
+               ((conn->flags & TLS_CONN_DISABLE_TLSv1_1) &&
+                ver == TLS_VERSION_1_1) ||
+               ((conn->flags & TLS_CONN_DISABLE_TLSv1_2) &&
+                ver == TLS_VERSION_1_2));
+}
+
+
+static int tls_process_server_hello_extensions(struct tlsv1_client *conn,
+                                              const u8 *pos, size_t len)
+{
+       const u8 *end = pos + len;
+
+       wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello extensions",
+                   pos, len);
+       while (pos < end) {
+               u16 ext, elen;
+
+               if (end - pos < 4) {
+                       wpa_printf(MSG_INFO, "TLSv1: Truncated ServerHello extension header");
+                       return -1;
+               }
+
+               ext = WPA_GET_BE16(pos);
+               pos += 2;
+               elen = WPA_GET_BE16(pos);
+               pos += 2;
+
+               if (elen > end - pos) {
+                       wpa_printf(MSG_INFO, "TLSv1: Truncated ServerHello extension");
+                       return -1;
+               }
+
+               wpa_printf(MSG_DEBUG, "TLSv1: ServerHello ExtensionType %u",
+                          ext);
+               wpa_hexdump(MSG_DEBUG, "TLSv1: ServerHello extension data",
+                           pos, elen);
+
+               pos += elen;
+       }
+
+       return 0;
+}
+
+
 static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
                                    const u8 *in_data, size_t *in_len)
 {
@@ -76,7 +124,8 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
        if (end - pos < 2)
                goto decode_error;
        tls_version = WPA_GET_BE16(pos);
-       if (!tls_version_ok(tls_version)) {
+       if (!tls_version_ok(tls_version) ||
+           tls_version_disabled(conn, tls_version)) {
                wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
                           "ServerHello %u.%u", pos[0], pos[1]);
                tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -165,8 +214,24 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
        }
        pos++;
 
+       if (end - pos >= 2) {
+               u16 ext_len;
+
+               ext_len = WPA_GET_BE16(pos);
+               pos += 2;
+               if (end - pos < ext_len) {
+                       wpa_printf(MSG_INFO,
+                                  "TLSv1: Invalid ServerHello extension length: %u (left: %u)",
+                                  ext_len, (unsigned int) (end - pos));
+                       goto decode_error;
+               }
+
+               if (tls_process_server_hello_extensions(conn, pos, ext_len))
+                       goto decode_error;
+               pos += ext_len;
+       }
+
        if (end != pos) {
-               /* TODO: ServerHello extensions */
                wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the "
                            "end of ServerHello", pos, end - pos);
                goto decode_error;
@@ -211,6 +276,73 @@ decode_error:
 }
 
 
+static void tls_peer_cert_event(struct tlsv1_client *conn, int depth,
+                               struct x509_certificate *cert)
+{
+       union tls_event_data ev;
+       struct wpabuf *cert_buf = NULL;
+#ifdef CONFIG_SHA256
+       u8 hash[32];
+#endif /* CONFIG_SHA256 */
+       char subject[128];
+
+       if (!conn->event_cb)
+               return;
+
+       os_memset(&ev, 0, sizeof(ev));
+       if (conn->cred->cert_probe || conn->cert_in_cb) {
+               cert_buf = wpabuf_alloc_copy(cert->cert_start,
+                                            cert->cert_len);
+               ev.peer_cert.cert = cert_buf;
+       }
+#ifdef CONFIG_SHA256
+       if (cert_buf) {
+               const u8 *addr[1];
+               size_t len[1];
+               addr[0] = wpabuf_head(cert_buf);
+               len[0] = wpabuf_len(cert_buf);
+               if (sha256_vector(1, addr, len, hash) == 0) {
+                       ev.peer_cert.hash = hash;
+                       ev.peer_cert.hash_len = sizeof(hash);
+               }
+       }
+#endif /* CONFIG_SHA256 */
+
+       ev.peer_cert.depth = depth;
+       x509_name_string(&cert->subject, subject, sizeof(subject));
+       ev.peer_cert.subject = subject;
+
+       conn->event_cb(conn->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
+       wpabuf_free(cert_buf);
+}
+
+
+static void tls_cert_chain_failure_event(struct tlsv1_client *conn, int depth,
+                                        struct x509_certificate *cert,
+                                        enum tls_fail_reason reason,
+                                        const char *reason_txt)
+{
+       struct wpabuf *cert_buf = NULL;
+       union tls_event_data ev;
+       char subject[128];
+
+       if (!conn->event_cb || !cert)
+               return;
+
+       os_memset(&ev, 0, sizeof(ev));
+       ev.cert_fail.depth = depth;
+       x509_name_string(&cert->subject, subject, sizeof(subject));
+       ev.peer_cert.subject = subject;
+       ev.cert_fail.reason = reason;
+       ev.cert_fail.reason_txt = reason_txt;
+       cert_buf = wpabuf_alloc_copy(cert->cert_start,
+                                    cert->cert_len);
+       ev.cert_fail.cert = cert_buf;
+       conn->event_cb(conn->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+       wpabuf_free(cert_buf);
+}
+
+
 static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
                                   const u8 *in_data, size_t *in_len)
 {
@@ -354,6 +486,8 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
                        return -1;
                }
 
+               tls_peer_cert_event(conn, idx, cert);
+
                if (last == NULL)
                        chain = cert;
                else
@@ -364,31 +498,99 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
                pos += cert_len;
        }
 
-       if (conn->cred &&
-           x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
-                                           &reason, conn->disable_time_checks)
-           < 0) {
+       if (conn->cred && conn->cred->server_cert_only && chain) {
+               u8 hash[SHA256_MAC_LEN];
+               char buf[128];
+
+               wpa_printf(MSG_DEBUG,
+                          "TLSv1: Validate server certificate hash");
+               x509_name_string(&chain->subject, buf, sizeof(buf));
+               wpa_printf(MSG_DEBUG, "TLSv1: 0: %s", buf);
+               if (sha256_vector(1, &chain->cert_start, &chain->cert_len,
+                                 hash) < 0 ||
+                   os_memcmp(conn->cred->srv_cert_hash, hash,
+                             SHA256_MAC_LEN) != 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "TLSv1: Server certificate hash mismatch");
+                       wpa_hexdump(MSG_MSGDUMP, "TLSv1: SHA256 hash",
+                                   hash, SHA256_MAC_LEN);
+                       if (conn->event_cb) {
+                               union tls_event_data ev;
+
+                               os_memset(&ev, 0, sizeof(ev));
+                               ev.cert_fail.reason = TLS_FAIL_UNSPECIFIED;
+                               ev.cert_fail.reason_txt =
+                                       "Server certificate mismatch";
+                               ev.cert_fail.subject = buf;
+                               conn->event_cb(conn->cb_ctx,
+                                              TLS_CERT_CHAIN_FAILURE, &ev);
+                       }
+                       tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                 TLS_ALERT_BAD_CERTIFICATE);
+                       x509_certificate_chain_free(chain);
+                       return -1;
+               }
+       } else if (conn->cred && conn->cred->cert_probe) {
+               wpa_printf(MSG_DEBUG,
+                          "TLSv1: Reject server certificate on probe-only rune");
+               if (conn->event_cb) {
+                       union tls_event_data ev;
+                       char buf[128];
+
+                       os_memset(&ev, 0, sizeof(ev));
+                       ev.cert_fail.reason = TLS_FAIL_SERVER_CHAIN_PROBE;
+                       ev.cert_fail.reason_txt =
+                               "Server certificate chain probe";
+                       if (chain) {
+                               x509_name_string(&chain->subject, buf,
+                                                sizeof(buf));
+                               ev.cert_fail.subject = buf;
+                       }
+                       conn->event_cb(conn->cb_ctx, TLS_CERT_CHAIN_FAILURE,
+                                      &ev);
+               }
+               tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                         TLS_ALERT_BAD_CERTIFICATE);
+               x509_certificate_chain_free(chain);
+               return -1;
+       } else if (conn->cred && conn->cred->ca_cert_verify &&
+                  x509_certificate_chain_validate(
+                          conn->cred->trusted_certs, chain, &reason,
+                          !!(conn->flags & TLS_CONN_DISABLE_TIME_CHECKS))
+                  < 0) {
                int tls_reason;
                wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
                           "validation failed (reason=%d)", reason);
                switch (reason) {
                case X509_VALIDATE_BAD_CERTIFICATE:
                        tls_reason = TLS_ALERT_BAD_CERTIFICATE;
+                       tls_cert_chain_failure_event(
+                               conn, 0, chain, TLS_FAIL_BAD_CERTIFICATE,
+                               "bad certificate");
                        break;
                case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
                        tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
                        break;
                case X509_VALIDATE_CERTIFICATE_REVOKED:
                        tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
+                       tls_cert_chain_failure_event(
+                               conn, 0, chain, TLS_FAIL_REVOKED,
+                               "certificate revoked");
                        break;
                case X509_VALIDATE_CERTIFICATE_EXPIRED:
                        tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
+                       tls_cert_chain_failure_event(
+                               conn, 0, chain, TLS_FAIL_EXPIRED,
+                               "certificate has expired or is not yet valid");
                        break;
                case X509_VALIDATE_CERTIFICATE_UNKNOWN:
                        tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
                        break;
                case X509_VALIDATE_UNKNOWN_CA:
                        tls_reason = TLS_ALERT_UNKNOWN_CA;
+                       tls_cert_chain_failure_event(
+                               conn, 0, chain, TLS_FAIL_UNTRUSTED,
+                               "unknown CA");
                        break;
                default:
                        tls_reason = TLS_ALERT_BAD_CERTIFICATE;
@@ -399,7 +601,25 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
                return -1;
        }
 
-       x509_certificate_chain_free(chain);
+       if (conn->cred && !conn->cred->server_cert_only && chain &&
+           (chain->extensions_present & X509_EXT_EXT_KEY_USAGE) &&
+           !(chain->ext_key_usage &
+             (X509_EXT_KEY_USAGE_ANY | X509_EXT_KEY_USAGE_SERVER_AUTH))) {
+               tls_cert_chain_failure_event(
+                       conn, 0, chain, TLS_FAIL_BAD_CERTIFICATE,
+                       "certificate not allowed for server authentication");
+               tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                         TLS_ALERT_BAD_CERTIFICATE);
+               x509_certificate_chain_free(chain);
+               return -1;
+       }
+
+       if (conn->flags & TLS_CONN_REQUEST_OCSP) {
+               x509_certificate_chain_free(conn->server_cert);
+               conn->server_cert = chain;
+       } else {
+               x509_certificate_chain_free(chain);
+       }
 
        *in_len = end - in_data;
 
@@ -507,7 +727,7 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
        server_params_end = pos;
 
        if (key_exchange == TLS_KEY_X_DHE_RSA) {
-               u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+               u8 hash[64];
                int hlen;
 
                if (conn->rl.tls_version == TLS_VERSION_1_2) {
@@ -524,18 +744,21 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
                         */
                        if (end - pos < 2)
                                goto fail;
-                       if (pos[0] != TLS_HASH_ALG_SHA256 ||
+                       if ((pos[0] != TLS_HASH_ALG_SHA256 &&
+                            pos[0] != TLS_HASH_ALG_SHA384 &&
+                            pos[0] != TLS_HASH_ALG_SHA512) ||
                            pos[1] != TLS_SIGN_ALG_RSA) {
                                wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/signature(%u) algorithm",
                                           pos[0], pos[1]);
                                goto fail;
                        }
-                       pos += 2;
 
                        hlen = tlsv12_key_x_server_params_hash(
-                               conn->rl.tls_version, conn->client_random,
+                               conn->rl.tls_version, pos[0],
+                               conn->client_random,
                                conn->server_random, server_params,
                                server_params_end - server_params, hash);
+                       pos += 2;
 #else /* CONFIG_TLSV12 */
                        goto fail;
 #endif /* CONFIG_TLSV12 */
@@ -567,6 +790,229 @@ fail:
 }
 
 
+static enum tls_ocsp_result
+tls_process_certificate_status_ocsp_response(struct tlsv1_client *conn,
+                                            const u8 *pos, size_t len)
+{
+       const u8 *end = pos + len;
+       u32 ocsp_resp_len;
+
+       /* opaque OCSPResponse<1..2^24-1>; */
+       if (end - pos < 3) {
+               wpa_printf(MSG_INFO, "TLSv1: Too short OCSPResponse");
+               tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+               return TLS_OCSP_INVALID;
+       }
+       ocsp_resp_len = WPA_GET_BE24(pos);
+       pos += 3;
+       if (end - pos < ocsp_resp_len) {
+               wpa_printf(MSG_INFO, "TLSv1: Truncated OCSPResponse");
+               tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+               return TLS_OCSP_INVALID;
+       }
+
+       return tls_process_ocsp_response(conn, pos, ocsp_resp_len);
+}
+
+
+static int tls_process_certificate_status(struct tlsv1_client *conn, u8 ct,
+                                          const u8 *in_data, size_t *in_len)
+{
+       const u8 *pos, *end;
+       size_t left, len;
+       u8 type, status_type;
+       enum tls_ocsp_result res;
+       struct x509_certificate *cert;
+       int depth;
+
+       if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+               wpa_printf(MSG_DEBUG,
+                          "TLSv1: Expected Handshake; received content type 0x%x",
+                          ct);
+               tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                         TLS_ALERT_UNEXPECTED_MESSAGE);
+               return -1;
+       }
+
+       pos = in_data;
+       left = *in_len;
+
+       if (left < 4) {
+               wpa_printf(MSG_DEBUG,
+                          "TLSv1: Too short CertificateStatus (left=%lu)",
+                          (unsigned long) left);
+               tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+               return -1;
+       }
+
+       type = *pos++;
+       len = WPA_GET_BE24(pos);
+       pos += 3;
+       left -= 4;
+
+       if (len > left) {
+               wpa_printf(MSG_DEBUG,
+                          "TLSv1: Mismatch in CertificateStatus length (len=%lu != left=%lu)",
+                          (unsigned long) len, (unsigned long) left);
+               tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+               return -1;
+       }
+
+       end = pos + len;
+
+       if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS) {
+               wpa_printf(MSG_DEBUG,
+                          "TLSv1: Received unexpected handshake message %d (expected CertificateStatus)",
+                          type);
+               tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                         TLS_ALERT_UNEXPECTED_MESSAGE);
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateStatus");
+
+       /*
+        * struct {
+        *     CertificateStatusType status_type;
+        *     select (status_type) {
+        *         case ocsp: OCSPResponse;
+        *         case ocsp_multi: OCSPResponseList;
+        *     } response;
+        * } CertificateStatus;
+        */
+       if (end - pos < 1) {
+               wpa_printf(MSG_INFO, "TLSv1: Too short CertificateStatus");
+               tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+               return -1;
+       }
+       status_type = *pos++;
+       wpa_printf(MSG_DEBUG, "TLSv1: CertificateStatus status_type %u",
+                  status_type);
+
+       if (status_type == 1 /* ocsp */) {
+               res = tls_process_certificate_status_ocsp_response(
+                       conn, pos, end - pos);
+       } else if (status_type == 2 /* ocsp_multi */) {
+               int good = 0, revoked = 0;
+               u32 resp_len;
+
+               res = TLS_OCSP_NO_RESPONSE;
+
+               /*
+                * opaque OCSPResponse<0..2^24-1>;
+                *
+                * struct {
+                *   OCSPResponse ocsp_response_list<1..2^24-1>;
+                * } OCSPResponseList;
+                */
+               if (end - pos < 3) {
+                       wpa_printf(MSG_DEBUG,
+                                  "TLSv1: Truncated OCSPResponseList");
+                       res = TLS_OCSP_INVALID;
+                       goto done;
+               }
+               resp_len = WPA_GET_BE24(pos);
+               pos += 3;
+               if (end - pos < resp_len) {
+                       wpa_printf(MSG_DEBUG,
+                                  "TLSv1: Truncated OCSPResponseList(len=%u)",
+                                  resp_len);
+                       res = TLS_OCSP_INVALID;
+                       goto done;
+               }
+               end = pos + resp_len;
+
+               while (end - pos >= 3) {
+                       resp_len = WPA_GET_BE24(pos);
+                       pos += 3;
+                       if (resp_len > end - pos) {
+                               wpa_printf(MSG_DEBUG,
+                                          "TLSv1: Truncated OCSPResponse(len=%u; left=%d) in ocsp_multi",
+                                          resp_len, (int) (end - pos));
+                               res = TLS_OCSP_INVALID;
+                               break;
+                       }
+                       if (!resp_len)
+                               continue; /* Skip an empty response */
+                       res = tls_process_certificate_status_ocsp_response(
+                               conn, pos - 3, resp_len + 3);
+                       if (res == TLS_OCSP_REVOKED)
+                               revoked++;
+                       else if (res == TLS_OCSP_GOOD)
+                               good++;
+                       pos += resp_len;
+               }
+
+               if (revoked)
+                       res = TLS_OCSP_REVOKED;
+               else if (good)
+                       res = TLS_OCSP_GOOD;
+       } else {
+               wpa_printf(MSG_DEBUG,
+                          "TLSv1: Ignore unsupported CertificateStatus");
+               goto skip;
+       }
+
+done:
+       if (res == TLS_OCSP_REVOKED) {
+               tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                         TLS_ALERT_CERTIFICATE_REVOKED);
+               for (cert = conn->server_cert, depth = 0; cert;
+                    cert = cert->next, depth++) {
+                       if (cert->ocsp_revoked) {
+                               tls_cert_chain_failure_event(
+                                       conn, depth, cert, TLS_FAIL_REVOKED,
+                                       "certificate revoked");
+                       }
+               }
+               return -1;
+       }
+
+       if (conn->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+               /*
+                * Verify that each certificate on the chain that is not part
+                * of the trusted certificates has a good status. If not,
+                * terminate handshake.
+                */
+               for (cert = conn->server_cert, depth = 0; cert;
+                    cert = cert->next, depth++) {
+                       if (!cert->ocsp_good) {
+                               tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                         TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
+                               tls_cert_chain_failure_event(
+                                       conn, depth, cert,
+                                       TLS_FAIL_UNSPECIFIED,
+                                       "bad certificate status response");
+                               return -1;
+                       }
+                       if (cert->issuer_trusted)
+                               break;
+               }
+       }
+
+       if ((conn->flags & TLS_CONN_REQUIRE_OCSP) && res != TLS_OCSP_GOOD) {
+               tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                         res == TLS_OCSP_INVALID ? TLS_ALERT_DECODE_ERROR :
+                         TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
+               if (conn->server_cert)
+                       tls_cert_chain_failure_event(
+                               conn, 0, conn->server_cert,
+                               TLS_FAIL_UNSPECIFIED,
+                               "bad certificate status response");
+               return -1;
+       }
+
+       conn->ocsp_resp_received = 1;
+
+skip:
+       *in_len = end - in_data;
+
+       conn->state = SERVER_KEY_EXCHANGE;
+
+       return 0;
+}
+
+
 static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
                                           const u8 *in_data, size_t *in_len)
 {
@@ -608,6 +1054,10 @@ static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
 
        end = pos + len;
 
+       if ((conn->flags & TLS_CONN_REQUEST_OCSP) &&
+           type == TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS)
+               return tls_process_certificate_status(conn, ct, in_data,
+                                                     in_len);
        if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
                return tls_process_certificate_request(conn, ct, in_data,
                                                       in_len);
@@ -617,7 +1067,9 @@ static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
        if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) {
                wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
                           "message %d (expected ServerKeyExchange/"
-                          "CertificateRequest/ServerHelloDone)", type);
+                          "CertificateRequest/ServerHelloDone%s)", type,
+                          (conn->flags & TLS_CONN_REQUEST_OCSP) ?
+                          "/CertificateStatus" : "");
                tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
                          TLS_ALERT_UNEXPECTED_MESSAGE);
                return -1;
@@ -771,6 +1223,15 @@ static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
 
        wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone");
 
+       if ((conn->flags & TLS_CONN_REQUIRE_OCSP) &&
+           !conn->ocsp_resp_received) {
+               wpa_printf(MSG_INFO,
+                          "TLSv1: No OCSP response received - reject handshake");
+               tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                         TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
+               return -1;
+       }
+
        *in_len = end - in_data;
 
        conn->state = CLIENT_KEY_EXCHANGE;
index d192f44..04d895e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * TLSv1 client - write handshake message
- * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -47,8 +47,28 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
        u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr;
        struct os_time now;
        size_t len, i;
+       u8 *ext_start;
+       u16 tls_version = TLS_VERSION;
 
-       wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello");
+       /* 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) {
+               wpa_printf(MSG_INFO, "TLSv1: No TLS version allowed");
+               return NULL;
+       }
+
+       wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello (ver %s)",
+                  tls_version_str(tls_version));
        *out_len = 0;
 
        os_get_time(&now);
@@ -61,7 +81,7 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
        wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
                    conn->client_random, TLS_RANDOM_LEN);
 
-       len = 100 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
+       len = 150 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
        hello = os_malloc(len);
        if (hello == NULL)
                return NULL;
@@ -81,7 +101,7 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
        pos += 3;
        /* body - ClientHello */
        /* ProtocolVersion client_version */
-       WPA_PUT_BE16(pos, TLS_VERSION);
+       WPA_PUT_BE16(pos, tls_version);
        pos += 2;
        /* Random random: uint32 gmt_unix_time, opaque random_bytes */
        os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN);
@@ -101,12 +121,124 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
        *pos++ = 1;
        *pos++ = TLS_COMPRESSION_NULL;
 
+       /* Extension */
+       ext_start = pos;
+       pos += 2;
+
+#ifdef CONFIG_TLSV12
+       if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+               /*
+                * Add signature_algorithms extension since we support only
+                * SHA256 (and not the default SHA1) with TLSv1.2.
+                */
+               /* ExtensionsType extension_type = signature_algorithms(13) */
+               WPA_PUT_BE16(pos, TLS_EXT_SIGNATURE_ALGORITHMS);
+               pos += 2;
+               /* opaque extension_data<0..2^16-1> length */
+               WPA_PUT_BE16(pos, 8);
+               pos += 2;
+               /* supported_signature_algorithms<2..2^16-2> length */
+               WPA_PUT_BE16(pos, 6);
+               pos += 2;
+               /* supported_signature_algorithms */
+               *pos++ = TLS_HASH_ALG_SHA512;
+               *pos++ = TLS_SIGN_ALG_RSA;
+               *pos++ = TLS_HASH_ALG_SHA384;
+               *pos++ = TLS_SIGN_ALG_RSA;
+               *pos++ = TLS_HASH_ALG_SHA256;
+               *pos++ = TLS_SIGN_ALG_RSA;
+       }
+#endif /* CONFIG_TLSV12 */
+
        if (conn->client_hello_ext) {
                os_memcpy(pos, conn->client_hello_ext,
                          conn->client_hello_ext_len);
                pos += conn->client_hello_ext_len;
        }
 
+       if (conn->flags & TLS_CONN_REQUEST_OCSP) {
+               wpa_printf(MSG_DEBUG,
+                          "TLSv1: Add status_request extension for OCSP stapling");
+               /* ExtensionsType extension_type = status_request(5) */
+               WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST);
+               pos += 2;
+               /* opaque extension_data<0..2^16-1> length */
+               WPA_PUT_BE16(pos, 5);
+               pos += 2;
+
+               /*
+                * RFC 6066, 8:
+                * struct {
+                *     CertificateStatusType status_type;
+                *     select (status_type) {
+                *         case ocsp: OCSPStatusRequest;
+                *     } request;
+                * } CertificateStatusRequest;
+                *
+                * enum { ocsp(1), (255) } CertificateStatusType;
+                */
+               *pos++ = 1; /* status_type = ocsp(1) */
+
+               /*
+                * struct {
+                *     ResponderID responder_id_list<0..2^16-1>;
+                *     Extensions  request_extensions;
+                * } OCSPStatusRequest;
+                *
+                * opaque ResponderID<1..2^16-1>;
+                * opaque Extensions<0..2^16-1>;
+                */
+               WPA_PUT_BE16(pos, 0); /* responder_id_list(empty) */
+               pos += 2;
+               WPA_PUT_BE16(pos, 0); /* request_extensions(empty) */
+               pos += 2;
+
+               wpa_printf(MSG_DEBUG,
+                          "TLSv1: Add status_request_v2 extension for OCSP stapling");
+               /* ExtensionsType extension_type = status_request_v2(17) */
+               WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST_V2);
+               pos += 2;
+               /* opaque extension_data<0..2^16-1> length */
+               WPA_PUT_BE16(pos, 7);
+               pos += 2;
+
+               /*
+                * RFC 6961, 2.2:
+                * struct {
+                *     CertificateStatusType status_type;
+                *     uint16 request_length;
+                *     select (status_type) {
+                *         case ocsp: OCSPStatusRequest;
+                *         case ocsp_multi: OCSPStatusRequest;
+                *     } request;
+                * } CertificateStatusRequestItemV2;
+                *
+                * enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;
+                *
+                * struct {
+                * CertificateStatusRequestItemV2
+                *     certificate_status_req_list<1..2^16-1>;
+                * } CertificateStatusRequestListV2;
+                */
+
+               /* certificate_status_req_list<1..2^16-1> */
+               WPA_PUT_BE16(pos, 5);
+               pos += 2;
+
+               /* CertificateStatusRequestItemV2 */
+               *pos++ = 2; /* status_type = ocsp_multi(2) */
+               /* OCSPStatusRequest as shown above for v1 */
+               WPA_PUT_BE16(pos, 0); /* responder_id_list(empty) */
+               pos += 2;
+               WPA_PUT_BE16(pos, 0); /* request_extensions(empty) */
+               pos += 2;
+       }
+
+       if (pos == ext_start + 2)
+               pos -= 2; /* no extensions */
+       else
+               WPA_PUT_BE16(ext_start, pos - ext_start - 2);
+
        WPA_PUT_BE24(hs_length, pos - hs_length - 3);
        tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 
@@ -134,6 +266,11 @@ static int tls_write_client_certificate(struct tlsv1_client *conn,
        struct x509_certificate *cert;
 
        pos = *msgpos;
+       if (TLS_RECORD_HEADER_LEN + 1 + 3 + 3 > end - pos) {
+               tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                         TLS_ALERT_INTERNAL_ERROR);
+               return -1;
+       }
 
        wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
        rhdr = pos;
@@ -154,7 +291,7 @@ static int tls_write_client_certificate(struct tlsv1_client *conn,
        pos += 3;
        cert = conn->cred ? conn->cred->cert : NULL;
        while (cert) {
-               if (pos + 3 + cert->cert_len > end) {
+               if (3 + cert->cert_len > (size_t) (end - pos)) {
                        wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
                                   "for Certificate (cert_len=%lu left=%lu)",
                                   (unsigned long) cert->cert_len,
@@ -265,9 +402,16 @@ static int tlsv1_key_x_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
        wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
                    dh_yc, dh_yc_len);
 
+       if (end - *pos < 2) {
+               tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                         TLS_ALERT_INTERNAL_ERROR);
+               os_free(csecret);
+               os_free(dh_yc);
+               return -1;
+       }
        WPA_PUT_BE16(*pos, dh_yc_len);
        *pos += 2;
-       if (*pos + dh_yc_len > end) {
+       if (dh_yc_len > (size_t) (end - *pos)) {
                wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the "
                           "message buffer for Yc");
                tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -789,6 +933,8 @@ static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn,
 
        wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed "
                   "successfully");
+       if (!conn->session_resumed && conn->use_session_ticket)
+               conn->session_resumed = 1;
        conn->state = ESTABLISHED;
 
        return msg;
index dabc12a..6b28417 100644 (file)
@@ -335,7 +335,7 @@ int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
 
 
 #ifdef CONFIG_TLSV12
-int tlsv12_key_x_server_params_hash(u16 tls_version,
+int tlsv12_key_x_server_params_hash(u16 tls_version, u8 hash_alg,
                                    const u8 *client_random,
                                    const u8 *server_random,
                                    const u8 *server_params,
@@ -343,14 +343,30 @@ int tlsv12_key_x_server_params_hash(u16 tls_version,
 {
        size_t hlen;
        struct crypto_hash *ctx;
-
-       ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0);
+       enum crypto_hash_alg alg;
+
+       switch (hash_alg) {
+       case TLS_HASH_ALG_SHA256:
+               alg = CRYPTO_HASH_ALG_SHA256;
+               hlen = SHA256_MAC_LEN;
+               break;
+       case TLS_HASH_ALG_SHA384:
+               alg = CRYPTO_HASH_ALG_SHA384;
+               hlen = 48;
+               break;
+       case TLS_HASH_ALG_SHA512:
+               alg = CRYPTO_HASH_ALG_SHA512;
+               hlen = 64;
+               break;
+       default:
+               return -1;
+       }
+       ctx = crypto_hash_init(alg, NULL, 0);
        if (ctx == NULL)
                return -1;
        crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
        crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
        crypto_hash_update(ctx, server_params, server_params_len);
-       hlen = SHA256_MAC_LEN;
        if (crypto_hash_finish(ctx, hash, &hlen) < 0)
                return -1;
 
@@ -469,6 +485,21 @@ int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
                        wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = SHA-256");
                        decrypted = buf + 19;
                        buflen -= 19;
+               } else if (buflen >= 19 + 48 &&
+                   os_memcmp(buf, "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01"
+                             "\x65\x03\x04\x02\x02\x05\x00\x04\x30", 19) == 0)
+               {
+                       wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = SHA-384");
+                       decrypted = buf + 19;
+                       buflen -= 19;
+               } else if (buflen >= 19 + 64 &&
+                   os_memcmp(buf, "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01"
+                             "\x65\x03\x04\x02\x03\x05\x00\x04\x40", 19) == 0)
+               {
+                       wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = SHA-512");
+                       decrypted = buf + 19;
+                       buflen -= 19;
+
                } else {
                        wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized DigestInfo");
                        os_free(buf);
index 26e68af..e30b15a 100644 (file)
@@ -169,6 +169,8 @@ enum {
 #define TLS_EXT_TRUSTED_CA_KEYS                        3 /* RFC 4366 */
 #define TLS_EXT_TRUNCATED_HMAC                 4 /* RFC 4366 */
 #define TLS_EXT_STATUS_REQUEST                 5 /* RFC 4366 */
+#define TLS_EXT_SIGNATURE_ALGORITHMS           13 /* RFC 5246 */
+#define TLS_EXT_STATUS_REQUEST_V2              17 /* RFC 6961 */
 #define TLS_EXT_SESSION_TICKET                 35 /* RFC 4507 */
 
 #define TLS_EXT_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */
@@ -257,7 +259,8 @@ int tls_version_ok(u16 ver);
 const char * tls_version_str(u16 ver);
 int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
            const u8 *seed, size_t seed_len, u8 *out, size_t outlen);
-int tlsv12_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
+int tlsv12_key_x_server_params_hash(u16 tls_version, u8 hash_Alg,
+                                   const u8 *client_random,
                                    const u8 *server_random,
                                    const u8 *server_params,
                                    size_t server_params_len, u8 *hash);
index 1ea6827..52c1ae0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * TLSv1 credentials
- * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, 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,9 @@
 #include "common.h"
 #include "base64.h"
 #include "crypto/crypto.h"
+#include "crypto/sha1.h"
+#include "pkcs5.h"
+#include "pkcs8.h"
 #include "x509v3.h"
 #include "tlsv1_cred.h"
 
@@ -33,6 +36,8 @@ void tlsv1_cred_free(struct tlsv1_credentials *cred)
        crypto_private_key_free(cred->key);
        os_free(cred->dh_p);
        os_free(cred->dh_g);
+       os_free(cred->ocsp_stapling_response);
+       os_free(cred->ocsp_stapling_response_multi);
        os_free(cred);
 }
 
@@ -190,6 +195,43 @@ int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
                      const u8 *cert_blob, size_t cert_blob_len,
                      const char *path)
 {
+       if (cert && os_strncmp(cert, "hash://", 7) == 0) {
+               const char *pos = cert + 7;
+               if (os_strncmp(pos, "server/sha256/", 14) != 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "TLSv1: Unsupported ca_cert hash value '%s'",
+                                  cert);
+                       return -1;
+               }
+               pos += 14;
+               if (os_strlen(pos) != 32 * 2) {
+                       wpa_printf(MSG_DEBUG,
+                                  "TLSv1: Unexpected SHA256 hash length in ca_cert '%s'",
+                                  cert);
+                       return -1;
+               }
+               if (hexstr2bin(pos, cred->srv_cert_hash, 32) < 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "TLSv1: Invalid SHA256 hash value in ca_cert '%s'",
+                                  cert);
+                       return -1;
+               }
+               cred->server_cert_only = 1;
+               cred->ca_cert_verify = 0;
+               wpa_printf(MSG_DEBUG,
+                          "TLSv1: Checking only server certificate match");
+               return 0;
+       }
+
+       if (cert && os_strncmp(cert, "probe://", 8) == 0) {
+               cred->cert_probe = 1;
+               cred->ca_cert_verify = 0;
+               wpa_printf(MSG_DEBUG, "TLSv1: Only probe server certificate");
+               return 0;
+       }
+
+       cred->ca_cert_verify = cert || cert_blob || path;
+
        if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
                                 cert_blob, cert_blob_len) < 0)
                return -1;
@@ -288,6 +330,735 @@ static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
 }
 
 
+#ifdef PKCS12_FUNCS
+
+static int oid_is_rsadsi(struct asn1_oid *oid)
+{
+       return oid->len >= 4 &&
+               oid->oid[0] == 1 /* iso */ &&
+               oid->oid[1] == 2 /* member-body */ &&
+               oid->oid[2] == 840 /* us */ &&
+               oid->oid[3] == 113549 /* rsadsi */;
+}
+
+
+static int pkcs12_is_bagtype_oid(struct asn1_oid *oid, unsigned long type)
+{
+       return oid->len == 9 &&
+               oid_is_rsadsi(oid) &&
+               oid->oid[4] == 1 /* pkcs */ &&
+               oid->oid[5] == 12 /* pkcs-12 */ &&
+               oid->oid[6] == 10 &&
+               oid->oid[7] == 1 /* bagtypes */ &&
+               oid->oid[8] == type;
+}
+
+
+static int is_oid_pkcs7(struct asn1_oid *oid)
+{
+       return oid->len == 7 &&
+               oid->oid[0] == 1 /* iso */ &&
+               oid->oid[1] == 2 /* member-body */ &&
+               oid->oid[2] == 840 /* us */ &&
+               oid->oid[3] == 113549 /* rsadsi */ &&
+               oid->oid[4] == 1 /* pkcs */ &&
+               oid->oid[5] == 7 /* pkcs-7 */;
+}
+
+
+static int is_oid_pkcs7_data(struct asn1_oid *oid)
+{
+       return is_oid_pkcs7(oid) && oid->oid[6] == 1 /* data */;
+}
+
+
+static int is_oid_pkcs7_enc_data(struct asn1_oid *oid)
+{
+       return is_oid_pkcs7(oid) && oid->oid[6] == 6 /* encryptedData */;
+}
+
+
+static int is_oid_pkcs9(struct asn1_oid *oid)
+{
+       return oid->len >= 6 &&
+               oid->oid[0] == 1 /* iso */ &&
+               oid->oid[1] == 2 /* member-body */ &&
+               oid->oid[2] == 840 /* us */ &&
+               oid->oid[3] == 113549 /* rsadsi */ &&
+               oid->oid[4] == 1 /* pkcs */ &&
+               oid->oid[5] == 9 /* pkcs-9 */;
+}
+
+
+static int is_oid_pkcs9_friendly_name(struct asn1_oid *oid)
+{
+       return oid->len == 7 && is_oid_pkcs9(oid) &&
+               oid->oid[6] == 20;
+}
+
+
+static int is_oid_pkcs9_local_key_id(struct asn1_oid *oid)
+{
+       return oid->len == 7 && is_oid_pkcs9(oid) &&
+               oid->oid[6] == 21;
+}
+
+
+static int is_oid_pkcs9_x509_cert(struct asn1_oid *oid)
+{
+       return oid->len == 8 && is_oid_pkcs9(oid) &&
+               oid->oid[6] == 22 /* certTypes */ &&
+               oid->oid[7] == 1 /* x509Certificate */;
+}
+
+
+static int pkcs12_keybag(struct tlsv1_credentials *cred,
+                        const u8 *buf, size_t len)
+{
+       /* TODO */
+       return 0;
+}
+
+
+static int pkcs12_pkcs8_keybag(struct tlsv1_credentials *cred,
+                              const u8 *buf, size_t len,
+                              const char *passwd)
+{
+       struct crypto_private_key *key;
+
+       /* PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo */
+       key = pkcs8_enc_key_import(buf, len, passwd);
+       if (!key)
+               return -1;
+
+       wpa_printf(MSG_DEBUG,
+                  "PKCS #12: Successfully decrypted PKCS8ShroudedKeyBag");
+       crypto_private_key_free(cred->key);
+       cred->key = key;
+
+       return 0;
+}
+
+
+static int pkcs12_certbag(struct tlsv1_credentials *cred,
+                         const u8 *buf, size_t len)
+{
+       struct asn1_hdr hdr;
+       struct asn1_oid oid;
+       char obuf[80];
+       const u8 *pos, *end;
+
+       /*
+        * CertBag ::= SEQUENCE {
+        *     certId      BAG-TYPE.&id   ({CertTypes}),
+        *     certValue   [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId})
+        * }
+        */
+
+       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);
+               return -1;
+       }
+
+       pos = hdr.payload;
+       end = hdr.payload + hdr.length;
+
+       if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+               wpa_printf(MSG_DEBUG,
+                          "PKCS #12: Failed to parse OID (certId)");
+               return -1;
+       }
+
+       asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+       wpa_printf(MSG_DEBUG, "PKCS #12: certId %s", obuf);
+
+       if (!is_oid_pkcs9_x509_cert(&oid)) {
+               wpa_printf(MSG_DEBUG,
+                          "PKCS #12: Ignored unsupported certificate type (certId %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 (certValue) - found class %d tag 0x%x",
+                          hdr.class, hdr.tag);
+               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);
+               return -1;
+       }
+
+       wpa_hexdump(MSG_DEBUG, "PKCS #12: x509Certificate",
+                   hdr.payload, hdr.length);
+       if (cred->cert) {
+               struct x509_certificate *cert;
+
+               wpa_printf(MSG_DEBUG, "PKCS #12: Ignore extra certificate");
+               cert = x509_certificate_parse(hdr.payload, hdr.length);
+               if (!cert) {
+                       wpa_printf(MSG_DEBUG,
+                                  "PKCS #12: Failed to parse x509Certificate");
+                       return 0;
+               }
+               x509_certificate_chain_free(cert);
+
+               return 0;
+       }
+       return tlsv1_set_cert(cred, NULL, hdr.payload, hdr.length);
+}
+
+
+static int pkcs12_parse_attr_friendly_name(const u8 *pos, const u8 *end)
+{
+       struct asn1_hdr hdr;
+
+       /*
+        * RFC 2985, 5.5.1:
+        * friendlyName ATTRIBUTE ::= {
+        *         WITH SYNTAX BMPString (SIZE(1..pkcs-9-ub-friendlyName))
+        *         EQUALITY MATCHING RULE caseIgnoreMatch
+        *         SINGLE VALUE TRUE
+        *          ID pkcs-9-at-friendlyName
+        * }
+        */
+       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);
+               return 0;
+       }
+       wpa_hexdump_ascii(MSG_DEBUG, "PKCS #12: friendlyName",
+                         hdr.payload, hdr.length);
+       return 0;
+}
+
+
+static int pkcs12_parse_attr_local_key_id(const u8 *pos, const u8 *end)
+{
+       struct asn1_hdr hdr;
+
+       /*
+        * RFC 2985, 5.5.2:
+        * localKeyId ATTRIBUTE ::= {
+        *         WITH SYNTAX OCTET STRING
+        *         EQUALITY MATCHING RULE octetStringMatch
+        *         SINGLE VALUE TRUE
+        *         ID pkcs-9-at-localKeyId
+        * }
+        */
+       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);
+               return -1;
+       }
+       wpa_hexdump_key(MSG_DEBUG, "PKCS #12: localKeyID",
+                       hdr.payload, hdr.length);
+       return 0;
+}
+
+
+static int pkcs12_parse_attr(const u8 *pos, size_t len)
+{
+       const u8 *end = pos + len;
+       struct asn1_hdr hdr;
+       struct asn1_oid a_oid;
+       char obuf[80];
+
+       /*
+        * PKCS12Attribute ::= SEQUENCE {
+        * attrId      ATTRIBUTE.&id ({PKCS12AttrSet}),
+        * attrValues  SET OF ATTRIBUTE.&Type ({PKCS12AttrSet}{@attrId})
+        * }
+        */
+
+       if (asn1_get_oid(pos, end - pos, &a_oid, &pos)) {
+               wpa_printf(MSG_DEBUG, "PKCS #12: Failed to parse OID (attrId)");
+               return -1;
+       }
+
+       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);
+               return -1;
+       }
+       wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: attrValues",
+                       hdr.payload, hdr.length);
+       pos = hdr.payload;
+       end = hdr.payload + hdr.length;
+
+       if (is_oid_pkcs9_friendly_name(&a_oid))
+               return pkcs12_parse_attr_friendly_name(pos, end);
+       if (is_oid_pkcs9_local_key_id(&a_oid))
+               return pkcs12_parse_attr_local_key_id(pos, end);
+
+       wpa_printf(MSG_DEBUG, "PKCS #12: Ignore unknown attribute");
+       return 0;
+}
+
+
+static int pkcs12_safebag(struct tlsv1_credentials *cred,
+                         const u8 *buf, size_t len, const char *passwd)
+{
+       struct asn1_hdr hdr;
+       struct asn1_oid oid;
+       char obuf[80];
+       const u8 *pos = buf, *end = buf + len;
+       const u8 *value;
+       size_t value_len;
+
+       wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: SafeBag", buf, len);
+
+       /* BAG-TYPE ::= TYPE-IDENTIFIER */
+       if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+               wpa_printf(MSG_DEBUG,
+                          "PKCS #12: Failed to parse OID (BAG-TYPE)");
+               return -1;
+       }
+
+       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);
+               return 0;
+       }
+       value = hdr.payload;
+       value_len = hdr.length;
+       wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: bagValue", value, value_len);
+       pos = hdr.payload + hdr.length;
+
+       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);
+                       return -1;
+               }
+               wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: bagAttributes",
+                               hdr.payload, hdr.length);
+
+               pos = hdr.payload;
+               end = hdr.payload + hdr.length;
+               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);
+                               return -1;
+                       }
+                       if (pkcs12_parse_attr(hdr.payload, hdr.length) < 0)
+                               return -1;
+                       pos = hdr.payload + hdr.length;
+               }
+       }
+
+       if (pkcs12_is_bagtype_oid(&oid, 1))
+               return pkcs12_keybag(cred, value, value_len);
+       if (pkcs12_is_bagtype_oid(&oid, 2))
+               return pkcs12_pkcs8_keybag(cred, value, value_len, passwd);
+       if (pkcs12_is_bagtype_oid(&oid, 3))
+               return pkcs12_certbag(cred, value, value_len);
+
+       wpa_printf(MSG_DEBUG, "PKCS #12: Ignore unsupported BAG-TYPE");
+       return 0;
+}
+
+
+static int pkcs12_safecontents(struct tlsv1_credentials *cred,
+                              const u8 *buf, size_t len,
+                              const char *passwd)
+{
+       struct asn1_hdr hdr;
+       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);
+               return -1;
+       }
+       pos = hdr.payload;
+       end = hdr.payload + hdr.length;
+
+       /*
+        * SafeBag ::= SEQUENCE {
+        *   bagId          BAG-TYPE.&id ({PKCS12BagSet})
+        *   bagValue       [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
+        *   bagAttributes  SET OF PKCS12Attribute OPTIONAL
+        * }
+        */
+
+       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);
+                       return -1;
+               }
+               if (pkcs12_safebag(cred, hdr.payload, hdr.length, passwd) < 0)
+                       return -1;
+               pos = hdr.payload + hdr.length;
+       }
+
+       return 0;
+}
+
+
+static int pkcs12_parse_content_data(struct tlsv1_credentials *cred,
+                                    const u8 *pos, const u8 *end,
+                                    const char *passwd)
+{
+       struct asn1_hdr hdr;
+
+       /* 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);
+               return -1;
+       }
+
+       wpa_hexdump(MSG_MSGDUMP, "PKCS #12: Data", hdr.payload, hdr.length);
+
+       return pkcs12_safecontents(cred, hdr.payload, hdr.length, passwd);
+}
+
+
+static int pkcs12_parse_content_enc_data(struct tlsv1_credentials *cred,
+                                        const u8 *pos, const u8 *end,
+                                        const char *passwd)
+{
+       struct asn1_hdr hdr;
+       struct asn1_oid oid;
+       char buf[80];
+       const u8 *enc_alg;
+       u8 *data;
+       size_t enc_alg_len, data_len;
+       int res = -1;
+
+       /*
+        * EncryptedData ::= SEQUENCE {
+        *   version Version,
+        *   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);
+               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);
+               return -1;
+       }
+       if (hdr.length != 1 || hdr.payload[0] != 0) {
+               wpa_printf(MSG_DEBUG, "PKCS #12: Unrecognized PKCS #7 version");
+               return -1;
+       }
+       pos = hdr.payload + hdr.length;
+
+       wpa_hexdump(MSG_MSGDUMP, "PKCS #12: EncryptedContentInfo",
+                   pos, end - pos);
+
+       /*
+        * EncryptedContentInfo ::= SEQUENCE {
+        *   contentType ContentType,
+        *   contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+        *   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);
+               return -1;
+       }
+
+       pos = hdr.payload;
+       end = pos + hdr.length;
+
+       /* ContentType ::= OBJECT IDENTIFIER */
+       if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+               wpa_printf(MSG_DEBUG,
+                          "PKCS #12: Could not find OBJECT IDENTIFIER (contentType)");
+               return -1;
+       }
+       asn1_oid_to_str(&oid, buf, sizeof(buf));
+       wpa_printf(MSG_DEBUG, "PKCS #12: EncryptedContentInfo::contentType %s",
+                  buf);
+
+       if (!is_oid_pkcs7_data(&oid)) {
+               wpa_printf(MSG_DEBUG,
+                          "PKCS #12: Unsupported EncryptedContentInfo::contentType %s",
+                          buf);
+               return 0;
+       }
+
+       /* 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);
+               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);
+               return -1;
+       }
+
+       /* EncryptedContent ::= OCTET STRING */
+       data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
+                            passwd, &data_len);
+       if (data) {
+               wpa_hexdump_key(MSG_MSGDUMP,
+                               "PKCS #12: Decrypted encryptedContent",
+                               data, data_len);
+               res = pkcs12_safecontents(cred, data, data_len, passwd);
+               os_free(data);
+       }
+
+       return res;
+}
+
+
+static int pkcs12_parse_content(struct tlsv1_credentials *cred,
+                               const u8 *buf, size_t len,
+                               const char *passwd)
+{
+       const u8 *pos = buf;
+       const u8 *end = buf + len;
+       struct asn1_oid oid;
+       char txt[80];
+       struct asn1_hdr hdr;
+
+       wpa_hexdump(MSG_MSGDUMP, "PKCS #12: ContentInfo", buf, len);
+
+       if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+               wpa_printf(MSG_DEBUG,
+                          "PKCS #12: Could not find OBJECT IDENTIFIER (contentType)");
+               return 0;
+       }
+
+       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);
+               return 0;
+       }
+       pos = hdr.payload;
+
+       if (is_oid_pkcs7_data(&oid))
+               return pkcs12_parse_content_data(cred, pos, end, passwd);
+       if (is_oid_pkcs7_enc_data(&oid))
+               return pkcs12_parse_content_enc_data(cred, pos, end, passwd);
+
+       wpa_printf(MSG_DEBUG, "PKCS #12: Ignored unsupported contentType %s",
+                  txt);
+
+       return 0;
+}
+
+
+static int pkcs12_parse(struct tlsv1_credentials *cred,
+                       const u8 *key, size_t len, const char *passwd)
+{
+       struct asn1_hdr hdr;
+       const u8 *pos, *end;
+       struct asn1_oid oid;
+       char buf[80];
+
+       /*
+        * PFX ::= SEQUENCE {
+        *     version     INTEGER {v3(3)}(v3,...),
+        *     authSafe    ContentInfo,
+        *     macData     MacData OPTIONAL
+        * }
+        */
+
+       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);
+               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);
+               return -1;
+       }
+       if (hdr.length != 1 || hdr.payload[0] != 3) {
+               wpa_printf(MSG_DEBUG, "PKCS #12: Unrecognized version");
+               return -1;
+       }
+       pos = hdr.payload + hdr.length;
+
+       /*
+        * ContentInfo ::= SEQUENCE {
+        *   contentType ContentType,
+        *   content [0] EXPLICIT ANY DEFINED BY contentType 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 (authSafe) - found class %d tag 0x%x; assume PKCS #12 not used",
+                          hdr.class, hdr.tag);
+               return -1;
+       }
+
+       pos = hdr.payload;
+       end = pos + hdr.length;
+
+       /* ContentType ::= OBJECT IDENTIFIER */
+       if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+               wpa_printf(MSG_DEBUG,
+                          "PKCS #12: Could not find OBJECT IDENTIFIER (contentType); assume PKCS #12 not used");
+               return -1;
+       }
+       asn1_oid_to_str(&oid, buf, sizeof(buf));
+       wpa_printf(MSG_DEBUG, "PKCS #12: contentType %s", buf);
+       if (!is_oid_pkcs7_data(&oid)) {
+               wpa_printf(MSG_DEBUG, "PKCS #12: Unsupported contentType %s",
+                          buf);
+               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);
+               return -1;
+       }
+
+       pos = hdr.payload;
+
+       /* 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);
+               return -1;
+       }
+
+       /*
+        * AuthenticatedSafe ::= SEQUENCE OF ContentInfo
+        *     -- Data if unencrypted
+        *     -- EncryptedData if password-encrypted
+        *     -- EnvelopedData if public key-encrypted
+        */
+       wpa_hexdump(MSG_MSGDUMP, "PKCS #12: Data content",
+                   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);
+               return -1;
+       }
+
+       pos = hdr.payload;
+       end = pos + hdr.length;
+
+       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);
+                       return -1;
+               }
+               if (pkcs12_parse_content(cred, hdr.payload, hdr.length,
+                                        passwd) < 0)
+                       return -1;
+
+               pos = hdr.payload + hdr.length;
+       }
+
+       return 0;
+}
+
+#endif /* PKCS12_FUNCS */
+
+
 static int tlsv1_set_key(struct tlsv1_credentials *cred,
                         const u8 *key, size_t len, const char *passwd)
 {
@@ -296,6 +1067,10 @@ static int tlsv1_set_key(struct tlsv1_credentials *cred,
                cred->key = tlsv1_set_key_pem(key, len);
        if (cred->key == NULL)
                cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
+#ifdef PKCS12_FUNCS
+       if (!cred->key)
+               pkcs12_parse(cred, key, len, passwd);
+#endif /* PKCS12_FUNCS */
        if (cred->key == NULL) {
                wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
                return -1;
index 68fbdc9..716e93c 100644 (file)
@@ -14,11 +14,19 @@ struct tlsv1_credentials {
        struct x509_certificate *cert;
        struct crypto_private_key *key;
 
+       unsigned int cert_probe:1;
+       unsigned int ca_cert_verify:1;
+       unsigned int server_cert_only:1;
+       u8 srv_cert_hash[32];
+
        /* Diffie-Hellman parameters */
        u8 *dh_p; /* prime */
        size_t dh_p_len;
        u8 *dh_g; /* generator */
        size_t dh_g_len;
+
+       char *ocsp_stapling_response;
+       char *ocsp_stapling_response_multi;
 };
 
 
index 96d79b3..29c6678 100644 (file)
@@ -55,6 +55,9 @@ struct tlsv1_server {
        void *log_cb_ctx;
 
        int use_session_ticket;
+       unsigned int status_request:1;
+       unsigned int status_request_v2:1;
+       unsigned int status_request_multi:1;
 
        u8 *dh_secret;
        size_t dh_secret_len;
index 0f237ba..4aa8a01 100644 (file)
@@ -46,6 +46,78 @@ static int testing_cipher_suite_filter(struct tlsv1_server *conn, u16 suite)
 }
 
 
+static void tls_process_status_request_item(struct tlsv1_server *conn,
+                                           const u8 *req, size_t req_len)
+{
+       const u8 *pos, *end;
+       u8 status_type;
+
+       pos = req;
+       end = req + req_len;
+
+       /*
+        * RFC 6961, 2.2:
+        * struct {
+        *   CertificateStatusType status_type;
+        *   uint16 request_length;
+        *   select (status_type) {
+        *     case ocsp: OCSPStatusRequest;
+        *     case ocsp_multi: OCSPStatusRequest;
+        *   } request;
+        * } CertificateStatusRequestItemV2;
+        *
+        * enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;
+        */
+
+       if (end - pos < 1)
+               return; /* Truncated data */
+
+       status_type = *pos++;
+       wpa_printf(MSG_DEBUG, "TLSv1: CertificateStatusType %u", status_type);
+       if (status_type != 1 && status_type != 2)
+               return; /* Unsupported status type */
+       /*
+        * For now, only OCSP stapling is supported, so ignore the specific
+        * request, if any.
+        */
+       wpa_hexdump(MSG_DEBUG, "TLSv1: OCSPStatusRequest", pos, end - pos);
+
+       if (status_type == 2)
+               conn->status_request_multi = 1;
+}
+
+
+static void tls_process_status_request_v2(struct tlsv1_server *conn,
+                                         const u8 *ext, size_t ext_len)
+{
+       const u8 *pos, *end;
+
+       conn->status_request_v2 = 1;
+
+       pos = ext;
+       end = ext + ext_len;
+
+       /*
+        * RFC 6961, 2.2:
+        * struct {
+        *   CertificateStatusRequestItemV2
+        *                    certificate_status_req_list<1..2^16-1>;
+        * } CertificateStatusRequestListV2;
+        */
+
+       while (end - pos >= 2) {
+               u16 len;
+
+               len = WPA_GET_BE16(pos);
+               pos += 2;
+               if (len > end - pos)
+                       break; /* Truncated data */
+               tls_process_status_request_item(conn, pos, len);
+               pos += len;
+       }
+}
+
+
 static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
                                    const u8 *in_data, size_t *in_len)
 {
@@ -267,6 +339,11 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
                                                  ext_len);
                                        conn->session_ticket_len = ext_len;
                                }
+                       } else if (ext_type == TLS_EXT_STATUS_REQUEST) {
+                               conn->status_request = 1;
+                       } else if (ext_type == TLS_EXT_STATUS_REQUEST_V2) {
+                               tls_process_status_request_v2(conn, pos,
+                                                             ext_len);
                        }
 
                        pos += ext_len;
@@ -471,6 +548,15 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
                return -1;
        }
 
+       if (chain && (chain->extensions_present & X509_EXT_EXT_KEY_USAGE) &&
+           !(chain->ext_key_usage &
+             (X509_EXT_KEY_USAGE_ANY | X509_EXT_KEY_USAGE_CLIENT_AUTH))) {
+               tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                  TLS_ALERT_BAD_CERTIFICATE);
+               x509_certificate_chain_free(chain);
+               return -1;
+       }
+
        x509_certificate_chain_free(chain);
 
        *in_len = end - in_data;
index 15e6692..bdc6c11 100644 (file)
@@ -42,7 +42,7 @@ static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn)
 static int tls_write_server_hello(struct tlsv1_server *conn,
                                  u8 **msgpos, u8 *end)
 {
-       u8 *pos, *rhdr, *hs_start, *hs_length;
+       u8 *pos, *rhdr, *hs_start, *hs_length, *ext_start;
        struct os_time now;
        size_t rlen;
 
@@ -97,6 +97,32 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
        /* CompressionMethod compression_method */
        *pos++ = TLS_COMPRESSION_NULL;
 
+       /* Extension */
+       ext_start = pos;
+       pos += 2;
+
+       if (conn->status_request) {
+               /* Add a status_request extension with empty extension_data */
+               /* ExtensionsType extension_type = status_request(5) */
+               WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST);
+               pos += 2;
+               /* opaque extension_data<0..2^16-1> length */
+               WPA_PUT_BE16(pos, 0);
+               pos += 2;
+       }
+
+       if (conn->status_request_v2) {
+               /*
+                 Add a status_request_v2 extension with empty extension_data
+               */
+               /* ExtensionsType extension_type = status_request_v2(17) */
+               WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST_V2);
+               pos += 2;
+               /* opaque extension_data<0..2^16-1> length */
+               WPA_PUT_BE16(pos, 0);
+               pos += 2;
+       }
+
        if (conn->session_ticket && conn->session_ticket_cb) {
                int res = conn->session_ticket_cb(
                        conn->session_ticket_cb_ctx,
@@ -133,6 +159,11 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
                 */
        }
 
+       if (pos == ext_start + 2)
+               pos -= 2; /* no extensions */
+       else
+               WPA_PUT_BE16(ext_start, pos - ext_start - 2);
+
        WPA_PUT_BE24(hs_length, pos - hs_length - 3);
        tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 
@@ -168,6 +199,11 @@ static int tls_write_server_certificate(struct tlsv1_server *conn,
        }
 
        pos = *msgpos;
+       if (TLS_RECORD_HEADER_LEN + 1 + 3 + 3 > end - pos) {
+               tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                  TLS_ALERT_INTERNAL_ERROR);
+               return -1;
+       }
 
        tlsv1_server_log(conn, "Send Certificate");
        rhdr = pos;
@@ -188,7 +224,7 @@ static int tls_write_server_certificate(struct tlsv1_server *conn,
        pos += 3;
        cert = conn->cred->cert;
        while (cert) {
-               if (pos + 3 + cert->cert_len > end) {
+               if (3 + cert->cert_len > (size_t) (end - pos)) {
                        wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
                                   "for Certificate (cert_len=%lu left=%lu)",
                                   (unsigned long) cert->cert_len,
@@ -239,6 +275,93 @@ static int tls_write_server_certificate(struct tlsv1_server *conn,
 }
 
 
+static int tls_write_server_certificate_status(struct tlsv1_server *conn,
+                                              u8 **msgpos, u8 *end,
+                                              int ocsp_multi,
+                                              char *ocsp_resp,
+                                              size_t ocsp_resp_len)
+{
+       u8 *pos, *rhdr, *hs_start, *hs_length;
+       size_t rlen;
+
+       if (!ocsp_resp) {
+                /*
+                 * Client did not request certificate status or there is no
+                 * matching response cached.
+                 */
+               return 0;
+       }
+
+       pos = *msgpos;
+       if (TLS_RECORD_HEADER_LEN + 1 + 3 + 1 + 3 + ocsp_resp_len >
+           (unsigned int) (end - pos)) {
+               tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                  TLS_ALERT_INTERNAL_ERROR);
+               return -1;
+       }
+
+       tlsv1_server_log(conn, "Send CertificateStatus (multi=%d)", ocsp_multi);
+       rhdr = pos;
+       pos += TLS_RECORD_HEADER_LEN;
+
+       /* opaque fragment[TLSPlaintext.length] */
+
+       /* Handshake */
+       hs_start = pos;
+       /* HandshakeType msg_type */
+       *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS;
+       /* uint24 length (to be filled) */
+       hs_length = pos;
+       pos += 3;
+
+       /* body - CertificateStatus
+        *
+        * struct {
+        *     CertificateStatusType status_type;
+        *     select (status_type) {
+        *         case ocsp: OCSPResponse;
+        *         case ocsp_multi: OCSPResponseList;
+        *     } response;
+        * } CertificateStatus;
+        *
+        * opaque OCSPResponse<1..2^24-1>;
+        *
+        * struct {
+        *   OCSPResponse ocsp_response_list<1..2^24-1>;
+        * } OCSPResponseList;
+        */
+
+       /* CertificateStatusType status_type */
+       if (ocsp_multi)
+               *pos++ = 2; /* ocsp_multi(2) */
+       else
+               *pos++ = 1; /* ocsp(1) */
+       /* uint24 length of OCSPResponse */
+       WPA_PUT_BE24(pos, ocsp_resp_len);
+       pos += 3;
+       os_memcpy(pos, ocsp_resp, ocsp_resp_len);
+       pos += ocsp_resp_len;
+
+       WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+       if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+                             rhdr, end - rhdr, hs_start, pos - hs_start,
+                             &rlen) < 0) {
+               wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+               tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                  TLS_ALERT_INTERNAL_ERROR);
+               return -1;
+       }
+       pos = rhdr + rlen;
+
+       tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+       *msgpos = pos;
+
+       return 0;
+}
+
+
 static int tls_write_server_key_exchange(struct tlsv1_server *conn,
                                         u8 **msgpos, u8 *end)
 {
@@ -371,7 +494,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
        /* body - ServerDHParams */
        server_params = pos;
        /* dh_p */
-       if (pos + 2 + dh_p_len > end) {
+       if (2 + dh_p_len > (size_t) (end - pos)) {
                wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
                           "dh_p");
                tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -385,7 +508,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
        pos += dh_p_len;
 
        /* dh_g */
-       if (pos + 2 + conn->cred->dh_g_len > end) {
+       if (2 + conn->cred->dh_g_len > (size_t) (end - pos)) {
                wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
                           "dh_g");
                tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -399,7 +522,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
        pos += conn->cred->dh_g_len;
 
        /* dh_Ys */
-       if (pos + 2 + dh_ys_len > end) {
+       if (2 + dh_ys_len > (size_t) (end - pos)) {
                wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
                           "dh_Ys");
                tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -443,7 +566,8 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
                if (conn->rl.tls_version >= TLS_VERSION_1_2) {
 #ifdef CONFIG_TLSV12
                        hlen = tlsv12_key_x_server_params_hash(
-                               conn->rl.tls_version, conn->client_random,
+                               conn->rl.tls_version, TLS_HASH_ALG_SHA256,
+                               conn->client_random,
                                conn->server_random, server_params,
                                pos - server_params, hash + 19);
 
@@ -457,7 +581,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
                         *   SignatureAlgorithm signature;
                         * } SignatureAndHashAlgorithm;
                         */
-                       if (hlen < 0 || pos + 2 > end) {
+                       if (hlen < 0 || end - pos < 2) {
                                tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                                                   TLS_ALERT_INTERNAL_ERROR);
                                return -1;
@@ -804,24 +928,46 @@ static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
 {
        u8 *msg, *end, *pos;
        size_t msglen;
+       int ocsp_multi = 0;
+       char *ocsp_resp = NULL;
+       size_t ocsp_resp_len = 0;
 
        *out_len = 0;
 
-       msglen = 1000 + tls_server_cert_chain_der_len(conn);
+       if (conn->status_request_multi &&
+           conn->cred->ocsp_stapling_response_multi) {
+               ocsp_resp = os_readfile(
+                       conn->cred->ocsp_stapling_response_multi,
+                       &ocsp_resp_len);
+               ocsp_multi = 1;
+       } else if ((conn->status_request || conn->status_request_v2) &&
+                  conn->cred->ocsp_stapling_response) {
+               ocsp_resp = os_readfile(conn->cred->ocsp_stapling_response,
+                                       &ocsp_resp_len);
+       }
+       if (!ocsp_resp)
+               ocsp_resp_len = 0;
+
+       msglen = 1000 + tls_server_cert_chain_der_len(conn) + ocsp_resp_len;
 
        msg = os_malloc(msglen);
-       if (msg == NULL)
+       if (msg == NULL) {
+               os_free(ocsp_resp);
                return NULL;
+       }
 
        pos = msg;
        end = msg + msglen;
 
        if (tls_write_server_hello(conn, &pos, end) < 0) {
                os_free(msg);
+               os_free(ocsp_resp);
                return NULL;
        }
 
        if (conn->use_session_ticket) {
+               os_free(ocsp_resp);
+
                /* Abbreviated handshake using session ticket; RFC 4507 */
                if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
                    tls_write_server_finished(conn, &pos, end) < 0) {
@@ -838,12 +984,16 @@ static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
 
        /* Full handshake */
        if (tls_write_server_certificate(conn, &pos, end) < 0 ||
+           tls_write_server_certificate_status(conn, &pos, end, ocsp_multi,
+                                               ocsp_resp, ocsp_resp_len) < 0 ||
            tls_write_server_key_exchange(conn, &pos, end) < 0 ||
            tls_write_server_certificate_request(conn, &pos, end) < 0 ||
            tls_write_server_hello_done(conn, &pos, end) < 0) {
                os_free(msg);
+               os_free(ocsp_resp);
                return NULL;
        }
+       os_free(ocsp_resp);
 
        *out_len = pos - msg;
 
index b51dfcd..75f222c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * X.509v3 certificate parsing and processing (RFC 3280 profile)
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -14,7 +14,7 @@
 #include "x509v3.h"
 
 
-static void x509_free_name(struct x509_name *name)
+void x509_free_name(struct x509_name *name)
 {
        size_t i;
 
@@ -55,6 +55,7 @@ void x509_certificate_free(struct x509_certificate *cert)
        x509_free_name(&cert->subject);
        os_free(cert->public_key);
        os_free(cert->sign_value);
+       os_free(cert->subject_dn);
        os_free(cert);
 }
 
@@ -177,9 +178,9 @@ int x509_name_compare(struct x509_name *a, struct x509_name *b)
 }
 
 
-static int x509_parse_algorithm_identifier(
-       const u8 *buf, size_t len,
-       struct x509_algorithm_identifier *id, const u8 **next)
+int x509_parse_algorithm_identifier(const u8 *buf, size_t len,
+                                   struct x509_algorithm_identifier *id,
+                                   const u8 **next)
 {
        struct asn1_hdr hdr;
        const u8 *pos, *end;
@@ -199,12 +200,11 @@ static int x509_parse_algorithm_identifier(
                           hdr.class, hdr.tag);
                return -1;
        }
+       if (hdr.length > buf + len - hdr.payload)
+               return -1;
        pos = hdr.payload;
        end = pos + hdr.length;
 
-       if (end > buf + len)
-               return -1;
-
        *next = end;
 
        if (asn1_get_oid(pos, end - pos, &id->oid, &pos))
@@ -243,7 +243,7 @@ static int x509_parse_public_key(const u8 *buf, size_t len,
        }
        pos = hdr.payload;
 
-       if (pos + hdr.length > end)
+       if (hdr.length > end - pos)
                return -1;
        end = pos + hdr.length;
        *next = end;
@@ -289,8 +289,8 @@ static int x509_parse_public_key(const u8 *buf, size_t len,
 }
 
 
-static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
-                          const u8 **next)
+int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
+                   const u8 **next)
 {
        struct asn1_hdr hdr;
        const u8 *pos, *end, *set_pos, *set_end, *seq_pos, *seq_end;
@@ -319,7 +319,7 @@ static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
        }
        pos = hdr.payload;
 
-       if (pos + hdr.length > buf + len)
+       if (hdr.length > buf + len - pos)
                return -1;
 
        end = *next = pos + hdr.length;
@@ -537,8 +537,7 @@ done:
 }
 
 
-static int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag,
-                          os_time_t *val)
+int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, os_time_t *val)
 {
        const char *pos;
        int year, month, day, hour, min, sec;
@@ -677,7 +676,7 @@ static int x509_parse_validity(const u8 *buf, size_t len,
        pos = hdr.payload;
        plen = hdr.length;
 
-       if (pos + plen > buf + len)
+       if (plen > (size_t) (buf + len - pos))
                return -1;
 
        *next = pos + plen;
@@ -721,6 +720,15 @@ static int x509_id_ce_oid(struct asn1_oid *oid)
 }
 
 
+static int x509_any_ext_key_usage_oid(struct asn1_oid *oid)
+{
+       return oid->len == 6 &&
+               x509_id_ce_oid(oid) &&
+               oid->oid[3] == 37 /* extKeyUsage */ &&
+               oid->oid[4] == 0 /* anyExtendedKeyUsage */;
+}
+
+
 static int x509_parse_ext_key_usage(struct x509_certificate *cert,
                                    const u8 *pos, size_t len)
 {
@@ -801,7 +809,7 @@ static int x509_parse_ext_basic_constraints(struct x509_certificate *cert,
                }
                cert->ca = hdr.payload[0];
 
-               if (hdr.payload + hdr.length == pos + len) {
+               if (hdr.length == pos + len - hdr.payload) {
                        wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d",
                                   cert->ca);
                        return 0;
@@ -1074,6 +1082,112 @@ static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert,
 }
 
 
+static int x509_id_pkix_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] == 5 /* security */ &&
+               oid->oid[5] == 5 /* mechanisms */ &&
+               oid->oid[6] == 7 /* id-pkix */;
+}
+
+
+static int x509_id_kp_oid(struct asn1_oid *oid)
+{
+       /* id-kp */
+       return oid->len >= 8 &&
+               x509_id_pkix_oid(oid) &&
+               oid->oid[7] == 3 /* id-kp */;
+}
+
+
+static int x509_id_kp_server_auth_oid(struct asn1_oid *oid)
+{
+       /* id-kp */
+       return oid->len == 9 &&
+               x509_id_kp_oid(oid) &&
+               oid->oid[8] == 1 /* id-kp-serverAuth */;
+}
+
+
+static int x509_id_kp_client_auth_oid(struct asn1_oid *oid)
+{
+       /* id-kp */
+       return oid->len == 9 &&
+               x509_id_kp_oid(oid) &&
+               oid->oid[8] == 2 /* id-kp-clientAuth */;
+}
+
+
+static int x509_id_kp_ocsp_oid(struct asn1_oid *oid)
+{
+       /* id-kp */
+       return oid->len == 9 &&
+               x509_id_kp_oid(oid) &&
+               oid->oid[8] == 9 /* id-kp-OCSPSigning */;
+}
+
+
+static int x509_parse_ext_ext_key_usage(struct x509_certificate *cert,
+                                       const u8 *pos, size_t len)
+{
+       struct asn1_hdr hdr;
+       const u8 *end;
+       struct asn1_oid oid;
+
+       /*
+        * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
+        *
+        * 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);
+               return -1;
+       }
+       if (hdr.length > pos + len - hdr.payload)
+               return -1;
+       pos = hdr.payload;
+       end = pos + hdr.length;
+
+       wpa_hexdump(MSG_MSGDUMP, "X509: ExtKeyUsageSyntax", pos, end - pos);
+
+       while (pos < end) {
+               char buf[80];
+
+               if (asn1_get_oid(pos, end - pos, &oid, &pos))
+                       return -1;
+               if (x509_any_ext_key_usage_oid(&oid)) {
+                       os_strlcpy(buf, "anyExtendedKeyUsage", sizeof(buf));
+                       cert->ext_key_usage |= X509_EXT_KEY_USAGE_ANY;
+               } else if (x509_id_kp_server_auth_oid(&oid)) {
+                       os_strlcpy(buf, "id-kp-serverAuth", sizeof(buf));
+                       cert->ext_key_usage |= X509_EXT_KEY_USAGE_SERVER_AUTH;
+               } else if (x509_id_kp_client_auth_oid(&oid)) {
+                       os_strlcpy(buf, "id-kp-clientAuth", sizeof(buf));
+                       cert->ext_key_usage |= X509_EXT_KEY_USAGE_CLIENT_AUTH;
+               } else if (x509_id_kp_ocsp_oid(&oid)) {
+                       os_strlcpy(buf, "id-kp-OCSPSigning", sizeof(buf));
+                       cert->ext_key_usage |= X509_EXT_KEY_USAGE_OCSP;
+               } else {
+                       asn1_oid_to_str(&oid, buf, sizeof(buf));
+               }
+               wpa_printf(MSG_DEBUG, "ExtKeyUsage KeyPurposeId: %s", buf);
+       }
+
+       cert->extensions_present |= X509_EXT_EXT_KEY_USAGE;
+
+       return 0;
+}
+
+
 static int x509_parse_extension_data(struct x509_certificate *cert,
                                     struct asn1_oid *oid,
                                     const u8 *pos, size_t len)
@@ -1085,7 +1199,6 @@ static int x509_parse_extension_data(struct x509_certificate *cert,
         * certificate policies (section 4.2.1.5)
         * name constraints (section 4.2.1.11)
         * policy constraints (section 4.2.1.12)
-        * extended key usage (section 4.2.1.13)
         * inhibit any-policy (section 4.2.1.15)
         */
        switch (oid->oid[3]) {
@@ -1097,6 +1210,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 37: /* id-ce-extKeyUsage */
+               return x509_parse_ext_ext_key_usage(cert, pos, len);
        default:
                return 1;
        }
@@ -1224,6 +1339,7 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
        size_t left;
        char sbuf[128];
        unsigned long value;
+       const u8 *subject_dn;
 
        /* tbsCertificate TBSCertificate ::= SEQUENCE */
        if (asn1_get_next(buf, len, &hdr) < 0 ||
@@ -1287,21 +1403,23 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
 
        /* serialNumber CertificateSerialNumber ::= INTEGER */
        if (hdr.class != ASN1_CLASS_UNIVERSAL ||
-           hdr.tag != ASN1_TAG_INTEGER) {
+           hdr.tag != ASN1_TAG_INTEGER ||
+           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",
-                          hdr.class, hdr.tag);
+                          "serialNumber; class=%d tag=0x%x length=%u",
+                          hdr.class, hdr.tag, hdr.length);
                return -1;
        }
 
-       pos = hdr.payload;
-       left = hdr.length;
-       while (left) {
-               cert->serial_number <<= 8;
-               cert->serial_number |= *pos++;
-               left--;
+       pos = hdr.payload + hdr.length;
+       while (hdr.length > 0 && hdr.payload[0] == 0) {
+               hdr.payload++;
+               hdr.length--;
        }
-       wpa_printf(MSG_MSGDUMP, "X509: serialNumber %lu", cert->serial_number);
+       os_memcpy(cert->serial_number, hdr.payload, hdr.length);
+       cert->serial_number_len = hdr.length;
+       wpa_hexdump(MSG_MSGDUMP, "X509: serialNumber", cert->serial_number,
+                   cert->serial_number_len);
 
        /* signature AlgorithmIdentifier */
        if (x509_parse_algorithm_identifier(pos, end - pos, &cert->signature,
@@ -1319,8 +1437,14 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
                return -1;
 
        /* subject Name */
+       subject_dn = pos;
        if (x509_parse_name(pos, end - pos, &cert->subject, &pos))
                return -1;
+       cert->subject_dn = os_malloc(pos - subject_dn);
+       if (!cert->subject_dn)
+               return -1;
+       cert->subject_dn_len = pos - subject_dn;
+       os_memcpy(cert->subject_dn, subject_dn, cert->subject_dn_len);
        x509_name_string(&cert->subject, sbuf, sizeof(sbuf));
        wpa_printf(MSG_MSGDUMP, "X509: subject %s", sbuf);
 
@@ -1437,7 +1561,7 @@ static int x509_digest_oid(struct asn1_oid *oid)
 }
 
 
-static int x509_sha1_oid(struct asn1_oid *oid)
+int x509_sha1_oid(struct asn1_oid *oid)
 {
        return oid->len == 6 &&
                oid->oid[0] == 1 /* iso */ &&
@@ -1449,7 +1573,7 @@ static int x509_sha1_oid(struct asn1_oid *oid)
 }
 
 
-static int x509_sha256_oid(struct asn1_oid *oid)
+static int x509_sha2_oid(struct asn1_oid *oid)
 {
        return oid->len == 9 &&
                oid->oid[0] == 2 /* joint-iso-itu-t */ &&
@@ -1459,11 +1583,31 @@ static int x509_sha256_oid(struct asn1_oid *oid)
                oid->oid[4] == 101 /* gov */ &&
                oid->oid[5] == 3 /* csor */ &&
                oid->oid[6] == 4 /* nistAlgorithm */ &&
-               oid->oid[7] == 2 /* hashAlgs */ &&
+               oid->oid[7] == 2 /* hashAlgs */;
+}
+
+
+int x509_sha256_oid(struct asn1_oid *oid)
+{
+       return x509_sha2_oid(oid) &&
                oid->oid[8] == 1 /* sha256 */;
 }
 
 
+int x509_sha384_oid(struct asn1_oid *oid)
+{
+       return x509_sha2_oid(oid) &&
+               oid->oid[8] == 2 /* sha384 */;
+}
+
+
+int x509_sha512_oid(struct asn1_oid *oid)
+{
+       return x509_sha2_oid(oid) &&
+               oid->oid[8] == 3 /* sha512 */;
+}
+
+
 /**
  * x509_certificate_parse - Parse a X.509 certificate in DER format
  * @buf: Pointer to the X.509 certificate in DER format
@@ -1503,12 +1647,12 @@ struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)
        }
        pos = hdr.payload;
 
-       if (pos + hdr.length > end) {
+       if (hdr.length > end - pos) {
                x509_certificate_free(cert);
                return NULL;
        }
 
-       if (pos + hdr.length < end) {
+       if (hdr.length < end - pos) {
                wpa_hexdump(MSG_MSGDUMP, "X509: Ignoring extra data after DER "
                            "encoded certificate",
                            pos + hdr.length, end - (pos + hdr.length));
@@ -1582,18 +1726,31 @@ struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)
 int x509_certificate_check_signature(struct x509_certificate *issuer,
                                     struct x509_certificate *cert)
 {
+       return x509_check_signature(issuer, &cert->signature,
+                                   cert->sign_value, cert->sign_value_len,
+                                   cert->tbs_cert_start, cert->tbs_cert_len);
+}
+
+
+int x509_check_signature(struct x509_certificate *issuer,
+                        struct x509_algorithm_identifier *signature,
+                        const u8 *sign_value, size_t sign_value_len,
+                        const u8 *signed_data, size_t signed_data_len)
+{
        struct crypto_public_key *pk;
        u8 *data;
        const u8 *pos, *end, *next, *da_end;
        size_t data_len;
        struct asn1_hdr hdr;
        struct asn1_oid oid;
-       u8 hash[32];
+       u8 hash[64];
        size_t hash_len;
+       const u8 *addr[1] = { signed_data };
+       size_t len[1] = { signed_data_len };
 
-       if (!x509_pkcs_oid(&cert->signature.oid) ||
-           cert->signature.oid.len != 7 ||
-           cert->signature.oid.oid[5] != 1 /* pkcs-1 */) {
+       if (!x509_pkcs_oid(&signature->oid) ||
+           signature->oid.len != 7 ||
+           signature->oid.oid[5] != 1 /* pkcs-1 */) {
                wpa_printf(MSG_DEBUG, "X509: Unrecognized signature "
                           "algorithm");
                return -1;
@@ -1604,15 +1761,15 @@ int x509_certificate_check_signature(struct x509_certificate *issuer,
        if (pk == NULL)
                return -1;
 
-       data_len = cert->sign_value_len;
+       data_len = sign_value_len;
        data = os_malloc(data_len);
        if (data == NULL) {
                crypto_public_key_free(pk);
                return -1;
        }
 
-       if (crypto_public_key_decrypt_pkcs1(pk, cert->sign_value,
-                                           cert->sign_value_len, data,
+       if (crypto_public_key_decrypt_pkcs1(pk, sign_value,
+                                           sign_value_len, data,
                                            &data_len) < 0) {
                wpa_printf(MSG_DEBUG, "X509: Failed to decrypt signature");
                crypto_public_key_free(pk);
@@ -1675,12 +1832,11 @@ int x509_certificate_check_signature(struct x509_certificate *issuer,
        }
 
        if (x509_sha1_oid(&oid)) {
-               if (cert->signature.oid.oid[6] !=
-                   5 /* sha-1WithRSAEncryption */) {
+               if (signature->oid.oid[6] != 5 /* sha-1WithRSAEncryption */) {
                        wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA1 "
                                   "does not match with certificate "
                                   "signatureAlgorithm (%lu)",
-                                  cert->signature.oid.oid[6]);
+                                  signature->oid.oid[6]);
                        os_free(data);
                        return -1;
                }
@@ -1688,12 +1844,36 @@ int x509_certificate_check_signature(struct x509_certificate *issuer,
        }
 
        if (x509_sha256_oid(&oid)) {
-               if (cert->signature.oid.oid[6] !=
+               if (signature->oid.oid[6] !=
                    11 /* sha2561WithRSAEncryption */) {
                        wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA256 "
                                   "does not match with certificate "
                                   "signatureAlgorithm (%lu)",
-                                  cert->signature.oid.oid[6]);
+                                  signature->oid.oid[6]);
+                       os_free(data);
+                       return -1;
+               }
+               goto skip_digest_oid;
+       }
+
+       if (x509_sha384_oid(&oid)) {
+               if (signature->oid.oid[6] != 12 /* sha384WithRSAEncryption */) {
+                       wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA384 "
+                                  "does not match with certificate "
+                                  "signatureAlgorithm (%lu)",
+                                  signature->oid.oid[6]);
+                       os_free(data);
+                       return -1;
+               }
+               goto skip_digest_oid;
+       }
+
+       if (x509_sha512_oid(&oid)) {
+               if (signature->oid.oid[6] != 13 /* sha512WithRSAEncryption */) {
+                       wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA512 "
+                                  "does not match with certificate "
+                                  "signatureAlgorithm (%lu)",
+                                  signature->oid.oid[6]);
                        os_free(data);
                        return -1;
                }
@@ -1707,12 +1887,11 @@ int x509_certificate_check_signature(struct x509_certificate *issuer,
        }
        switch (oid.oid[5]) {
        case 5: /* md5 */
-               if (cert->signature.oid.oid[6] != 4 /* md5WithRSAEncryption */)
-               {
+               if (signature->oid.oid[6] != 4 /* md5WithRSAEncryption */) {
                        wpa_printf(MSG_DEBUG, "X509: digestAlgorithm MD5 does "
                                   "not match with certificate "
                                   "signatureAlgorithm (%lu)",
-                                  cert->signature.oid.oid[6]);
+                                  signature->oid.oid[6]);
                        os_free(data);
                        return -1;
                }
@@ -1743,34 +1922,41 @@ skip_digest_oid:
        wpa_hexdump(MSG_MSGDUMP, "X509: Decrypted Digest",
                    hdr.payload, hdr.length);
 
-       switch (cert->signature.oid.oid[6]) {
+       switch (signature->oid.oid[6]) {
        case 4: /* md5WithRSAEncryption */
-               md5_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
-                          hash);
+               md5_vector(1, addr, len, hash);
                hash_len = 16;
                wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (MD5)",
                            hash, hash_len);
                break;
        case 5: /* sha-1WithRSAEncryption */
-               sha1_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
-                           hash);
+               sha1_vector(1, addr, len, hash);
                hash_len = 20;
                wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA1)",
                            hash, hash_len);
                break;
        case 11: /* sha256WithRSAEncryption */
-               sha256_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
-                             hash);
+               sha256_vector(1, addr, len, hash);
                hash_len = 32;
                wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)",
                            hash, hash_len);
                break;
-       case 2: /* md2WithRSAEncryption */
        case 12: /* sha384WithRSAEncryption */
+               sha384_vector(1, addr, len, hash);
+               hash_len = 48;
+               wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA384)",
+                           hash, hash_len);
+               break;
        case 13: /* sha512WithRSAEncryption */
+               sha512_vector(1, addr, len, hash);
+               hash_len = 64;
+               wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA512)",
+                           hash, hash_len);
+               break;
+       case 2: /* md2WithRSAEncryption */
        default:
                wpa_printf(MSG_INFO, "X509: Unsupported certificate signature "
-                          "algorithm (%lu)", cert->signature.oid.oid[6]);
+                          "algorithm (%lu)", signature->oid.oid[6]);
                os_free(data);
                return -1;
        }
@@ -1852,6 +2038,7 @@ int x509_certificate_chain_validate(struct x509_certificate *trusted,
        os_get_time(&now);
 
        for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
+               cert->issuer_trusted = 0;
                x509_name_string(&cert->subject, buf, sizeof(buf)); 
                wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
 
@@ -1937,6 +2124,7 @@ int x509_certificate_chain_validate(struct x509_certificate *trusted,
 
                        wpa_printf(MSG_DEBUG, "X509: Trusted certificate "
                                   "found to complete the chain");
+                       cert->issuer_trusted = 1;
                        chain_trusted = 1;
                }
        }
index 91a35ba..7df8e2a 100644 (file)
@@ -45,13 +45,18 @@ struct x509_name {
        struct asn1_oid rid; /* registeredID */
 };
 
+#define X509_MAX_SERIAL_NUM_LEN 20
+
 struct x509_certificate {
        struct x509_certificate *next;
        enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version;
-       unsigned long serial_number;
+       u8 serial_number[X509_MAX_SERIAL_NUM_LEN];
+       size_t serial_number_len;
        struct x509_algorithm_identifier signature;
        struct x509_name issuer;
        struct x509_name subject;
+       u8 *subject_dn;
+       size_t subject_dn_len;
        os_time_t not_before;
        os_time_t not_after;
        struct x509_algorithm_identifier public_key_alg;
@@ -68,6 +73,7 @@ struct x509_certificate {
 #define X509_EXT_KEY_USAGE                     (1 << 2)
 #define X509_EXT_SUBJECT_ALT_NAME              (1 << 3)
 #define X509_EXT_ISSUER_ALT_NAME               (1 << 4)
+#define X509_EXT_EXT_KEY_USAGE                 (1 << 5)
 
        /* BasicConstraints */
        int ca; /* cA */
@@ -85,6 +91,13 @@ struct x509_certificate {
 #define X509_KEY_USAGE_ENCIPHER_ONLY           (1 << 7)
 #define X509_KEY_USAGE_DECIPHER_ONLY           (1 << 8)
 
+       /* ExtKeyUsage */
+       unsigned long ext_key_usage;
+#define X509_EXT_KEY_USAGE_ANY                 (1 << 0)
+#define X509_EXT_KEY_USAGE_SERVER_AUTH         (1 << 1)
+#define X509_EXT_KEY_USAGE_CLIENT_AUTH         (1 << 2)
+#define X509_EXT_KEY_USAGE_OCSP                        (1 << 3)
+
        /*
         * The DER format certificate follows struct x509_certificate. These
         * pointers point to that buffer.
@@ -93,6 +106,11 @@ struct x509_certificate {
        size_t cert_len;
        const u8 *tbs_cert_start;
        size_t tbs_cert_len;
+
+       /* Meta data used for certificate validation */
+       unsigned int ocsp_good:1;
+       unsigned int ocsp_revoked:1;
+       unsigned int issuer_trusted:1;
 };
 
 enum {
@@ -106,10 +124,21 @@ enum {
 };
 
 void x509_certificate_free(struct x509_certificate *cert);
+int x509_parse_algorithm_identifier(const u8 *buf, size_t len,
+                                   struct x509_algorithm_identifier *id,
+                                   const u8 **next);
+int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
+                   const u8 **next);
+int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, os_time_t *val);
 struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len);
+void x509_free_name(struct x509_name *name);
 void x509_name_string(struct x509_name *name, char *buf, size_t len);
 int x509_name_compare(struct x509_name *a, struct x509_name *b);
 void x509_certificate_chain_free(struct x509_certificate *cert);
+int x509_check_signature(struct x509_certificate *issuer,
+                        struct x509_algorithm_identifier *signature,
+                        const u8 *sign_value, size_t sign_value_len,
+                        const u8 *signed_data, size_t signed_data_len);
 int x509_certificate_check_signature(struct x509_certificate *issuer,
                                     struct x509_certificate *cert);
 int x509_certificate_chain_validate(struct x509_certificate *trusted,
@@ -120,4 +149,9 @@ x509_certificate_get_subject(struct x509_certificate *chain,
                             struct x509_name *name);
 int x509_certificate_self_signed(struct x509_certificate *cert);
 
+int x509_sha1_oid(struct asn1_oid *oid);
+int x509_sha256_oid(struct asn1_oid *oid);
+int x509_sha384_oid(struct asn1_oid *oid);
+int x509_sha512_oid(struct asn1_oid *oid);
+
 #endif /* X509V3_H */
index 9ce1a5c..71a1652 100644 (file)
@@ -95,7 +95,7 @@ int hs20_web_browser(const char *url)
 
        if (pid == 0) {
                /* run the external command in the child process */
-               char *argv[9];
+               char *argv[7];
 
                argv[0] = "browser-android";
                argv[1] = "start";
@@ -103,9 +103,7 @@ int hs20_web_browser(const char *url)
                argv[3] = "android.intent.action.VIEW";
                argv[4] = "-d";
                argv[5] = (void *) url;
-               argv[6] = "-n";
-               argv[7] = "com.android.browser/.BrowserActivity";
-               argv[8] = NULL;
+               argv[6] = NULL;
 
                execv("/system/bin/am", argv);
                wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
index 660e9fc..04a533a 100644 (file)
@@ -86,7 +86,7 @@ int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable)
                return -1;
 
        /* check for optional mask */
-       if (*r == '\0' || isspace(*r)) {
+       if (*r == '\0' || isspace((unsigned char) *r)) {
                /* no mask specified, assume default */
                os_memset(mask, 0xff, ETH_ALEN);
        } else if (maskable && *r == '/') {
@@ -498,7 +498,7 @@ void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len)
                        *txt++ = 't';
                        break;
                default:
-                       if (data[i] >= 32 && data[i] <= 127) {
+                       if (data[i] >= 32 && data[i] <= 126) {
                                *txt++ = data[i];
                        } else {
                                txt += os_snprintf(txt, end - txt, "\\x%02x",
@@ -697,6 +697,29 @@ int is_hex(const u8 *data, size_t len)
 }
 
 
+int has_ctrl_char(const u8 *data, size_t len)
+{
+       size_t i;
+
+       for (i = 0; i < len; i++) {
+               if (data[i] < 32 || data[i] == 127)
+                       return 1;
+       }
+       return 0;
+}
+
+
+int has_newline(const char *str)
+{
+       while (*str) {
+               if (*str == '\n' || *str == '\r')
+                       return 1;
+               str++;
+       }
+       return 0;
+}
+
+
 size_t merge_byte_arrays(u8 *res, size_t res_len,
                         const u8 *src1, size_t src1_len,
                         const u8 *src2, size_t src2_len)
@@ -978,7 +1001,7 @@ int random_mac_addr_keep_oui(u8 *addr)
  * @delim: a string of delimiters
  * @last: a pointer to a character following the returned token
  *      It has to be set to NULL for the first call and passed for any
- *      futher call.
+ *      further call.
  * Returns: a pointer to token position in str or NULL
  *
  * This function is similar to str_token, but it can be used with both
@@ -1123,3 +1146,57 @@ int is_ctrl_char(char c)
 {
        return c > 0 && c < 32;
 }
+
+
+/**
+ * ssid_parse - Parse a string that contains SSID in hex or text format
+ * @buf: Input NULL terminated string that contains the SSID
+ * @ssid: Output SSID
+ * Returns: 0 on success, -1 otherwise
+ *
+ * The SSID has to be enclosed in double quotes for the text format or space
+ * or NULL terminated string of hex digits for the hex format. buf can include
+ * additional arguments after the SSID.
+ */
+int ssid_parse(const char *buf, struct wpa_ssid_value *ssid)
+{
+       char *tmp, *res, *end;
+       size_t len;
+
+       ssid->ssid_len = 0;
+
+       tmp = os_strdup(buf);
+       if (!tmp)
+               return -1;
+
+       if (*tmp != '"') {
+               end = os_strchr(tmp, ' ');
+               if (end)
+                       *end = '\0';
+       } else {
+               end = os_strchr(tmp + 1, '"');
+               if (!end) {
+                       os_free(tmp);
+                       return -1;
+               }
+
+               end[1] = '\0';
+       }
+
+       res = wpa_config_parse_string(tmp, &len);
+       if (res && len <= SSID_MAX_LEN) {
+               ssid->ssid_len = len;
+               os_memcpy(ssid->ssid, res, len);
+       }
+
+       os_free(tmp);
+       os_free(res);
+
+       return ssid->ssid_len ? 0 : -1;
+}
+
+
+int str_starts(const char *str, const char *start)
+{
+       return os_strncmp(str, start, os_strlen(start)) == 0;
+}
index 13aa941..2a185fb 100644 (file)
@@ -320,6 +320,9 @@ static inline void WPA_PUT_LE64(u8 *a, u64 val)
 #ifndef ETH_P_ALL
 #define ETH_P_ALL 0x0003
 #endif
+#ifndef ETH_P_IP
+#define ETH_P_IP 0x0800
+#endif
 #ifndef ETH_P_80211_ENCAP
 #define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */
 #endif
@@ -425,6 +428,7 @@ void perror(const char *s);
  */
 #ifdef __CHECKER__
 #define __force __attribute__((force))
+#undef __bitwise
 #define __bitwise __attribute__((bitwise))
 #else
 #define __force
@@ -454,6 +458,13 @@ typedef u64 __bitwise le64;
 #endif /* __GNUC__ */
 #endif /* __must_check */
 
+#define SSID_MAX_LEN 32
+
+struct wpa_ssid_value {
+       u8 ssid[SSID_MAX_LEN];
+       size_t ssid_len;
+};
+
 int hwaddr_aton(const char *txt, u8 *addr);
 int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable);
 int hwaddr_compact_aton(const char *txt, u8 *addr);
@@ -470,6 +481,7 @@ int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
                               size_t len);
 
 int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask);
+int ssid_parse(const char *buf, struct wpa_ssid_value *ssid);
 
 #ifdef CONFIG_NATIVE_WINDOWS
 void wpa_unicode2ascii_inplace(TCHAR *str);
@@ -486,6 +498,8 @@ const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len);
 
 char * wpa_config_parse_string(const char *value, size_t *len);
 int is_hex(const u8 *data, size_t len);
+int has_ctrl_char(const u8 *data, size_t len);
+int has_newline(const char *str);
 size_t merge_byte_arrays(u8 *res, size_t res_len,
                         const u8 *src1, size_t src1_len,
                         const u8 *src2, size_t src2_len);
@@ -545,6 +559,8 @@ size_t utf8_unescape(const char *inp, size_t in_size,
                     char *outp, size_t out_size);
 int is_ctrl_char(char c);
 
+int str_starts(const char *str, const char *start);
+
 
 /*
  * gcc 4.4 ends up generating strict-aliasing warnings about some very common
index 13173cb..2ffd1a2 100644 (file)
@@ -47,6 +47,12 @@ static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
                return;
        }
 
+       if (c == '\b') {
+               if (cmdbuf_pos > 0)
+                       cmdbuf_pos--;
+               return;
+       }
+
        if (c >= 32 && c <= 255) {
                if (cmdbuf_pos < (int) sizeof(cmdbuf) - 1) {
                        cmdbuf[cmdbuf_pos++] = c;
index 8647229..436bc8c 100644 (file)
 #error Do not define both of poll and epoll
 #endif
 
-#if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL)
+#if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_KQUEUE)
+#error Do not define both of poll and kqueue
+#endif
+
+#if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL) && \
+    !defined(CONFIG_ELOOP_KQUEUE)
 #define CONFIG_ELOOP_SELECT
 #endif
 
 #include <sys/epoll.h>
 #endif /* CONFIG_ELOOP_EPOLL */
 
+#ifdef CONFIG_ELOOP_KQUEUE
+#include <sys/event.h>
+#endif /* CONFIG_ELOOP_KQUEUE */
+
 struct eloop_sock {
        int sock;
        void *eloop_data;
@@ -75,13 +84,20 @@ struct eloop_data {
        struct pollfd *pollfds;
        struct pollfd **pollfds_map;
 #endif /* CONFIG_ELOOP_POLL */
+#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
+       int max_fd;
+       struct eloop_sock *fd_table;
+#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
 #ifdef CONFIG_ELOOP_EPOLL
        int epollfd;
        int epoll_max_event_num;
-       int epoll_max_fd;
-       struct eloop_sock *epoll_table;
        struct epoll_event *epoll_events;
 #endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+       int kqueuefd;
+       int kqueue_nevents;
+       struct kevent *kqueue_events;
+#endif /* CONFIG_ELOOP_KQUEUE */
        struct eloop_sock_table readers;
        struct eloop_sock_table writers;
        struct eloop_sock_table exceptions;
@@ -149,14 +165,24 @@ int eloop_init(void)
 #ifdef CONFIG_ELOOP_EPOLL
        eloop.epollfd = epoll_create1(0);
        if (eloop.epollfd < 0) {
-               wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s\n",
+               wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s",
+                          __func__, strerror(errno));
+               return -1;
+       }
+#endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+       eloop.kqueuefd = kqueue();
+       if (eloop.kqueuefd < 0) {
+               wpa_printf(MSG_ERROR, "%s: kqueue failed: %s",
                           __func__, strerror(errno));
                return -1;
        }
+#endif /* CONFIG_ELOOP_KQUEUE */
+#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
        eloop.readers.type = EVENT_TYPE_READ;
        eloop.writers.type = EVENT_TYPE_WRITE;
        eloop.exceptions.type = EVENT_TYPE_EXCEPTION;
-#endif /* CONFIG_ELOOP_EPOLL */
+#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
 #ifdef WPA_TRACE
        signal(SIGSEGV, eloop_sigsegv_handler);
 #endif /* WPA_TRACE */
@@ -164,15 +190,80 @@ int eloop_init(void)
 }
 
 
+#ifdef CONFIG_ELOOP_EPOLL
+static int eloop_sock_queue(int sock, eloop_event_type type)
+{
+       struct epoll_event ev;
+
+       os_memset(&ev, 0, sizeof(ev));
+       switch (type) {
+       case EVENT_TYPE_READ:
+               ev.events = EPOLLIN;
+               break;
+       case EVENT_TYPE_WRITE:
+               ev.events = EPOLLOUT;
+               break;
+       /*
+        * Exceptions are always checked when using epoll, but I suppose it's
+        * possible that someone registered a socket *only* for exception
+        * handling.
+        */
+       case EVENT_TYPE_EXCEPTION:
+               ev.events = EPOLLERR | EPOLLHUP;
+               break;
+       }
+       ev.data.fd = sock;
+       if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) {
+               wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d failed: %s",
+                          __func__, sock, strerror(errno));
+               return -1;
+       }
+       return 0;
+}
+#endif /* CONFIG_ELOOP_EPOLL */
+
+
+#ifdef CONFIG_ELOOP_KQUEUE
+static int eloop_sock_queue(int sock, eloop_event_type type)
+{
+       int filter;
+       struct kevent ke;
+
+       switch (type) {
+       case EVENT_TYPE_READ:
+               filter = EVFILT_READ;
+               break;
+       case EVENT_TYPE_WRITE:
+               filter = EVFILT_WRITE;
+               break;
+       default:
+               filter = 0;
+       }
+       EV_SET(&ke, sock, filter, EV_ADD, 0, 0, 0);
+       if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) == -1) {
+               wpa_printf(MSG_ERROR, "%s: kevent(ADD) for fd=%d failed: %s",
+                          __func__, sock, strerror(errno));
+               return -1;
+       }
+       return 0;
+}
+#endif /* CONFIG_ELOOP_KQUEUE */
+
+
 static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
                                      int sock, eloop_sock_handler handler,
                                      void *eloop_data, void *user_data)
 {
 #ifdef CONFIG_ELOOP_EPOLL
+       struct epoll_event *temp_events;
+#endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+       struct kevent *temp_events;
+#endif /* CONFIG_ELOOP_EPOLL */
+#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
        struct eloop_sock *temp_table;
-       struct epoll_event ev, *temp_events;
        int next;
-#endif /* CONFIG_ELOOP_EPOLL */
+#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
        struct eloop_sock *tmp;
        int new_max_sock;
 
@@ -208,26 +299,28 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
                eloop.pollfds = n;
        }
 #endif /* CONFIG_ELOOP_POLL */
-#ifdef CONFIG_ELOOP_EPOLL
-       if (new_max_sock >= eloop.epoll_max_fd) {
-               next = eloop.epoll_max_fd == 0 ? 16 : eloop.epoll_max_fd * 2;
-               temp_table = os_realloc_array(eloop.epoll_table, next,
+#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
+       if (new_max_sock >= eloop.max_fd) {
+               next = eloop.max_fd == 0 ? 16 : eloop.max_fd * 2;
+               temp_table = os_realloc_array(eloop.fd_table, next,
                                              sizeof(struct eloop_sock));
                if (temp_table == NULL)
                        return -1;
 
-               eloop.epoll_max_fd = next;
-               eloop.epoll_table = temp_table;
+               eloop.max_fd = next;
+               eloop.fd_table = temp_table;
        }
+#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
 
+#ifdef CONFIG_ELOOP_EPOLL
        if (eloop.count + 1 > eloop.epoll_max_event_num) {
                next = eloop.epoll_max_event_num == 0 ? 8 :
                        eloop.epoll_max_event_num * 2;
                temp_events = os_realloc_array(eloop.epoll_events, next,
                                               sizeof(struct epoll_event));
                if (temp_events == NULL) {
-                       wpa_printf(MSG_ERROR, "%s: malloc for epoll failed. "
-                                  "%s\n", __func__, strerror(errno));
+                       wpa_printf(MSG_ERROR, "%s: malloc for epoll failed: %s",
+                                  __func__, strerror(errno));
                        return -1;
                }
 
@@ -235,6 +328,22 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
                eloop.epoll_events = temp_events;
        }
 #endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+       if (eloop.count + 1 > eloop.kqueue_nevents) {
+               next = eloop.kqueue_nevents == 0 ? 8 : eloop.kqueue_nevents * 2;
+               temp_events = os_malloc(next * sizeof(*temp_events));
+               if (!temp_events) {
+                       wpa_printf(MSG_ERROR,
+                                  "%s: malloc for kqueue failed: %s",
+                                  __func__, strerror(errno));
+                       return -1;
+               }
+
+               os_free(eloop.kqueue_events);
+               eloop.kqueue_events = temp_events;
+               eloop.kqueue_nevents = next;
+       }
+#endif /* CONFIG_ELOOP_KQUEUE */
 
        eloop_trace_sock_remove_ref(table);
        tmp = os_realloc_array(table->table, table->count + 1,
@@ -256,33 +365,12 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
        table->changed = 1;
        eloop_trace_sock_add_ref(table);
 
-#ifdef CONFIG_ELOOP_EPOLL
-       os_memset(&ev, 0, sizeof(ev));
-       switch (table->type) {
-       case EVENT_TYPE_READ:
-               ev.events = EPOLLIN;
-               break;
-       case EVENT_TYPE_WRITE:
-               ev.events = EPOLLOUT;
-               break;
-       /*
-        * Exceptions are always checked when using epoll, but I suppose it's
-        * possible that someone registered a socket *only* for exception
-        * handling.
-        */
-       case EVENT_TYPE_EXCEPTION:
-               ev.events = EPOLLERR | EPOLLHUP;
-               break;
-       }
-       ev.data.fd = sock;
-       if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) {
-               wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d "
-                          "failed. %s\n", __func__, sock, strerror(errno));
+#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
+       if (eloop_sock_queue(sock, table->type) < 0)
                return -1;
-       }
-       os_memcpy(&eloop.epoll_table[sock], &table->table[table->count - 1],
+       os_memcpy(&eloop.fd_table[sock], &table->table[table->count - 1],
                  sizeof(struct eloop_sock));
-#endif /* CONFIG_ELOOP_EPOLL */
+#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
        return 0;
 }
 
@@ -290,6 +378,9 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
 static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
                                          int sock)
 {
+#ifdef CONFIG_ELOOP_KQUEUE
+       struct kevent ke;
+#endif /* CONFIG_ELOOP_KQUEUE */
        int i;
 
        if (table == NULL || table->table == NULL || table->count == 0)
@@ -313,12 +404,21 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
        eloop_trace_sock_add_ref(table);
 #ifdef CONFIG_ELOOP_EPOLL
        if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) {
-               wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d "
-                          "failed. %s\n", __func__, sock, strerror(errno));
+               wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d failed: %s",
+                          __func__, sock, strerror(errno));
                return;
        }
-       os_memset(&eloop.epoll_table[sock], 0, sizeof(struct eloop_sock));
+       os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
 #endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+       EV_SET(&ke, sock, 0, EV_DELETE, 0, 0, 0);
+       if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) < 0) {
+               wpa_printf(MSG_ERROR, "%s: kevent(DEL) for fd=%d failed: %s",
+                          __func__, sock, strerror(errno));
+               return;
+       }
+       os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
+#endif /* CONFIG_ELOOP_KQUEUE */
 }
 
 
@@ -511,7 +611,7 @@ static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds)
        int i;
 
        for (i = 0; i < nfds; i++) {
-               table = &eloop.epoll_table[events[i].data.fd];
+               table = &eloop.fd_table[events[i].data.fd];
                if (table->handler == NULL)
                        continue;
                table->handler(table->sock, table->eloop_data,
@@ -525,6 +625,67 @@ static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds)
 #endif /* CONFIG_ELOOP_EPOLL */
 
 
+#ifdef CONFIG_ELOOP_KQUEUE
+
+static void eloop_sock_table_dispatch(struct kevent *events, int nfds)
+{
+       struct eloop_sock *table;
+       int i;
+
+       for (i = 0; i < nfds; i++) {
+               table = &eloop.fd_table[events[i].ident];
+               if (table->handler == NULL)
+                       continue;
+               table->handler(table->sock, table->eloop_data,
+                              table->user_data);
+               if (eloop.readers.changed ||
+                   eloop.writers.changed ||
+                   eloop.exceptions.changed)
+                       break;
+       }
+}
+
+
+static int eloop_sock_table_requeue(struct eloop_sock_table *table)
+{
+       int i, r;
+
+       r = 0;
+       for (i = 0; i < table->count && table->table; i++) {
+               if (eloop_sock_queue(table->table[i].sock, table->type) == -1)
+                       r = -1;
+       }
+       return r;
+}
+
+#endif /* CONFIG_ELOOP_KQUEUE */
+
+
+int eloop_sock_requeue(void)
+{
+       int r = 0;
+
+#ifdef CONFIG_ELOOP_KQUEUE
+       close(eloop.kqueuefd);
+       eloop.kqueuefd = kqueue();
+       if (eloop.kqueuefd < 0) {
+               wpa_printf(MSG_ERROR, "%s: kqueue failed: %s",
+                          __func__, strerror(errno));
+               return -1;
+       }
+
+       if (eloop_sock_table_requeue(&eloop.readers) < 0)
+               r = -1;
+       if (eloop_sock_table_requeue(&eloop.writers) < 0)
+               r = -1;
+       if (eloop_sock_table_requeue(&eloop.exceptions) < 0)
+               r = -1;
+#endif /* CONFIG_ELOOP_KQUEUE */
+
+       return r;
+}
+
+
 static void eloop_sock_table_destroy(struct eloop_sock_table *table)
 {
        if (table) {
@@ -905,6 +1066,9 @@ void eloop_run(void)
 #ifdef CONFIG_ELOOP_EPOLL
        int timeout_ms = -1;
 #endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+       struct timespec ts;
+#endif /* CONFIG_ELOOP_KQUEUE */
        int res;
        struct os_reltime tv, now;
 
@@ -949,6 +1113,10 @@ void eloop_run(void)
                        _tv.tv_sec = tv.sec;
                        _tv.tv_usec = tv.usec;
 #endif /* CONFIG_ELOOP_SELECT */
+#ifdef CONFIG_ELOOP_KQUEUE
+                       ts.tv_sec = tv.sec;
+                       ts.tv_nsec = tv.usec * 1000L;
+#endif /* CONFIG_ELOOP_KQUEUE */
                }
 
 #ifdef CONFIG_ELOOP_POLL
@@ -974,6 +1142,15 @@ void eloop_run(void)
                                         eloop.count, timeout_ms);
                }
 #endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+               if (eloop.count == 0) {
+                       res = 0;
+               } else {
+                       res = kevent(eloop.kqueuefd, NULL, 0,
+                                    eloop.kqueue_events, eloop.kqueue_nevents,
+                                    timeout ? &ts : NULL);
+               }
+#endif /* CONFIG_ELOOP_KQUEUE */
                if (res < 0 && errno != EINTR && errno != 0) {
                        wpa_printf(MSG_ERROR, "eloop: %s: %s",
 #ifdef CONFIG_ELOOP_POLL
@@ -985,6 +1162,10 @@ void eloop_run(void)
 #ifdef CONFIG_ELOOP_EPOLL
                                   "epoll"
 #endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+                                  "kqueue"
+#endif /* CONFIG_ELOOP_EKQUEUE */
+
                                   , strerror(errno));
                        goto out;
                }
@@ -995,6 +1176,7 @@ void eloop_run(void)
 
                eloop_process_pending_signals();
 
+
                /* check if some registered timeouts have occurred */
                timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
                                        list);
@@ -1040,6 +1222,9 @@ void eloop_run(void)
 #ifdef CONFIG_ELOOP_EPOLL
                eloop_sock_table_dispatch(eloop.epoll_events, res);
 #endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+               eloop_sock_table_dispatch(eloop.kqueue_events, res);
+#endif /* CONFIG_ELOOP_KQUEUE */
        }
 
        eloop.terminate = 0;
@@ -1092,11 +1277,17 @@ void eloop_destroy(void)
        os_free(eloop.pollfds);
        os_free(eloop.pollfds_map);
 #endif /* CONFIG_ELOOP_POLL */
+#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
+       os_free(eloop.fd_table);
+#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
 #ifdef CONFIG_ELOOP_EPOLL
-       os_free(eloop.epoll_table);
        os_free(eloop.epoll_events);
        close(eloop.epollfd);
 #endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+       os_free(eloop.kqueue_events);
+       close(eloop.kqueuefd);
+#endif /* CONFIG_ELOOP_KQUEUE */
 }
 
 
@@ -1135,6 +1326,17 @@ void eloop_wait_for_read_sock(int sock)
        FD_SET(sock, &rfds);
        select(sock + 1, &rfds, NULL, NULL, NULL);
 #endif /* defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) */
+#ifdef CONFIG_ELOOP_KQUEUE
+       int kfd;
+       struct kevent ke1, ke2;
+
+       kfd = kqueue();
+       if (kfd == -1)
+               return;
+       EV_SET(&ke1, sock, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
+       kevent(kfd, &ke1, 1, &ke2, 1, NULL);
+       close(kfd);
+#endif /* CONFIG_ELOOP_KQUEUE */
 }
 
 #ifdef CONFIG_ELOOP_SELECT
index 00233a0..ef5fd0a 100644 (file)
@@ -318,6 +318,14 @@ int eloop_register_signal_reconfig(eloop_signal_handler handler,
                                   void *user_data);
 
 /**
+ * eloop_sock_requeue - Requeue sockets
+ *
+ * Requeue sockets after forking because some implementations require this,
+ * such as epoll and kqueue.
+ */
+int eloop_sock_requeue(void);
+
+/**
  * eloop_run - Start the event loop
  *
  * Start the event loop and continue running as long as there are any
index de47fb2..9c8b12b 100644 (file)
@@ -692,3 +692,9 @@ void eloop_wait_for_read_sock(int sock)
        WSAEventSelect(sock, event, 0);
        WSACloseEvent(event);
 }
+
+
+int eloop_sock_requeue(void)
+{
+       return 0;
+}
index 0613119..5615bd7 100644 (file)
 #include "ext_password_i.h"
 
 
-#ifdef CONFIG_EXT_PASSWORD_TEST
-extern struct ext_password_backend ext_password_test;
-#endif /* CONFIG_EXT_PASSWORD_TEST */
-
 static const struct ext_password_backend *backends[] = {
 #ifdef CONFIG_EXT_PASSWORD_TEST
        &ext_password_test,
index 043e731..948eaf5 100644 (file)
@@ -20,4 +20,10 @@ struct ext_password_backend {
 
 struct wpabuf * ext_password_alloc(size_t len);
 
+/* Available ext_password backends */
+
+#ifdef CONFIG_EXT_PASSWORD_TEST
+extern const struct ext_password_backend ext_password_test;
+#endif /* CONFIG_EXT_PASSWORD_TEST */
+
 #endif /* EXT_PASSWORD_I_H */
index 653eb54..a06aae8 100644 (file)
@@ -26,6 +26,9 @@
 #include "common.h"
 #include "xml-utils.h"
 #include "http-utils.h"
+#ifdef EAP_TLS_OPENSSL
+#include "crypto/tls_openssl.h"
+#endif /* EAP_TLS_OPENSSL */
 
 
 struct http_ctx {
@@ -421,6 +424,28 @@ ASN1_SEQUENCE(LogotypeExtn) = {
 
 IMPLEMENT_ASN1_FUNCTIONS(LogotypeExtn);
 
+#ifdef OPENSSL_IS_BORINGSSL
+#define sk_LogotypeInfo_num(st) \
+sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeInfo) *, (st)))
+#define sk_LogotypeInfo_value(st, i) (LogotypeInfo *) \
+sk_value(CHECKED_CAST(_STACK *, const STACK_OF(LogotypeInfo) *, (st)), (i))
+#define sk_LogotypeImage_num(st) \
+sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeImage) *, (st)))
+#define sk_LogotypeImage_value(st, i) (LogotypeImage *) \
+sk_value(CHECKED_CAST(_STACK *, const STACK_OF(LogotypeImage) *, (st)), (i))
+#define sk_LogotypeAudio_num(st) \
+sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeAudio) *, (st)))
+#define sk_LogotypeAudio_value(st, i) (LogotypeAudio *) \
+sk_value(CHECK_CAST(_STACK *, const STACK_OF(LogotypeAudio) *, (st)), (i))
+#define sk_HashAlgAndValue_num(st) \
+sk_num(CHECKED_CAST(_STACK *, STACK_OF(HashAlgAndValue) *, (st)))
+#define sk_HashAlgAndValue_value(st, i) (HashAlgAndValue *) \
+sk_value(CHECKED_CAST(_STACK *, const STACK_OF(HashAlgAndValue) *, (st)), (i))
+#define sk_ASN1_IA5STRING_num(st) \
+sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_IA5STRING) *, (st)))
+#define sk_ASN1_IA5STRING_value(st, i) (ASN1_IA5STRING *) \
+sk_value(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_IA5STRING) *, (st)), (i))
+#else /* OPENSSL_IS_BORINGSSL */
 #define sk_LogotypeInfo_num(st) SKM_sk_num(LogotypeInfo, (st))
 #define sk_LogotypeInfo_value(st, i) SKM_sk_value(LogotypeInfo, (st), (i))
 #define sk_LogotypeImage_num(st) SKM_sk_num(LogotypeImage, (st))
@@ -431,6 +456,7 @@ IMPLEMENT_ASN1_FUNCTIONS(LogotypeExtn);
 #define sk_HashAlgAndValue_value(st, i) SKM_sk_value(HashAlgAndValue, (st), (i))
 #define sk_ASN1_IA5STRING_num(st) SKM_sk_num(ASN1_IA5STRING, (st))
 #define sk_ASN1_IA5STRING_value(st, i) SKM_sk_value(ASN1_IA5STRING, (st), (i))
+#endif /* OPENSSL_IS_BORINGSSL */
 
 
 static void add_logo(struct http_ctx *ctx, struct http_cert *hcert,
@@ -618,13 +644,25 @@ static void i2r_LogotypeImageInfo(LogotypeImageInfo *info, BIO *out, int indent)
        } else {
                BIO_printf(out, "%*stype: default (1)\n", indent, "");
        }
+       val = ASN1_INTEGER_get(info->fileSize);
+       BIO_printf(out, "%*sfileSize: %ld\n", indent, "", val);
        val = ASN1_INTEGER_get(info->xSize);
        BIO_printf(out, "%*sxSize: %ld\n", indent, "", val);
        val = ASN1_INTEGER_get(info->ySize);
        BIO_printf(out, "%*sySize: %ld\n", indent, "", val);
        if (info->resolution) {
-               BIO_printf(out, "%*sresolution\n", indent, "");
-               /* TODO */
+               BIO_printf(out, "%*sresolution [%d]\n", indent, "",
+                          info->resolution->type);
+               switch (info->resolution->type) {
+               case 0:
+                       val = ASN1_INTEGER_get(info->resolution->d.numBits);
+                       BIO_printf(out, "%*snumBits: %ld\n", indent, "", val);
+                       break;
+               case 1:
+                       val = ASN1_INTEGER_get(info->resolution->d.tableSize);
+                       BIO_printf(out, "%*stableSize: %ld\n", indent, "", val);
+                       break;
+               }
        }
        if (info->language) {
                BIO_printf(out, "%*slanguage: ", indent, "");
@@ -981,6 +1019,26 @@ static int curl_cb_ssl_verify(int preverify_ok, X509_STORE_CTX *x509_ctx)
        if (depth == 0 && preverify_ok && validate_server_cert(ctx, cert) < 0)
                return 0;
 
+#ifdef OPENSSL_IS_BORINGSSL
+       if (depth == 0 && ctx->ocsp != NO_OCSP && preverify_ok) {
+               enum ocsp_result res;
+
+               res = check_ocsp_resp(ssl_ctx, ssl, cert, ctx->peer_issuer,
+                                     ctx->peer_issuer_issuer);
+               if (res == OCSP_REVOKED) {
+                       preverify_ok = 0;
+                       wpa_printf(MSG_INFO, "OCSP: certificate revoked");
+                       if (err == X509_V_OK)
+                               X509_STORE_CTX_set_error(
+                                       x509_ctx, X509_V_ERR_CERT_REVOKED);
+               } else if (res != OCSP_GOOD && (ctx->ocsp == MANDATORY_OCSP)) {
+                       preverify_ok = 0;
+                       wpa_printf(MSG_INFO,
+                                  "OCSP: bad certificate status response");
+               }
+       }
+#endif /* OPENSSL_IS_BORINGSSL */
+
        if (!preverify_ok)
                ctx->last_err = "TLS validation failed";
 
@@ -1156,6 +1214,7 @@ static int ocsp_resp_cb(SSL *s, void *arg)
                wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
                           (ctx->ocsp == MANDATORY_OCSP) ? "" :
                           " (OCSP not required)");
+               OCSP_CERTID_free(id);
                OCSP_BASICRESP_free(basic);
                OCSP_RESPONSE_free(rsp);
                if (ctx->ocsp == MANDATORY_OCSP)
@@ -1163,6 +1222,7 @@ static int ocsp_resp_cb(SSL *s, void *arg)
                        ctx->last_err = "Could not find current server certificate from OCSP response";
                return (ctx->ocsp == MANDATORY_OCSP) ? 0 : 1;
        }
+       OCSP_CERTID_free(id);
 
        if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
                tls_show_errors(__func__, "OpenSSL: OCSP status times invalid");
@@ -1273,6 +1333,16 @@ static CURL * setup_curl_post(struct http_ctx *ctx, const char *address,
 #ifdef EAP_TLS_OPENSSL
                curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, curl_cb_ssl);
                curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, ctx);
+#ifdef OPENSSL_IS_BORINGSSL
+               /* For now, using the CURLOPT_SSL_VERIFYSTATUS option only
+                * with BoringSSL since the OpenSSL specific callback hack to
+                * enable OCSP is not available with BoringSSL. The OCSP
+                * implementation within libcurl is not sufficient for the
+                * Hotspot 2.0 OSU needs, so cannot use this with OpenSSL.
+                */
+               if (ctx->ocsp != NO_OCSP)
+                       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L);
+#endif /* OPENSSL_IS_BORINGSSL */
 #endif /* EAP_TLS_OPENSSL */
        } else {
                curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
diff --git a/libeap/src/utils/module_tests.h b/libeap/src/utils/module_tests.h
new file mode 100644 (file)
index 0000000..3bfe4ad
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Module tests
+ * Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MODULE_TESTS_H
+#define MODULE_TESTS_H
+
+int wpas_module_tests(void);
+int hapd_module_tests(void);
+
+int utils_module_tests(void);
+int wps_module_tests(void);
+int common_module_tests(void);
+int crypto_module_tests(void);
+
+#endif /* MODULE_TESTS_H */
index 9e496fb..e8f0b79 100644 (file)
@@ -657,6 +657,10 @@ int os_exec(const char *program, const char *arg, int wait_completion);
 #if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
 #define TEST_FAIL() testing_test_fail()
 int testing_test_fail(void);
+extern char wpa_trace_fail_func[256];
+extern unsigned int wpa_trace_fail_after;
+extern char wpa_trace_test_fail_func[256];
+extern unsigned int wpa_trace_test_fail_after;
 #else
 #define TEST_FAIL() 0
 #endif
index ffa2e78..65c6fa4 100644 (file)
@@ -372,6 +372,7 @@ void os_program_deinit(void)
        if (total)
                wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
                           (unsigned long) total);
+       wpa_trace_deinit();
 #endif /* WPA_TRACE */
 }
 
@@ -434,27 +435,23 @@ char * os_readfile(const char *name, size_t *len)
 
 int os_file_exists(const char *fname)
 {
-       FILE *f = fopen(fname, "rb");
-       if (f == NULL)
-               return 0;
-       fclose(f);
-       return 1;
+       return access(fname, F_OK) == 0;
 }
 
 
 int os_fdatasync(FILE *stream)
 {
        if (!fflush(stream)) {
-#ifndef __MACH__
+#ifdef __linux__
                return fdatasync(fileno(stream));
-#else /* __MACH__ */
+#else /* !__linux__ */
 #ifdef F_FULLFSYNC
                /* OS X does not implement fdatasync(). */
                return fcntl(fileno(stream), F_FULLFSYNC);
 #else /* F_FULLFSYNC */
-#error Neither fdatasync nor F_FULLSYNC are defined
+               return fsync(fileno(stream));
 #endif /* F_FULLFSYNC */
-#endif /* __MACH__ */
+#endif /* __linux__ */
        }
 
        return -1;
index 6f5ea93..383ed3d 100644 (file)
  */
 
 #include "includes.h"
+#ifdef __APPLE__
+#include <PCSC/winscard.h>
+#else
 #include <winscard.h>
+#endif
 
 #include "common.h"
 #include "pcsc_funcs.h"
@@ -110,7 +114,11 @@ typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types;
 struct scard_data {
        SCARDCONTEXT ctx;
        SCARDHANDLE card;
+#ifdef __APPLE__
+       uint32_t protocol;
+#else
        DWORD protocol;
+#endif
        sim_types sim_type;
        int pin1_required;
 };
@@ -275,7 +283,7 @@ static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
        pos++;
        if (pos >= end)
                return -1;
-       if ((pos + pos[0]) < end)
+       if (pos[0] < end - pos)
                end = pos + 1 + pos[0];
        pos++;
        wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template",
@@ -504,7 +512,12 @@ static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
 struct scard_data * scard_init(const char *reader)
 {
        long ret;
-       unsigned long len, pos;
+#ifdef __APPLE__
+       uint32_t len;
+#else
+       unsigned long len;
+#endif
+       unsigned long pos;
        struct scard_data *scard;
 #ifdef CONFIG_NATIVE_WINDOWS
        TCHAR *readers = NULL;
@@ -605,7 +618,7 @@ struct scard_data * scard_init(const char *reader)
        readers = NULL;
 
        wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)",
-                  (unsigned int) scard->card, scard->protocol,
+                  (unsigned int) scard->card, (unsigned long) scard->protocol,
                   scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1");
 
        ret = SCardBeginTransaction(scard->card);
@@ -764,7 +777,11 @@ static long scard_transmit(struct scard_data *scard,
                           unsigned char *_recv, size_t *recv_len)
 {
        long ret;
+#ifdef __APPLE__
+       uint32_t rlen;
+#else
        unsigned long rlen;
+#endif
 
        wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send",
                        _send, send_len);
@@ -1385,7 +1402,7 @@ int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
                end = buf + len;
 
                /* RES */
-               if (pos[0] > RES_MAX_LEN || pos + pos[0] > end) {
+               if (pos[0] > RES_MAX_LEN || pos[0] > end - pos) {
                        wpa_printf(MSG_DEBUG, "SCARD: Invalid RES");
                        return -1;
                }
@@ -1395,7 +1412,7 @@ int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
                wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len);
 
                /* CK */
-               if (pos[0] != CK_LEN || pos + CK_LEN > end) {
+               if (pos[0] != CK_LEN || CK_LEN > end - pos) {
                        wpa_printf(MSG_DEBUG, "SCARD: Invalid CK");
                        return -1;
                }
@@ -1405,7 +1422,7 @@ int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
                wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN);
 
                /* IK */
-               if (pos[0] != IK_LEN || pos + IK_LEN > end) {
+               if (pos[0] != IK_LEN || IK_LEN > end - pos) {
                        wpa_printf(MSG_DEBUG, "SCARD: Invalid IK");
                        return -1;
                }
index 46cfe78..813987e 100644 (file)
@@ -15,7 +15,7 @@
                                                                \
        __ptr->__val;                                           \
 })
-#define get_unaligned_le16(p)  le16_to_cpu(get_unaligned((uint16_t *)(p)))
-#define get_unaligned_le32(p)  le32_to_cpu(get_unaligned((uint32_t *)(p)))
+#define get_unaligned_le16(p)  le16_to_cpu(get_unaligned((le16 *)(p)))
+#define get_unaligned_le32(p)  le32_to_cpu(get_unaligned((le32 *)(p)))
 
 #endif /* PLATFORM_H */
index c9a5023..71996eb 100644 (file)
@@ -13,8 +13,8 @@
  *
  * See COPYING for more details.
  */
-#include "radiotap_iter.h"
 #include "platform.h"
+#include "radiotap_iter.h"
 
 /* function prototypes and related defs are in radiotap_iter.h */
 
index 0572e7c..460af23 100644 (file)
@@ -65,12 +65,12 @@ struct ieee80211_radiotap_header {
                                 * new fields does not count.
                                 */
        uint8_t it_pad;
-       uint16_t it_len;        /* length of the whole
+       le16 it_len;            /* length of the whole
                                 * header in bytes, including
                                 * it_version, it_pad,
                                 * it_len, and data fields.
                                 */
-       uint32_t it_present;    /* A bitmap telling which
+       le32 it_present;        /* A bitmap telling which
                                 * fields are present. Set bit 31
                                 * (0x80000000) to extend the
                                 * bitmap by another 32 bits.
index b768c85..6ea07e3 100644 (file)
@@ -67,7 +67,7 @@ struct ieee80211_radiotap_iterator {
        const struct ieee80211_radiotap_namespace *current_namespace;
 
        unsigned char *_arg, *_next_ns_data;
-       uint32_t *_next_bitmap;
+       le32 *_next_bitmap;
 
        unsigned char *this_arg;
 #ifdef RADIOTAP_SUPPORT_OVERRIDES
index 8484d27..d72cf60 100644 (file)
@@ -366,4 +366,13 @@ void wpa_trace_check_ref(const void *addr)
        }
 }
 
+
+void wpa_trace_deinit(void)
+{
+#ifdef WPA_TRACE_BFD
+       free(syms);
+       syms = NULL;
+#endif /* WPA_TRACE_BFD */
+}
+
 #endif /* WPA_TRACE */
index 43ed86c..d1636de 100644 (file)
@@ -66,4 +66,6 @@ void wpa_trace_dump_funcname(const char *title, void *pc);
 
 #endif /* WPA_TRACE_BFD */
 
+void wpa_trace_deinit(void);
+
 #endif /* TRACE_H */
index 41511b9..abdb79c 100644 (file)
@@ -16,6 +16,7 @@
 #include "utils/base64.h"
 #include "utils/ip_addr.h"
 #include "utils/eloop.h"
+#include "utils/module_tests.h"
 
 
 struct printf_test_data {
index 7c72ea4..2983ad3 100644 (file)
@@ -148,7 +148,7 @@ int wpa_debug_open_linux_tracing(void)
                strtok_r(line, " ", &tmp2);
                tmp_path = strtok_r(NULL, " ", &tmp2);
                fstype = strtok_r(NULL, " ", &tmp2);
-               if (strcmp(fstype, "debugfs") == 0) {
+               if (fstype && strcmp(fstype, "debugfs") == 0) {
                        path = tmp_path;
                        break;
                }
@@ -517,16 +517,18 @@ int wpa_debug_reopen_file(void)
 {
 #ifdef CONFIG_DEBUG_FILE
        int rv;
-       if (last_path) {
-               char *tmp = os_strdup(last_path);
-               wpa_debug_close_file();
-               rv = wpa_debug_open_file(tmp);
-               os_free(tmp);
-       } else {
-               wpa_printf(MSG_ERROR, "Last-path was not set, cannot "
-                          "re-open log file.");
-               rv = -1;
-       }
+       char *tmp;
+
+       if (!last_path)
+               return 0; /* logfile not used */
+
+       tmp = os_strdup(last_path);
+       if (!tmp)
+               return -1;
+
+       wpa_debug_close_file();
+       rv = wpa_debug_open_file(tmp);
+       os_free(tmp);
        return rv;
 #else /* CONFIG_DEBUG_FILE */
        return 0;
index 11e7323..96cb25c 100644 (file)
@@ -310,3 +310,33 @@ void wpabuf_printf(struct wpabuf *buf, char *fmt, ...)
                wpabuf_overflow(buf, res);
        buf->used += res;
 }
+
+
+/**
+ * wpabuf_parse_bin - Parse a null terminated string of binary data to a wpabuf
+ * @buf: Buffer with null terminated string (hexdump) of binary data
+ * Returns: wpabuf or %NULL on failure
+ *
+ * The string len must be a multiple of two and contain only hexadecimal digits.
+ */
+struct wpabuf * wpabuf_parse_bin(const char *buf)
+{
+       size_t len;
+       struct wpabuf *ret;
+
+       len = os_strlen(buf);
+       if (len & 0x01)
+               return NULL;
+       len /= 2;
+
+       ret = wpabuf_alloc(len);
+       if (ret == NULL)
+               return NULL;
+
+       if (hexstr2bin(buf, wpabuf_put(ret, len), len)) {
+               wpabuf_free(ret);
+               return NULL;
+       }
+
+       return ret;
+}
index 64b3d8d..0458e3f 100644 (file)
@@ -41,6 +41,7 @@ void * wpabuf_put(struct wpabuf *buf, size_t len);
 struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b);
 struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len);
 void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3);
+struct wpabuf * wpabuf_parse_bin(const char *buf);
 
 
 /**
@@ -85,7 +86,7 @@ static inline const void * wpabuf_head(const struct wpabuf *buf)
 
 static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)
 {
-       return (const u8 *)wpabuf_head(buf);
+       return (const u8 *) wpabuf_head(buf);
 }
 
 /**
@@ -100,42 +101,42 @@ static inline void * wpabuf_mhead(struct wpabuf *buf)
 
 static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf)
 {
-       return (u8 *)wpabuf_mhead(buf);
+       return (u8 *) wpabuf_mhead(buf);
 }
 
 static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data)
 {
-       u8 *pos = (u8 *)wpabuf_put(buf, 1);
+       u8 *pos = (u8 *) wpabuf_put(buf, 1);
        *pos = data;
 }
 
 static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data)
 {
-       u8 *pos = (u8 *)wpabuf_put(buf, 2);
+       u8 *pos = (u8 *) wpabuf_put(buf, 2);
        WPA_PUT_LE16(pos, data);
 }
 
 static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data)
 {
-       u8 *pos = (u8 *)wpabuf_put(buf, 4);
+       u8 *pos = (u8 *) wpabuf_put(buf, 4);
        WPA_PUT_LE32(pos, data);
 }
 
 static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data)
 {
-       u8 *pos = (u8 *)wpabuf_put(buf, 2);
+       u8 *pos = (u8 *) wpabuf_put(buf, 2);
        WPA_PUT_BE16(pos, data);
 }
 
 static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data)
 {
-       u8 *pos = (u8 *)wpabuf_put(buf, 3);
+       u8 *pos = (u8 *) wpabuf_put(buf, 3);
        WPA_PUT_BE24(pos, data);
 }
 
 static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data)
 {
-       u8 *pos = (u8 *)wpabuf_put(buf, 4);
+       u8 *pos = (u8 *) wpabuf_put(buf, 4);
        WPA_PUT_BE32(pos, data);
 }
 
index c928394..7b6d276 100644 (file)
@@ -212,6 +212,8 @@ char * xml_node_to_str(struct xml_node_ctx *ctx, xml_node_t *node)
        xmlDocSetRootElement(doc, n);
        xmlDocDumpFormatMemory(doc, &buf, &bufsiz, 0);
        xmlFreeDoc(doc);
+       if (!buf)
+               return NULL;
        pos = (char *) buf;
        if (strncmp(pos, "<?xml", 5) == 0) {
                pos = strchr(pos, '>');
index fbaf85a..fade6b6 100644 (file)
 int wps_version_number = 0x20;
 int wps_testing_dummy_cred = 0;
 int wps_corrupt_pkhash = 0;
+int wps_force_auth_types_in_use = 0;
+u16 wps_force_auth_types = 0;
+int wps_force_encr_types_in_use = 0;
+u16 wps_force_encr_types = 0;
 #endif /* CONFIG_WPS_TESTING */
 
 
@@ -170,7 +174,7 @@ void wps_deinit(struct wps_data *data)
        } else if (data->registrar)
                wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e);
 
-       wpabuf_free(data->dh_privkey);
+       wpabuf_clear_free(data->dh_privkey);
        wpabuf_free(data->dh_pubkey_e);
        wpabuf_free(data->dh_pubkey_r);
        wpabuf_free(data->last_msg);
index 2c91d16..2505d2d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Wi-Fi Protected Setup
- * Copyright (c) 2007-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2016, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -664,6 +664,16 @@ struct wps_context {
        u16 encr_types;
 
        /**
+        * encr_types_rsn - Enabled encryption types for RSN (WPS_ENCR_*)
+        */
+       u16 encr_types_rsn;
+
+       /**
+        * encr_types_wpa - Enabled encryption types for WPA (WPS_ENCR_*)
+        */
+       u16 encr_types_wpa;
+
+       /**
         * auth_types - Authentication types (bit field of WPS_AUTH_*)
         */
        u16 auth_types;
@@ -827,7 +837,7 @@ int wps_build_credential_wrap(struct wpabuf *msg,
 
 unsigned int wps_pin_checksum(unsigned int pin);
 unsigned int wps_pin_valid(unsigned int pin);
-unsigned int wps_generate_pin(void);
+int wps_generate_pin(unsigned int *pin);
 int wps_pin_str_valid(const char *pin);
 void wps_free_pending_msgs(struct upnp_pending_message *msgs);
 
index b689357..770f5e9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Wi-Fi Protected Setup - attribute building
- * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2016, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
 
 int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
 {
-       struct wpabuf *pubkey;
+       struct wpabuf *pubkey = NULL;
 
        wpa_printf(MSG_DEBUG, "WPS:  * Public Key");
-       wpabuf_free(wps->dh_privkey);
+       wpabuf_clear_free(wps->dh_privkey);
        wps->dh_privkey = NULL;
        if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey &&
            wps->wps->dh_ctx) {
@@ -298,7 +298,16 @@ 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;
-       wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type Flags");
+#ifdef CONFIG_WPS_TESTING
+       if (wps_force_auth_types_in_use) {
+               wpa_printf(MSG_DEBUG,
+                          "WPS: Testing - replace auth type 0x%x with 0x%x",
+                          auth_types, wps_force_auth_types);
+               auth_types = wps_force_auth_types;
+       }
+#endif /* CONFIG_WPS_TESTING */
+       wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type Flags (0x%x)",
+                  auth_types);
        wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS);
        wpabuf_put_be16(msg, 2);
        wpabuf_put_be16(msg, auth_types);
@@ -310,7 +319,16 @@ int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)
 {
        u16 encr_types = WPS_ENCR_TYPES;
        encr_types &= ~WPS_ENCR_WEP;
-       wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type Flags");
+#ifdef CONFIG_WPS_TESTING
+       if (wps_force_encr_types_in_use) {
+               wpa_printf(MSG_DEBUG,
+                          "WPS: Testing - replace encr type 0x%x with 0x%x",
+                          encr_types, wps_force_encr_types);
+               encr_types = wps_force_encr_types;
+       }
+#endif /* CONFIG_WPS_TESTING */
+       wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type Flags (0x%x)",
+                  encr_types);
        wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS);
        wpabuf_put_be16(msg, 2);
        wpabuf_put_be16(msg, encr_types);
@@ -395,7 +413,8 @@ int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
                   dev_pw_id);
        addr[0] = wpabuf_head(pubkey);
        hash_len = wpabuf_len(pubkey);
-       sha256_vector(1, addr, &hash_len, pubkey_hash);
+       if (sha256_vector(1, addr, &hash_len, pubkey_hash) < 0)
+               return -1;
 #ifdef CONFIG_WPS_TESTING
        if (wps_corrupt_pkhash) {
                wpa_hexdump(MSG_DEBUG, "WPS: Real Public Key Hash",
index 11a967b..756d57e 100644 (file)
@@ -83,10 +83,10 @@ static int wps_parse_vendor_ext_wfa(struct wps_parse_attr *attr, const u8 *pos,
        const u8 *end = pos + len;
        u8 id, elen;
 
-       while (pos + 2 <= end) {
+       while (end - pos >= 2) {
                id = *pos++;
                elen = *pos++;
-               if (pos + elen > end)
+               if (elen > end - pos)
                        break;
                if (wps_set_vendor_ext_wfa_subelem(attr, id, elen, pos) < 0)
                        return -1;
index eadb22f..e8c4579 100644 (file)
@@ -229,6 +229,16 @@ static int wps_workaround_cred_key(struct wps_credential *cred)
                cred->key_len--;
 #endif /* CONFIG_WPS_STRICT */
        }
+
+
+       if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) &&
+           (cred->key_len < 8 || has_ctrl_char(cred->key, cred->key_len))) {
+               wpa_printf(MSG_INFO, "WPS: Reject credential with invalid WPA/WPA2-Personal passphrase");
+               wpa_hexdump_ascii_key(MSG_INFO, "WPS: Network Key",
+                                     cred->key, cred->key_len);
+               return -1;
+       }
+
        return 0;
 }
 
index 88f85fe..2e34721 100644 (file)
@@ -90,7 +90,7 @@ int wps_derive_keys(struct wps_data *wps)
        }
 
        /* Own DH private key is not needed anymore */
-       wpabuf_free(wps->dh_privkey);
+       wpabuf_clear_free(wps->dh_privkey);
        wps->dh_privkey = NULL;
 
        wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared);
@@ -100,7 +100,7 @@ int wps_derive_keys(struct wps_data *wps)
        len[0] = wpabuf_len(dh_shared);
        sha256_vector(1, addr, len, dhkey);
        wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey));
-       wpabuf_free(dh_shared);
+       wpabuf_clear_free(dh_shared);
 
        /* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */
        addr[0] = wps->nonce_e;
@@ -129,23 +129,26 @@ int wps_derive_keys(struct wps_data *wps)
 }
 
 
-void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
-                   size_t dev_passwd_len)
+int wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
+                  size_t dev_passwd_len)
 {
        u8 hash[SHA256_MAC_LEN];
 
-       hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd,
-                   (dev_passwd_len + 1) / 2, hash);
+       if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd,
+                       (dev_passwd_len + 1) / 2, hash) < 0)
+               return -1;
        os_memcpy(wps->psk1, hash, WPS_PSK_LEN);
-       hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN,
-                   dev_passwd + (dev_passwd_len + 1) / 2,
-                   dev_passwd_len / 2, hash);
+       if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN,
+                       dev_passwd + (dev_passwd_len + 1) / 2,
+                       dev_passwd_len / 2, hash) < 0)
+               return -1;
        os_memcpy(wps->psk2, hash, WPS_PSK_LEN);
 
        wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password",
                              dev_passwd, dev_passwd_len);
        wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN);
        wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN);
+       return 0;
 }
 
 
@@ -173,7 +176,7 @@ struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
        wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size);
        if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted),
                                wpabuf_len(decrypted))) {
-               wpabuf_free(decrypted);
+               wpabuf_clear_free(decrypted);
                return NULL;
        }
 
@@ -184,14 +187,14 @@ struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
        pad = *pos;
        if (pad > wpabuf_len(decrypted)) {
                wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value");
-               wpabuf_free(decrypted);
+               wpabuf_clear_free(decrypted);
                return NULL;
        }
        for (i = 0; i < pad; i++) {
                if (*pos-- != pad) {
                        wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad "
                                   "string");
-                       wpabuf_free(decrypted);
+                       wpabuf_clear_free(decrypted);
                        return NULL;
                }
        }
@@ -235,20 +238,18 @@ unsigned int wps_pin_valid(unsigned int pin)
  * wps_generate_pin - Generate a random PIN
  * Returns: Eight digit PIN (i.e., including the checksum digit)
  */
-unsigned int wps_generate_pin(void)
+int wps_generate_pin(unsigned int *pin)
 {
        unsigned int val;
 
        /* Generate seven random digits for the PIN */
-       if (random_get_bytes((unsigned char *) &val, sizeof(val)) < 0) {
-               struct os_time now;
-               os_get_time(&now);
-               val = os_random() ^ now.sec ^ now.usec;
-       }
+       if (random_get_bytes((unsigned char *) &val, sizeof(val)) < 0)
+               return -1;
        val %= 10000000;
 
        /* Append checksum digit */
-       return val * 10 + wps_pin_checksum(val);
+       *pin = val * 10 + wps_pin_checksum(val);
+       return 0;
 }
 
 
@@ -375,7 +376,7 @@ struct wpabuf * wps_get_oob_cred(struct wps_context *wps, int rf_band,
            wps_build_mac_addr(plain, wps->dev.mac_addr) ||
            wps_build_wfa_ext(plain, 0, NULL, 0)) {
                os_free(data.new_psk);
-               wpabuf_free(plain);
+               wpabuf_clear_free(plain);
                return NULL;
        }
 
@@ -423,7 +424,7 @@ struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
            wps_build_wfa_ext(data, 0, NULL, 0)) {
                wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password "
                           "token");
-               wpabuf_free(data);
+               wpabuf_clear_free(data);
                return NULL;
        }
 
@@ -660,7 +661,7 @@ int wps_nfc_gen_dh(struct wpabuf **pubkey, struct wpabuf **privkey)
 
        wpabuf_free(*pubkey);
        *pubkey = pub;
-       wpabuf_free(*privkey);
+       wpabuf_clear_free(*privkey);
        *privkey = priv;
 
        return 0;
@@ -691,7 +692,7 @@ struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
        }
 
        *id = 0x10 + val % 0xfff0;
-       wpabuf_free(*dev_pw);
+       wpabuf_clear_free(*dev_pw);
        *dev_pw = pw;
 
        return wps_nfc_token_build(ndef, *id, *pubkey, *dev_pw);
index a23b979..301864d 100644 (file)
 extern int wps_version_number;
 extern int wps_testing_dummy_cred;
 extern int wps_corrupt_pkhash;
+extern int wps_force_auth_types_in_use;
+extern u16 wps_force_auth_types;
+extern int wps_force_encr_types_in_use;
+extern u16 wps_force_encr_types;
 #define WPS_VERSION wps_version_number
 
 #else /* CONFIG_WPS_TESTING */
index 9321b72..4175077 100644 (file)
@@ -173,7 +173,8 @@ static struct wpabuf * wps_build_m3(struct wps_data *wps)
                wpa_printf(MSG_DEBUG, "WPS: No Device Password available");
                return NULL;
        }
-       wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
+       if (wps_derive_psk(wps, wps->dev_password, wps->dev_password_len) < 0)
+               return NULL;
 
        if (wps->wps->ap && random_pool_ready() != 1) {
                wpa_printf(MSG_INFO,
@@ -224,11 +225,11 @@ static struct wpabuf * wps_build_m5(struct wps_data *wps)
            wps_build_encr_settings(wps, msg, plain) ||
            wps_build_wfa_ext(msg, 0, NULL, 0) ||
            wps_build_authenticator(wps, msg)) {
-               wpabuf_free(plain);
+               wpabuf_clear_free(plain);
                wpabuf_free(msg);
                return NULL;
        }
-       wpabuf_free(plain);
+       wpabuf_clear_free(plain);
 
        wps->state = RECV_M6;
        return msg;
@@ -394,11 +395,11 @@ static struct wpabuf * wps_build_m7(struct wps_data *wps)
            wps_build_encr_settings(wps, msg, plain) ||
            wps_build_wfa_ext(msg, 0, NULL, 0) ||
            wps_build_authenticator(wps, msg)) {
-               wpabuf_free(plain);
+               wpabuf_clear_free(plain);
                wpabuf_free(msg);
                return NULL;
        }
-       wpabuf_free(plain);
+       wpabuf_clear_free(plain);
 
        if (wps->wps->ap && wps->wps->registrar) {
                /*
@@ -1007,11 +1008,11 @@ static enum wps_process_res wps_process_m2(struct wps_data *wps,
                                              eattr.key_wrap_auth) ||
                    wps_process_creds(wps, eattr.cred, eattr.cred_len,
                                      eattr.num_cred, attr->version2 != NULL)) {
-                       wpabuf_free(decrypted);
+                       wpabuf_clear_free(decrypted);
                        wps->state = SEND_WSC_NACK;
                        return WPS_CONTINUE;
                }
-               wpabuf_free(decrypted);
+               wpabuf_clear_free(decrypted);
 
                wps->state = WPS_MSG_DONE;
                return WPS_CONTINUE;
@@ -1112,7 +1113,7 @@ static enum wps_process_res wps_process_m4(struct wps_data *wps,
        }
 
        if (wps_validate_m4_encr(decrypted, attr->version2 != NULL) < 0) {
-               wpabuf_free(decrypted);
+               wpabuf_clear_free(decrypted);
                wps->state = SEND_WSC_NACK;
                return WPS_CONTINUE;
        }
@@ -1122,11 +1123,11 @@ static enum wps_process_res wps_process_m4(struct wps_data *wps,
        if (wps_parse_msg(decrypted, &eattr) < 0 ||
            wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
            wps_process_r_snonce1(wps, eattr.r_snonce1)) {
-               wpabuf_free(decrypted);
+               wpabuf_clear_free(decrypted);
                wps->state = SEND_WSC_NACK;
                return WPS_CONTINUE;
        }
-       wpabuf_free(decrypted);
+       wpabuf_clear_free(decrypted);
 
        wps->state = SEND_M5;
        return WPS_CONTINUE;
@@ -1165,7 +1166,7 @@ static enum wps_process_res wps_process_m6(struct wps_data *wps,
        }
 
        if (wps_validate_m6_encr(decrypted, attr->version2 != NULL) < 0) {
-               wpabuf_free(decrypted);
+               wpabuf_clear_free(decrypted);
                wps->state = SEND_WSC_NACK;
                return WPS_CONTINUE;
        }
@@ -1175,11 +1176,11 @@ static enum wps_process_res wps_process_m6(struct wps_data *wps,
        if (wps_parse_msg(decrypted, &eattr) < 0 ||
            wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
            wps_process_r_snonce2(wps, eattr.r_snonce2)) {
-               wpabuf_free(decrypted);
+               wpabuf_clear_free(decrypted);
                wps->state = SEND_WSC_NACK;
                return WPS_CONTINUE;
        }
-       wpabuf_free(decrypted);
+       wpabuf_clear_free(decrypted);
 
        if (wps->wps->ap)
                wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_AP_PIN_SUCCESS,
@@ -1236,7 +1237,7 @@ static enum wps_process_res wps_process_m8(struct wps_data *wps,
 
        if (wps_validate_m8_encr(decrypted, wps->wps->ap,
                                 attr->version2 != NULL) < 0) {
-               wpabuf_free(decrypted);
+               wpabuf_clear_free(decrypted);
                wps->state = SEND_WSC_NACK;
                return WPS_CONTINUE;
        }
@@ -1249,11 +1250,11 @@ static enum wps_process_res wps_process_m8(struct wps_data *wps,
                              eattr.num_cred, attr->version2 != NULL) ||
            wps_process_ap_settings_e(wps, &eattr, decrypted,
                                      attr->version2 != NULL)) {
-               wpabuf_free(decrypted);
+               wpabuf_clear_free(decrypted);
                wps->state = SEND_WSC_NACK;
                return WPS_CONTINUE;
        }
-       wpabuf_free(decrypted);
+       wpabuf_clear_free(decrypted);
 
        wps->state = WPS_MSG_DONE;
        return WPS_CONTINUE;
index f7154f8..fe0c60b 100644 (file)
@@ -132,8 +132,8 @@ struct wps_data {
 void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
             const char *label, u8 *res, size_t res_len);
 int wps_derive_keys(struct wps_data *wps);
-void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
-                   size_t dev_passwd_len);
+int wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
+                  size_t dev_passwd_len);
 struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
                                          size_t encr_len);
 void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
index 3506307..23bed4b 100644 (file)
@@ -9,6 +9,7 @@
 #include "utils/includes.h"
 
 #include "utils/common.h"
+#include "utils/module_tests.h"
 #include "wps_attr_parse.h"
 
 struct wps_attr_parse_test {
@@ -17,7 +18,7 @@ struct wps_attr_parse_test {
        int extra;
 };
 
-const struct wps_attr_parse_test wps_attr_parse_test_cases[] = {
+static const struct wps_attr_parse_test wps_attr_parse_test_cases[] = {
        /* Empty message */
        { "", 0, 0 },
        /* Truncated attribute header */
index 4ca3a42..fac8bd8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Wi-Fi Protected Setup - Registrar
- * Copyright (c) 2008-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2016, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -703,7 +703,7 @@ void wps_registrar_deinit(struct wps_registrar *reg)
        eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
        eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
        wps_registrar_flush(reg);
-       wpabuf_free(reg->extra_cred);
+       wpabuf_clear_free(reg->extra_cred);
        os_free(reg);
 }
 
@@ -1577,13 +1577,13 @@ int wps_build_credential_wrap(struct wpabuf *msg,
        if (wbuf == NULL)
                return -1;
        if (wps_build_credential(wbuf, cred)) {
-               wpabuf_free(wbuf);
+               wpabuf_clear_free(wbuf);
                return -1;
        }
        wpabuf_put_be16(msg, ATTR_CRED);
        wpabuf_put_be16(msg, wpabuf_len(wbuf));
        wpabuf_put_buf(msg, wbuf);
-       wpabuf_free(wbuf);
+       wpabuf_clear_free(wbuf);
        return 0;
 }
 
@@ -1606,6 +1606,9 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
        wps->cred.ssid_len = wps->wps->ssid_len;
 
        /* Select the best authentication and encryption type */
+       wpa_printf(MSG_DEBUG,
+                  "WPS: Own auth types 0x%x - masked Enrollee auth types 0x%x",
+                  wps->wps->auth_types, wps->auth_type);
        if (wps->auth_type & WPS_AUTH_WPA2PSK)
                wps->auth_type = WPS_AUTH_WPA2PSK;
        else if (wps->auth_type & WPS_AUTH_WPAPSK)
@@ -1619,6 +1622,14 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
        }
        wps->cred.auth_type = wps->auth_type;
 
+       wpa_printf(MSG_DEBUG,
+                  "WPS: Own encr types 0x%x (rsn: 0x%x, wpa: 0x%x) - masked Enrollee encr types 0x%x",
+                  wps->wps->encr_types, wps->wps->encr_types_rsn,
+                  wps->wps->encr_types_wpa, wps->encr_type);
+       if (wps->wps->ap && wps->auth_type == WPS_AUTH_WPA2PSK)
+               wps->encr_type &= wps->wps->encr_types_rsn;
+       else if (wps->wps->ap && wps->auth_type == WPS_AUTH_WPAPSK)
+               wps->encr_type &= wps->wps->encr_types_wpa;
        if (wps->auth_type == WPS_AUTH_WPA2PSK ||
            wps->auth_type == WPS_AUTH_WPAPSK) {
                if (wps->encr_type & WPS_ENCR_AES)
@@ -1740,14 +1751,14 @@ use_provided:
                return -1;
 
        if (wps_build_credential(cred, &wps->cred)) {
-               wpabuf_free(cred);
+               wpabuf_clear_free(cred);
                return -1;
        }
 
        wpabuf_put_be16(msg, ATTR_CRED);
        wpabuf_put_be16(msg, wpabuf_len(cred));
        wpabuf_put_buf(msg, cred);
-       wpabuf_free(cred);
+       wpabuf_clear_free(cred);
 
 skip_cred_build:
        if (wps->wps->registrar->extra_cred) {
@@ -1785,7 +1796,7 @@ static struct wpabuf * wps_build_ap_cred(struct wps_data *wps)
        }
 
        if (wps_build_ap_settings(wps, plain)) {
-               wpabuf_free(plain);
+               wpabuf_clear_free(plain);
                wpabuf_free(msg);
                return NULL;
        }
@@ -1793,7 +1804,7 @@ static struct wpabuf * wps_build_ap_cred(struct wps_data *wps)
        wpabuf_put_be16(msg, ATTR_CRED);
        wpabuf_put_be16(msg, wpabuf_len(plain));
        wpabuf_put_buf(msg, plain);
-       wpabuf_free(plain);
+       wpabuf_clear_free(plain);
 
        return msg;
 }
@@ -1853,10 +1864,10 @@ static struct wpabuf * wps_build_m2(struct wps_data *wps)
                    wps_build_key_wrap_auth(wps, plain) ||
                    wps_build_encr_settings(wps, msg, plain)) {
                        wpabuf_free(msg);
-                       wpabuf_free(plain);
+                       wpabuf_clear_free(plain);
                        return NULL;
                }
-               wpabuf_free(plain);
+               wpabuf_clear_free(plain);
                config_in_m2 = 1;
        }
 #endif /* CONFIG_WPS_NFC */
@@ -1917,7 +1928,8 @@ static struct wpabuf * wps_build_m4(struct wps_data *wps)
 
        wpa_printf(MSG_DEBUG, "WPS: Building Message M4");
 
-       wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
+       if (wps_derive_psk(wps, wps->dev_password, wps->dev_password_len) < 0)
+               return NULL;
 
        plain = wpabuf_alloc(200);
        if (plain == NULL)
@@ -1938,11 +1950,11 @@ static struct wpabuf * wps_build_m4(struct wps_data *wps)
            wps_build_encr_settings(wps, msg, plain) ||
            wps_build_wfa_ext(msg, 0, NULL, 0) ||
            wps_build_authenticator(wps, msg)) {
-               wpabuf_free(plain);
+               wpabuf_clear_free(plain);
                wpabuf_free(msg);
                return NULL;
        }
-       wpabuf_free(plain);
+       wpabuf_clear_free(plain);
 
        wps->state = RECV_M5;
        return msg;
@@ -1973,11 +1985,11 @@ static struct wpabuf * wps_build_m6(struct wps_data *wps)
            wps_build_encr_settings(wps, msg, plain) ||
            wps_build_wfa_ext(msg, 0, NULL, 0) ||
            wps_build_authenticator(wps, msg)) {
-               wpabuf_free(plain);
+               wpabuf_clear_free(plain);
                wpabuf_free(msg);
                return NULL;
        }
-       wpabuf_free(plain);
+       wpabuf_clear_free(plain);
 
        wps->wps_pin_revealed = 1;
        wps->state = RECV_M7;
@@ -2010,11 +2022,11 @@ static struct wpabuf * wps_build_m8(struct wps_data *wps)
            wps_build_encr_settings(wps, msg, plain) ||
            wps_build_wfa_ext(msg, 0, NULL, 0) ||
            wps_build_authenticator(wps, msg)) {
-               wpabuf_free(plain);
-               wpabuf_free(msg);
+               wpabuf_clear_free(plain);
+               wpabuf_clear_free(msg);
                return NULL;
        }
-       wpabuf_free(plain);
+       wpabuf_clear_free(plain);
 
        wps->state = RECV_DONE;
        return msg;
@@ -2343,6 +2355,23 @@ static int wps_process_auth_type_flags(struct wps_data *wps, const u8 *auth)
 
        wpa_printf(MSG_DEBUG, "WPS: Enrollee Authentication Type flags 0x%x",
                   auth_types);
+#ifdef WPS_WORKAROUNDS
+       /*
+        * Some deployed implementations seem to advertise incorrect information
+        * in this attribute. A value of 0x1b (WPA2 + WPA + WPAPSK + OPEN, but
+        * no WPA2PSK) has been reported to be used. Add WPA2PSK to the list to
+        * avoid issues with building Credentials that do not use the strongest
+        * actually supported authentication option (that device does support
+        * WPA2PSK even when it does not claim it here).
+        */
+       if ((auth_types &
+            (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) ==
+           (WPS_AUTH_WPA2 | WPS_AUTH_WPAPSK)) {
+               wpa_printf(MSG_DEBUG,
+                          "WPS: Workaround - assume Enrollee supports WPA2PSK based on claimed WPA2 support");
+               auth_types |= WPS_AUTH_WPA2PSK;
+       }
+#endif /* WPS_WORKAROUNDS */
        wps->auth_type = wps->wps->auth_types & auth_types;
        if (wps->auth_type == 0) {
                wpa_printf(MSG_DEBUG, "WPS: No match in supported "
@@ -2757,7 +2786,7 @@ static enum wps_process_res wps_process_m5(struct wps_data *wps,
        }
 
        if (wps_validate_m5_encr(decrypted, attr->version2 != NULL) < 0) {
-               wpabuf_free(decrypted);
+               wpabuf_clear_free(decrypted);
                wps->state = SEND_WSC_NACK;
                return WPS_CONTINUE;
        }
@@ -2767,11 +2796,11 @@ static enum wps_process_res wps_process_m5(struct wps_data *wps,
        if (wps_parse_msg(decrypted, &eattr) < 0 ||
            wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
            wps_process_e_snonce1(wps, eattr.e_snonce1)) {
-               wpabuf_free(decrypted);
+               wpabuf_clear_free(decrypted);
                wps->state = SEND_WSC_NACK;
                return WPS_CONTINUE;
        }
-       wpabuf_free(decrypted);
+       wpabuf_clear_free(decrypted);
 
        wps->state = SEND_M6;
        return WPS_CONTINUE;
@@ -2909,7 +2938,7 @@ static enum wps_process_res wps_process_m7(struct wps_data *wps,
 
        if (wps_validate_m7_encr(decrypted, wps->wps->ap || wps->er,
                                 attr->version2 != NULL) < 0) {
-               wpabuf_free(decrypted);
+               wpabuf_clear_free(decrypted);
                wps->state = SEND_WSC_NACK;
                return WPS_CONTINUE;
        }
@@ -2920,12 +2949,12 @@ static enum wps_process_res wps_process_m7(struct wps_data *wps,
            wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
            wps_process_e_snonce2(wps, eattr.e_snonce2) ||
            wps_process_ap_settings_r(wps, &eattr)) {
-               wpabuf_free(decrypted);
+               wpabuf_clear_free(decrypted);
                wps->state = SEND_WSC_NACK;
                return WPS_CONTINUE;
        }
 
-       wpabuf_free(decrypted);
+       wpabuf_clear_free(decrypted);
 
        wps->state = SEND_M8;
        return WPS_CONTINUE;
index 44318e0..0c458c6 100644 (file)
@@ -1082,6 +1082,7 @@ upnp_wps_get_iface(struct upnp_wps_device_sm *sm, void *priv)
 void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm, void *priv)
 {
        struct upnp_wps_device_interface *iface;
+       struct upnp_wps_peer *peer;
 
        if (!sm)
                return;
@@ -1102,8 +1103,13 @@ void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm, void *priv)
                                            iface->wps->registrar);
        dl_list_del(&iface->list);
 
-       if (iface->peer.wps)
-               wps_deinit(iface->peer.wps);
+       while ((peer = dl_list_first(&iface->peers, struct upnp_wps_peer,
+                                    list))) {
+               if (peer->wps)
+                       wps_deinit(peer->wps);
+               dl_list_del(&peer->list);
+               os_free(peer);
+       }
        os_free(iface->ctx->ap_pin);
        os_free(iface->ctx);
        os_free(iface);
@@ -1141,6 +1147,7 @@ upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps,
        }
        wpa_printf(MSG_DEBUG, "WPS UPnP: Init interface instance %p", iface);
 
+       dl_list_init(&iface->peers);
        iface->ctx = ctx;
        iface->wps = wps;
        iface->priv = priv;
index 87b7ab1..b6f6df5 100644 (file)
 #ifndef WPS_UPNP_H
 #define WPS_UPNP_H
 
+#include "utils/list.h"
+
 struct upnp_wps_device_sm;
 struct wps_context;
 struct wps_data;
 
 struct upnp_wps_peer {
+       struct dl_list list;
        struct wps_data *wps;
 };
 
index f289fe6..6a7c627 100644 (file)
@@ -109,8 +109,7 @@ struct upnp_wps_device_interface {
        struct wps_context *wps;
        void *priv;
 
-       /* FIX: maintain separate structures for each UPnP peer */
-       struct upnp_wps_peer peer;
+       struct dl_list peers; /* active UPnP peer sessions */
 };
 
 /*
index 968fc03..a685ce4 100644 (file)
@@ -100,12 +100,6 @@ static int line_length(const char *l)
 }
 
 
-static int str_starts(const char *str, const char *start)
-{
-       return os_strncmp(str, start, os_strlen(start)) == 0;
-}
-
-
 /***************************************************************************
  * Advertisements.
  * These are multicast to the world to tell them we are here.
index d5b0b5b..7548e84 100644 (file)
@@ -300,7 +300,8 @@ static void http_put_empty(struct wpabuf *buf, enum http_reply_code code)
  * would appear to be required (given that we will be closing it!).
  */
 static void web_connection_parse_get(struct upnp_wps_device_sm *sm,
-                                    struct http_request *hreq, char *filename)
+                                    struct http_request *hreq,
+                                    const char *filename)
 {
        struct wpabuf *buf; /* output buffer, allocated */
        char *put_length_here;
@@ -409,6 +410,15 @@ send_buf:
 }
 
 
+static void wps_upnp_peer_del(struct upnp_wps_peer *peer)
+{
+       dl_list_del(&peer->list);
+       if (peer->wps)
+               wps_deinit(peer->wps);
+       os_free(peer);
+}
+
+
 static enum http_reply_code
 web_process_get_device_info(struct upnp_wps_device_sm *sm,
                            struct wpabuf **reply, const char **replyname)
@@ -426,7 +436,9 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm,
        if (!iface || iface->ctx->ap_pin == NULL)
                return HTTP_INTERNAL_SERVER_ERROR;
 
-       peer = &iface->peer;
+       peer = os_zalloc(sizeof(*peer));
+       if (!peer)
+               return HTTP_INTERNAL_SERVER_ERROR;
 
        /*
         * Request for DeviceInfo, i.e., M1 TLVs. This is a start of WPS
@@ -436,9 +448,6 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm,
         * registration.
         */
 
-       if (peer->wps)
-               wps_deinit(peer->wps);
-
        os_memset(&cfg, 0, sizeof(cfg));
        cfg.wps = iface->wps;
        cfg.pin = (u8 *) iface->ctx->ap_pin;
@@ -455,8 +464,22 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm,
                *reply = NULL;
        if (*reply == NULL) {
                wpa_printf(MSG_INFO, "WPS UPnP: Failed to get DeviceInfo");
+               os_free(peer);
                return HTTP_INTERNAL_SERVER_ERROR;
        }
+
+       if (dl_list_len(&iface->peers) > 3) {
+               struct upnp_wps_peer *old;
+
+               old = dl_list_first(&iface->peers, struct upnp_wps_peer, list);
+               if (old) {
+                       wpa_printf(MSG_DEBUG, "WPS UPnP: Drop oldest active session");
+                       wps_upnp_peer_del(old);
+               }
+       }
+       dl_list_add_tail(&iface->peers, &peer->list);
+       /* TODO: Could schedule a timeout to free the entry */
+
        *replyname = name;
        return HTTP_OK;
 }
@@ -472,6 +495,8 @@ web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
        enum wps_process_res res;
        enum wsc_op_code op_code;
        struct upnp_wps_device_interface *iface;
+       struct wps_parse_attr attr;
+       struct upnp_wps_peer *tmp, *peer;
 
        iface = dl_list_first(&sm->interfaces,
                              struct upnp_wps_device_interface, list);
@@ -487,11 +512,56 @@ web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
        msg = xml_get_base64_item(data, "NewInMessage", &ret);
        if (msg == NULL)
                return ret;
-       res = wps_process_msg(iface->peer.wps, WSC_UPnP, msg);
-       if (res == WPS_FAILURE)
+
+       if (wps_parse_msg(msg, &attr)) {
+               wpa_printf(MSG_DEBUG,
+                          "WPS UPnP: Could not parse PutMessage - NewInMessage");
+               wpabuf_free(msg);
+               return HTTP_BAD_REQUEST;
+       }
+
+       /* Find a matching active peer session */
+       peer = NULL;
+       dl_list_for_each(tmp, &iface->peers, struct upnp_wps_peer, list) {
+               if (!tmp->wps)
+                       continue;
+               if (attr.enrollee_nonce &&
+                   os_memcmp(tmp->wps->nonce_e, attr.enrollee_nonce,
+                             WPS_NONCE_LEN) != 0)
+                       continue; /* Enrollee nonce mismatch */
+               if (attr.msg_type &&
+                   *attr.msg_type != WPS_M2 &&
+                   *attr.msg_type != WPS_M2D &&
+                   attr.registrar_nonce &&
+                   os_memcmp(tmp->wps->nonce_r, attr.registrar_nonce,
+                             WPS_NONCE_LEN) != 0)
+                       continue; /* Registrar nonce mismatch */
+               peer = tmp;
+               break;
+       }
+       if (!peer) {
+               /*
+                 Try to use the first entry in case message could work with
+                * it. The actual handler function will reject this, if needed.
+                * This maintains older behavior where only a single peer entry
+                * was supported.
+                */
+               peer = dl_list_first(&iface->peers, struct upnp_wps_peer, list);
+       }
+       if (!peer || !peer->wps) {
+               wpa_printf(MSG_DEBUG, "WPS UPnP: No active peer entry found");
+               wpabuf_free(msg);
+               return HTTP_BAD_REQUEST;
+       }
+
+       res = wps_process_msg(peer->wps, WSC_UPnP, msg);
+       if (res == WPS_FAILURE) {
                *reply = NULL;
-       else
-               *reply = wps_get_msg(iface->peer.wps, &op_code);
+               wpa_printf(MSG_DEBUG, "WPS UPnP: Drop active peer session");
+               wps_upnp_peer_del(peer);
+       } else {
+               *reply = wps_get_msg(peer->wps, &op_code);
+       }
        wpabuf_free(msg);
        if (*reply == NULL)
                return HTTP_INTERNAL_SERVER_ERROR;
index 0d89b92..61afc9a 100644 (file)
@@ -12,6 +12,7 @@ ca_cert=auth_serv/ca.pem
 server_cert=auth_serv/server.pem
 private_key=auth_serv/server.key
 ocsp_stapling_response=LOGDIR/ocsp-server-cache.der
+ocsp_stapling_response_multi=LOGDIR/ocsp-multi-server-cache.der
 server_id=server.w1.fi
 eap_sim_db=unix:/tmp/hlr_auc_gw.sock
 dh_file=auth_serv/dh.conf
index d9ee031..9bacbfa 100644 (file)
@@ -12,6 +12,7 @@ ca_cert=auth_serv/ca.pem
 server_cert=auth_serv/server.pem
 private_key=auth_serv/server.key
 ocsp_stapling_response=LOGDIR/ocsp-server-cache.der
+ocsp_stapling_response_multi=LOGDIR/ocsp-multi-server-cache.der
 server_id=server2.w1.fi
 eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=LOGDIR/hostapd.db
 dh_file=auth_serv/dh.conf
index 3738e6c..b85b9c5 100644 (file)
@@ -11,6 +11,9 @@
 "osen@example.com"     WFA-UNAUTH-TLS
 "unauth-tls"   UNAUTH-TLS
 
+"WFA-SimpleConfig-Enrollee-1-0"        WSC
+"WFA-SimpleConfig-Enrollee-unexpected" WSC
+
 "erp-fast@example.com" FAST
 "erp-fast@example.com" GTC     "password"      [2]
 "erp-gpsk@example.com" GPSK    "abcdefghijklmnop0123456789abcdef"
@@ -24,6 +27,8 @@
 "erp-tls@example.com"  TLS
 "erp-ttls@example.com" TTLS
 "erp-ttls@example.com" TTLS-PAP        "password"      [2]
+"erp-ttls"     TTLS
+"erp-ttls"     TTLS-PAP        "password"      [2]
 "erp-ikev2@example.com"        IKEV2   "password"
 
 "vlan1"        PAX     0123456789abcdef0123456789abcdef
@@ -36,6 +41,18 @@ radius_accept_attr=64:d:13
 radius_accept_attr=65:d:6
 radius_accept_attr=81:s:2
 
+"vlan1b"       PAX     0123456789abcdef0123456789abcdef
+radius_accept_attr=56:x:32000001
+
+"vlan1tagged"   PAX     0123456789abcdef0123456789abcdef
+radius_accept_attr=56:x:31000001
+
+"vlan12mixed"   PAX     0123456789abcdef0123456789abcdef
+radius_accept_attr=56:x:31000001
+radius_accept_attr=64:d:13
+radius_accept_attr=65:d:6
+radius_accept_attr=81:s:2
+
 "test-class"   PAX     0123456789abcdef0123456789abcdef
 radius_accept_attr=25:x:00112233445566778899
 
@@ -46,6 +63,8 @@ radius_accept_attr=25:x:00112233445566778899aa
 "gpsk-user-session-timeout"    GPSK    "abcdefghijklmnop0123456789abcdef"
 radius_accept_attr=27:d:3
 
+"phase1-user"  MSCHAPV2,MD5,GTC        "password"
+
 "020000000000" MACACL  "020000000000"
 
 "020000000100" MACACL  "020000000100"
@@ -56,6 +75,8 @@ radius_accept_attr=89:s:macacl-cui-test
 "0232010000000000@peap"        PEAP,AKA
 "0232010000000000@fast"        FAST,AKA
 "6555444333222111@both" AKA',AKA
+"peap-ver0"    PEAP    [ver=0]
+"peap-ver1"    PEAP    [ver=1]
 
 "0"*           AKA
 "1"*           SIM
@@ -85,10 +106,12 @@ radius_accept_attr=89:s:macacl-cui-test
 "mschap user"  TTLS-MSCHAP     "password"      [2]
 "DOMAIN\mschapv2 user" TTLS-MSCHAPV2   hash:8846f7eaee8fb117ad06bdd830b7586c   [2]
 "hs20-test"    TTLS-MSCHAPV2   "password"      [2]
+"hs20-test-with-domain@example.com"    TTLS-MSCHAPV2   "password"      [2]
 "utf8-user"    TTLS-MSCHAPV2   "secret-åäö-€-password"    [2]
 "utf8-user-hash"       TTLS-MSCHAPV2   hash:bd5844fad2489992da7fe8c5a01559cf   [2]
 
 "user" MSCHAPV2,MD5,GTC        "password"      [2]
+"user@example.com"     MSCHAPV2,MD5,GTC        "password"      [2]
 "user2"        MSCHAPV2,MD5,GTC        "password"      [2]
 "DOMAIN\user3" MSCHAPV2        "password"      [2]
 "user-no-passwd"       MSCHAPV2,MD5,GTC        [2]
index e5ad0d7..f8ab168 100644 (file)
@@ -2,3 +2,6 @@
 radius_accept_attr=64:d:13
 radius_accept_attr=65:d:6
 radius_accept_attr=81:s:2
+
+"vlan1tagged"   PAX     0123456789abcdef0123456789abcdef
+radius_accept_attr=56:x:31000002
index c803dd3..23467b6 100644 (file)
@@ -31,7 +31,7 @@ cert_opt      = ca_default
 
 copy_extensions = copy
 
-default_days   = 365
+default_days   = 3650
 default_crl_days= 30
 default_md     = default
 preserve       = no
index a04b886..f2bb4bc 100644 (file)
@@ -1,13 +1,13 @@
 -----BEGIN CERTIFICATE-----
-MIICAjCCAaegAwIBAgIJANry4MnEh6ybMAoGCCqGSM49BAMCMFIxCzAJBgNVBAYT
+MIICAjCCAaegAwIBAgIJAPdTJDJVY8FeMAoGCCqGSM49BAMCMFIxCzAJBgNVBAYT
 AkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxIDAeBgNVBAMM
-F1N1aXRlIEIgMTI4LWJpdCBSb290IENBMB4XDTE1MDEyNTExMjk1M1oXDTI1MDEy
-MjExMjk1M1owUjELMAkGA1UEBhMCRkkxETAPBgNVBAcMCEhlbHNpbmtpMQ4wDAYD
+F1N1aXRlIEIgMTI4LWJpdCBSb290IENBMB4XDTE2MDIwMTA5MjUyM1oXDTI2MDEy
+OTA5MjUyM1owUjELMAkGA1UEBhMCRkkxETAPBgNVBAcMCEhlbHNpbmtpMQ4wDAYD
 VQQKDAV3MS5maTEgMB4GA1UEAwwXU3VpdGUgQiAxMjgtYml0IFJvb3QgQ0EwWTAT
-BgcqhkjOPQIBBggqhkjOPQMBBwNCAASqUNEASvF83W/PA2xqq/2fhIgZeLdSnnLc
-0yLcjku5WvpLHGy/pLhRsvghtjWjTsgqBqfeW8tq0ywsUdY0ylsNo2YwZDAdBgNV
-HQ4EFgQU/IP6SzTrGV4cfeWF7Mf8IfXodWgwHwYDVR0jBBgwFoAU/IP6SzTrGV4c
-feWF7Mf8IfXodWgwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYw
-CgYIKoZIzj0EAwIDSQAwRgIhAIfEWvUO4+28moKfVL8RXbKKexTZk82UCRL2yi01
-c81AAiEAxBGPZU0vnwxjAaCOhRIH+5X9PDkdLSs25S4ua6BicT8=
+BgcqhkjOPQIBBggqhkjOPQMBBwNCAARwuOrBY7USD4V+MOidWwSkY3S8+4lXWUZ3
++YqRAcVjEPMtokc0zyJAofV0BPgz/yt41gXmvOTALpXfdHpPkeqOo2YwZDAdBgNV
+HQ4EFgQUcyrcCIxm5gVTsimSHN2Km8Amy/gwHwYDVR0jBBgwFoAUcyrcCIxm5gVT
+simSHN2Km8Amy/gwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYw
+CgYIKoZIzj0EAwIDSQAwRgIhAOHO2+N8tgUQKakQcLGR+kB3mKPmjyhu478xmrKg
+wQq9AiEAmnN7YQBgVBk/+zOri1rCCP8DJ3gE+BSUA3cyQGUvtAc=
 -----END CERTIFICATE-----
index 391e9ed..bb28e91 100644 (file)
@@ -2,7 +2,7 @@
 BggqhkjOPQMBBw==
 -----END EC PARAMETERS-----
 -----BEGIN EC PRIVATE KEY-----
-MHcCAQEEIN/qNiKLsQDpQWumSiRRF6LM7TP7GTwdS8vG7xP8vKz/oAoGCCqGSM49
-AwEHoUQDQgAEvl8WCLIK1vIZbxQZ7yDyKzzgvoxlhl+VwbuQNuzcWTq6QJqdEXbH
-gFohTPzAXxlSyHi45Uz6yWrR/uq2OldcmQ==
+MHcCAQEEIEoiI2GTM68G6vG2zpbM/a5j7e2yBCCWxaNe+nKPT47+oAoGCCqGSM49
+AwEHoUQDQgAEJu1Mahit1ZcoiSaYwew1ugckxpSGVvbrZUVf/IF13kiW+JBMcgrX
+oukSJOw2LVtLLJEf24YHRST8Dw7Kpzr+bQ==
 -----END EC PRIVATE KEY-----
index 4222b1e..e5d021c 100644 (file)
@@ -1,30 +1,30 @@
 Certificate:
     Data:
         Version: 3 (0x2)
-        Serial Number: 9573410140069116734 (0x84db95ccdff13b3e)
+        Serial Number: 11095559361558864825 (0x99fb5873d9f9e3b9)
     Signature Algorithm: ecdsa-with-SHA256
         Issuer: C=FI, L=Helsinki, O=w1.fi, CN=Suite B 128-bit Root CA
         Validity
-            Not Before: Jan 25 11:29:53 2015 GMT
-            Not After : Jan 25 11:29:53 2016 GMT
+            Not Before: Feb  1 09:25:23 2016 GMT
+            Not After : Jan 29 09:25:23 2026 GMT
         Subject: C=FI, O=w1.fi, CN=server.w1.fi
         Subject Public Key Info:
             Public Key Algorithm: id-ecPublicKey
                 Public-Key: (256 bit)
                 pub: 
-                    04:be:5f:16:08:b2:0a:d6:f2:19:6f:14:19:ef:20:
-                    f2:2b:3c:e0:be:8c:65:86:5f:95:c1:bb:90:36:ec:
-                    dc:59:3a:ba:40:9a:9d:11:76:c7:80:5a:21:4c:fc:
-                    c0:5f:19:52:c8:78:b8:e5:4c:fa:c9:6a:d1:fe:ea:
-                    b6:3a:57:5c:99
+                    04:26:ed:4c:6a:18:ad:d5:97:28:89:26:98:c1:ec:
+                    35:ba:07:24:c6:94:86:56:f6:eb:65:45:5f:fc:81:
+                    75:de:48:96:f8:90:4c:72:0a:d7:a2:e9:12:24:ec:
+                    36:2d:5b:4b:2c:91:1f:db:86:07:45:24:fc:0f:0e:
+                    ca:a7:3a:fe:6d
                 ASN1 OID: prime256v1
         X509v3 extensions:
             X509v3 Basic Constraints: critical
                 CA:FALSE
             X509v3 Subject Key Identifier: 
-                6E:21:26:96:72:29:39:BF:8B:EF:EB:65:CD:E0:4E:97:6F:1A:2C:E5
+                A4:A4:2C:68:89:C6:74:44:B4:BF:9A:BF:5F:D6:02:2C:DC:FE:4F:5A
             X509v3 Authority Key Identifier: 
-                keyid:FC:83:FA:4B:34:EB:19:5E:1C:7D:E5:85:EC:C7:FC:21:F5:E8:75:68
+                keyid:73:2A:DC:08:8C:66:E6:05:53:B2:29:92:1C:DD:8A:9B:C0:26:CB:F8
 
             X509v3 Subject Alternative Name: critical
                 DNS:server.w1.fi
@@ -33,21 +33,21 @@ Certificate:
             X509v3 Key Usage: 
                 Digital Signature, Key Encipherment
     Signature Algorithm: ecdsa-with-SHA256
-         30:44:02:20:47:b1:5e:57:ae:6c:0b:df:78:11:79:5c:b2:60:
-         fd:0c:9c:37:18:19:fe:c1:b6:ca:f6:4f:62:63:13:ff:ff:64:
-         02:20:07:1f:3b:1d:c7:d8:fe:ff:26:0b:68:d0:85:bc:01:15:
-         62:e4:7f:f4:c7:e4:ad:d5:da:40:44:5a:0b:f5:72:9e
+         30:45:02:20:25:ec:c6:e5:a2:66:e9:3a:f5:fa:b0:4a:dd:24:
+         89:fa:d0:e3:78:a6:2e:a5:da:39:8b:96:7a:ac:ae:17:1f:ef:
+         02:21:00:a8:2a:d1:f1:54:73:b9:8e:b9:8b:48:63:54:01:b3:
+         a3:cd:02:05:ba:d0:53:63:0b:d0:9c:f2:13:74:60:7a:a2
 -----BEGIN CERTIFICATE-----
-MIICDzCCAbagAwIBAgIJAITblczf8Ts+MAoGCCqGSM49BAMCMFIxCzAJBgNVBAYT
+MIICEDCCAbagAwIBAgIJAJn7WHPZ+eO5MAoGCCqGSM49BAMCMFIxCzAJBgNVBAYT
 AkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxIDAeBgNVBAMM
-F1N1aXRlIEIgMTI4LWJpdCBSb290IENBMB4XDTE1MDEyNTExMjk1M1oXDTE2MDEy
-NTExMjk1M1owNDELMAkGA1UEBhMCRkkxDjAMBgNVBAoMBXcxLmZpMRUwEwYDVQQD
-DAxzZXJ2ZXIudzEuZmkwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS+XxYIsgrW
-8hlvFBnvIPIrPOC+jGWGX5XBu5A27NxZOrpAmp0RdseAWiFM/MBfGVLIeLjlTPrJ
-atH+6rY6V1yZo4GSMIGPMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFG4hJpZyKTm/
-i+/rZc3gTpdvGizlMB8GA1UdIwQYMBaAFPyD+ks06xleHH3lhezH/CH16HVoMBoG
+F1N1aXRlIEIgMTI4LWJpdCBSb290IENBMB4XDTE2MDIwMTA5MjUyM1oXDTI2MDEy
+OTA5MjUyM1owNDELMAkGA1UEBhMCRkkxDjAMBgNVBAoMBXcxLmZpMRUwEwYDVQQD
+DAxzZXJ2ZXIudzEuZmkwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQm7UxqGK3V
+lyiJJpjB7DW6ByTGlIZW9utlRV/8gXXeSJb4kExyCtei6RIk7DYtW0sskR/bhgdF
+JPwPDsqnOv5to4GSMIGPMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFKSkLGiJxnRE
+tL+av1/WAizc/k9aMB8GA1UdIwQYMBaAFHMq3AiMZuYFU7IpkhzdipvAJsv4MBoG
 A1UdEQEB/wQQMA6CDHNlcnZlci53MS5maTAWBgNVHSUBAf8EDDAKBggrBgEFBQcD
-ATALBgNVHQ8EBAMCBaAwCgYIKoZIzj0EAwIDRwAwRAIgR7FeV65sC994EXlcsmD9
-DJw3GBn+wbbK9k9iYxP//2QCIAcfOx3H2P7/Jgto0IW8ARVi5H/0x+St1dpARFoL
-9XKe
+ATALBgNVHQ8EBAMCBaAwCgYIKoZIzj0EAwIDSAAwRQIgJezG5aJm6Tr1+rBK3SSJ
++tDjeKYupdo5i5Z6rK4XH+8CIQCoKtHxVHO5jrmLSGNUAbOjzQIFutBTYwvQnPIT
+dGB6og==
 -----END CERTIFICATE-----
index e390c06..dc6a7f0 100644 (file)
@@ -2,7 +2,7 @@
 BggqhkjOPQMBBw==
 -----END EC PARAMETERS-----
 -----BEGIN EC PRIVATE KEY-----
-MHcCAQEEIL52ZfaYm8GAzhot94BCQriTmQEq2+JPkS+HCwUpLuwaoAoGCCqGSM49
-AwEHoUQDQgAEnE2sSN8ZOateUoi3Ao0VewSH+1ceTf+NkiJpoymO6U6q0CSlG2bp
-dZyBk+6UIOD9WiCi2tN+QGbvPnPrlLfBOg==
+MHcCAQEEINKa/lt6n2rVp/6cLl65e8GR0vY0WKDfpBGltnggadz3oAoGCCqGSM49
+AwEHoUQDQgAEDbAoh2fby/hkxmF9Hm8fyzBHCpaDzFuAyG+SYmTBqpccxTXXfSNJ
+eYQXMoPTm14BXWgiTf7U9/C3FHolI5oBNQ==
 -----END EC PRIVATE KEY-----
index 9a6aba8..a4d6824 100644 (file)
@@ -1,30 +1,30 @@
 Certificate:
     Data:
         Version: 3 (0x2)
-        Serial Number: 9573410140069116735 (0x84db95ccdff13b3f)
+        Serial Number: 11095559361558864826 (0x99fb5873d9f9e3ba)
     Signature Algorithm: ecdsa-with-SHA256
         Issuer: C=FI, L=Helsinki, O=w1.fi, CN=Suite B 128-bit Root CA
         Validity
-            Not Before: Jan 25 11:29:53 2015 GMT
-            Not After : Jan 25 11:29:53 2016 GMT
+            Not Before: Feb  1 09:25:23 2016 GMT
+            Not After : Jan 29 09:25:23 2026 GMT
         Subject: C=FI, O=w1.fi, CN=user
         Subject Public Key Info:
             Public Key Algorithm: id-ecPublicKey
                 Public-Key: (256 bit)
                 pub: 
-                    04:9c:4d:ac:48:df:19:39:ab:5e:52:88:b7:02:8d:
-                    15:7b:04:87:fb:57:1e:4d:ff:8d:92:22:69:a3:29:
-                    8e:e9:4e:aa:d0:24:a5:1b:66:e9:75:9c:81:93:ee:
-                    94:20:e0:fd:5a:20:a2:da:d3:7e:40:66:ef:3e:73:
-                    eb:94:b7:c1:3a
+                    04:0d:b0:28:87:67:db:cb:f8:64:c6:61:7d:1e:6f:
+                    1f:cb:30:47:0a:96:83:cc:5b:80:c8:6f:92:62:64:
+                    c1:aa:97:1c:c5:35:d7:7d:23:49:79:84:17:32:83:
+                    d3:9b:5e:01:5d:68:22:4d:fe:d4:f7:f0:b7:14:7a:
+                    25:23:9a:01:35
                 ASN1 OID: prime256v1
         X509v3 extensions:
             X509v3 Basic Constraints: 
                 CA:FALSE
             X509v3 Subject Key Identifier: 
-                89:28:76:9A:42:DB:B6:F8:36:97:63:8F:7D:0A:EA:0B:FE:66:2B:CD
+                0E:0F:F9:64:AC:F9:DB:7C:45:22:9A:DF:E0:DB:1E:25:9D:8F:4D:C3
             X509v3 Authority Key Identifier: 
-                keyid:FC:83:FA:4B:34:EB:19:5E:1C:7D:E5:85:EC:C7:FC:21:F5:E8:75:68
+                keyid:73:2A:DC:08:8C:66:E6:05:53:B2:29:92:1C:DD:8A:9B:C0:26:CB:F8
 
             X509v3 Subject Alternative Name: 
                 email:user@w1.fi
@@ -33,20 +33,20 @@ Certificate:
             X509v3 Key Usage: 
                 Digital Signature, Key Encipherment
     Signature Algorithm: ecdsa-with-SHA256
-         30:45:02:20:26:84:14:f6:50:ac:ed:da:88:27:6d:18:d5:b3:
-         2c:c8:59:ea:2a:c3:ae:69:03:79:0d:66:5e:5f:a5:52:27:92:
-         02:21:00:db:8d:fd:58:e5:22:9b:17:32:57:34:e9:2e:30:da:
-         1d:77:4c:15:18:9b:7d:e4:5d:bc:64:cd:21:ff:57:df:16
+         30:44:02:20:12:a1:d9:30:43:fb:12:3d:67:72:a2:12:24:7c:
+         cb:1e:ce:f7:e6:fe:b6:79:b4:af:d8:85:72:49:2d:e9:de:01:
+         02:20:18:f3:6a:65:5d:c0:04:df:28:5a:44:b1:5f:75:25:eb:
+         a8:56:e9:5d:35:3c:9e:8d:63:cc:47:7f:22:a1:c0:27
 -----BEGIN CERTIFICATE-----
-MIIB/TCCAaOgAwIBAgIJAITblczf8Ts/MAoGCCqGSM49BAMCMFIxCzAJBgNVBAYT
+MIIB/DCCAaOgAwIBAgIJAJn7WHPZ+eO6MAoGCCqGSM49BAMCMFIxCzAJBgNVBAYT
 AkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxIDAeBgNVBAMM
-F1N1aXRlIEIgMTI4LWJpdCBSb290IENBMB4XDTE1MDEyNTExMjk1M1oXDTE2MDEy
-NTExMjk1M1owLDELMAkGA1UEBhMCRkkxDjAMBgNVBAoMBXcxLmZpMQ0wCwYDVQQD
-DAR1c2VyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnE2sSN8ZOateUoi3Ao0V
-ewSH+1ceTf+NkiJpoymO6U6q0CSlG2bpdZyBk+6UIOD9WiCi2tN+QGbvPnPrlLfB
-OqOBhzCBhDAJBgNVHRMEAjAAMB0GA1UdDgQWBBSJKHaaQtu2+DaXY499CuoL/mYr
-zTAfBgNVHSMEGDAWgBT8g/pLNOsZXhx95YXsx/wh9eh1aDAVBgNVHREEDjAMgQp1
+F1N1aXRlIEIgMTI4LWJpdCBSb290IENBMB4XDTE2MDIwMTA5MjUyM1oXDTI2MDEy
+OTA5MjUyM1owLDELMAkGA1UEBhMCRkkxDjAMBgNVBAoMBXcxLmZpMQ0wCwYDVQQD
+DAR1c2VyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDbAoh2fby/hkxmF9Hm8f
+yzBHCpaDzFuAyG+SYmTBqpccxTXXfSNJeYQXMoPTm14BXWgiTf7U9/C3FHolI5oB
+NaOBhzCBhDAJBgNVHRMEAjAAMB0GA1UdDgQWBBQOD/lkrPnbfEUimt/g2x4lnY9N
+wzAfBgNVHSMEGDAWgBRzKtwIjGbmBVOyKZIc3YqbwCbL+DAVBgNVHREEDjAMgQp1
 c2VyQHcxLmZpMBMGA1UdJQQMMAoGCCsGAQUFBwMCMAsGA1UdDwQEAwIFoDAKBggq
-hkjOPQQDAgNIADBFAiAmhBT2UKzt2ognbRjVsyzIWeoqw65pA3kNZl5fpVInkgIh
-ANuN/VjlIpsXMlc06S4w2h13TBUYm33kXbxkzSH/V98W
+hkjOPQQDAgNHADBEAiASodkwQ/sSPWdyohIkfMsezvfm/rZ5tK/YhXJJLeneAQIg
+GPNqZV3ABN8oWkSxX3Ul66hW6V01PJ6NY8xHfyKhwCc=
 -----END CERTIFICATE-----
index 0054ba8..b745ed3 100644 (file)
@@ -1,15 +1,15 @@
 -----BEGIN CERTIFICATE-----
-MIICPTCCAcSgAwIBAgIJAL63h7lu0KZpMAoGCCqGSM49BAMDMFIxCzAJBgNVBAYT
+MIICPjCCAcSgAwIBAgIJAIEUIb9N+rpkMAoGCCqGSM49BAMDMFIxCzAJBgNVBAYT
 AkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxIDAeBgNVBAMM
-F1N1aXRlIEIgMTkyLWJpdCBSb290IENBMB4XDTE1MDEyNTExMzIwM1oXDTI1MDEy
-MjExMzIwM1owUjELMAkGA1UEBhMCRkkxETAPBgNVBAcMCEhlbHNpbmtpMQ4wDAYD
+F1N1aXRlIEIgMTkyLWJpdCBSb290IENBMB4XDTE2MDIwMTA5MjYyNFoXDTI2MDEy
+OTA5MjYyNFowUjELMAkGA1UEBhMCRkkxETAPBgNVBAcMCEhlbHNpbmtpMQ4wDAYD
 VQQKDAV3MS5maTEgMB4GA1UEAwwXU3VpdGUgQiAxOTItYml0IFJvb3QgQ0EwdjAQ
-BgcqhkjOPQIBBgUrgQQAIgNiAAQjdOMC9bqcDR9/SaOhxNbmQLQTGZfhtmoxHkJL
-5GG3bwW5hYA2jYHWU84H+mR6om6fg78G+IxjLly2OWiByYUeWDcsYqLGj3UHHaVv
-rIitaRPyg3dExemnmK3zjgXnoaajZjBkMB0GA1UdDgQWBBSuBbynInvH0vn8IKZc
-MbtBTo9svTAfBgNVHSMEGDAWgBSuBbynInvH0vn8IKZcMbtBTo9svTASBgNVHRMB
-Af8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjBZ
-vEbGRDQNvzAY3nfYrsrE2Dd11smT6zv0mIvDeQCktbISGpStRBQjAaFjcCyjDEkC
-MH7ywcqJe+mpWDt5xFJvB52iZ7rX7rO0OX0qmjI38PC0IOo7euJdfcC1gHdSoAW3
-bA==
+BgcqhkjOPQIBBgUrgQQAIgNiAARWEuSpvRL6glbrbPMhDEcvHpQCirI4GtFDFYUE
+YIDqRObNZkeM4A9ygH3HUUmdm3SLHVxb+2nIVfPY3jyxwfOZGiL6ASomy1WwGY0A
+AaXU61MCiJBny1VTsjR7Dw+VcRejZjBkMB0GA1UdDgQWBBS4l8m+YxKr9qCMtl77
+l24QjtxI9TAfBgNVHSMEGDAWgBS4l8m+YxKr9qCMtl77l24QjtxI9TASBgNVHRMB
+Af8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjEA
+v+QeMLDKAY3+9dbdzPit9WCg7erYxa0LsV6ZTr4wIYwUIkybksD1Bwlq7Sw/lVpO
+AjBy4q3wJbj6unHQq9VsCKpHWiTi/WeKRo8X0djScKsN7R92A3vGgdhVEAXP0vTl
+Rn0=
 -----END CERTIFICATE-----
index 9cd76ee..e59a9be 100644 (file)
@@ -2,8 +2,8 @@
 BgUrgQQAIg==
 -----END EC PARAMETERS-----
 -----BEGIN EC PRIVATE KEY-----
-MIGkAgEBBDCjaz/zVDXqNO/XprtliomKOC6QjbBFgsF2YwUAtKB5ukL4miVGNyCu
-jIlq9eUD1x6gBwYFK4EEACKhZANiAARWq1ut1b6ctOFBkEOjULL3VjJFP15g0gk+
-sBTMBogU5WRN7Qod/jfem5k4O7FKYZNAarDFMh2yDMXZvRooiNyL0AH2wk0qzN5u
-n02JOt9Q76TVYflE91C5DTxjgLOgxBw=
+MIGkAgEBBDAgwG8tK5eYT4AX09cjhztI1oSnO7iEVf8n6UdbY41gmuU+ce+HPfpt
+mRFxdKSU29CgBwYFK4EEACKhZANiAAS4CCNfatEOzJswkLMlEn+bPMUEYQEYQwad
+uiJ3hJHkHxKnjjamvn+OCHxZwX0I2ci19y+cxgCIAKHRI2C/iijvr12ZcOkVEysf
+PODhGzHDloYyEfLcPSJ9hTk1ZIvyRSU=
 -----END EC PRIVATE KEY-----
index a7cc37e..f30e09f 100644 (file)
@@ -1,32 +1,32 @@
 Certificate:
     Data:
         Version: 3 (0x2)
-        Serial Number: 9347590364512421238 (0x81b94fe92ea08576)
+        Serial Number: 11652367451091730033 (0xa1b58675baa57e71)
     Signature Algorithm: ecdsa-with-SHA384
         Issuer: C=FI, L=Helsinki, O=w1.fi, CN=Suite B 192-bit Root CA
         Validity
-            Not Before: Jan 25 11:32:03 2015 GMT
-            Not After : Jan 25 11:32:03 2016 GMT
+            Not Before: Feb  1 09:26:24 2016 GMT
+            Not After : Jan 29 09:26:24 2026 GMT
         Subject: C=FI, O=w1.fi, CN=server.w1.fi
         Subject Public Key Info:
             Public Key Algorithm: id-ecPublicKey
                 Public-Key: (384 bit)
                 pub: 
-                    04:56:ab:5b:ad:d5:be:9c:b4:e1:41:90:43:a3:50:
-                    b2:f7:56:32:45:3f:5e:60:d2:09:3e:b0:14:cc:06:
-                    88:14:e5:64:4d:ed:0a:1d:fe:37:de:9b:99:38:3b:
-                    b1:4a:61:93:40:6a:b0:c5:32:1d:b2:0c:c5:d9:bd:
-                    1a:28:88:dc:8b:d0:01:f6:c2:4d:2a:cc:de:6e:9f:
-                    4d:89:3a:df:50:ef:a4:d5:61:f9:44:f7:50:b9:0d:
-                    3c:63:80:b3:a0:c4:1c
+                    04:b8:08:23:5f:6a:d1:0e:cc:9b:30:90:b3:25:12:
+                    7f:9b:3c:c5:04:61:01:18:43:06:9d:ba:22:77:84:
+                    91:e4:1f:12:a7:8e:36:a6:be:7f:8e:08:7c:59:c1:
+                    7d:08:d9:c8:b5:f7:2f:9c:c6:00:88:00:a1:d1:23:
+                    60:bf:8a:28:ef:af:5d:99:70:e9:15:13:2b:1f:3c:
+                    e0:e1:1b:31:c3:96:86:32:11:f2:dc:3d:22:7d:85:
+                    39:35:64:8b:f2:45:25
                 ASN1 OID: secp384r1
         X509v3 extensions:
             X509v3 Basic Constraints: critical
                 CA:FALSE
             X509v3 Subject Key Identifier: 
-                19:D7:57:D0:3B:91:84:A4:AF:93:03:32:3C:AB:C4:F9:A7:B0:27:19
+                EA:4A:EB:D2:AD:05:FC:FD:5F:A0:CA:8A:53:3B:4D:ED:F5:6B:EF:75
             X509v3 Authority Key Identifier: 
-                keyid:AE:05:BC:A7:22:7B:C7:D2:F9:FC:20:A6:5C:31:BB:41:4E:8F:6C:BD
+                keyid:B8:97:C9:BE:63:12:AB:F6:A0:8C:B6:5E:FB:97:6E:10:8E:DC:48:F5
 
             X509v3 Subject Alternative Name: critical
                 DNS:server.w1.fi
@@ -35,24 +35,24 @@ Certificate:
             X509v3 Key Usage: 
                 Digital Signature, Key Encipherment
     Signature Algorithm: ecdsa-with-SHA384
-         30:65:02:30:79:68:37:af:eb:46:e8:77:35:13:77:d5:db:eb:
-         f9:75:40:cd:d4:3d:0a:03:ec:67:a0:22:fe:65:f5:d7:ca:53:
-         4a:85:f5:14:4b:41:f9:b9:98:a6:85:8b:ac:e0:c8:6c:02:31:
-         00:83:12:02:be:93:2b:c2:00:74:ec:cb:fc:5a:8c:a6:5e:52:
-         ee:20:76:3d:73:2b:fb:fe:60:4c:52:f3:bc:1e:4c:e8:f9:ea:
-         f6:e2:f6:ca:c6:a8:3b:2d:9a:17:eb:4d:0a
+         30:65:02:30:1f:26:d2:79:e7:54:59:1a:b8:3b:92:26:05:1d:
+         f7:57:43:9d:8e:01:3d:57:ca:54:e1:9b:2e:ec:3a:32:a0:0d:
+         8b:7c:70:c2:27:d2:31:8b:39:5c:64:6d:81:dd:14:56:02:31:
+         00:f1:ac:58:25:9a:9e:cd:1c:fa:76:9d:da:1a:6b:28:b5:43:
+         15:4e:c7:aa:4d:26:4d:44:26:23:86:a8:5f:6e:f5:42:6d:26:
+         37:99:1d:70:b9:8e:96:4d:69:99:a9:6f:c6
 -----BEGIN CERTIFICATE-----
-MIICTTCCAdOgAwIBAgIJAIG5T+kuoIV2MAoGCCqGSM49BAMDMFIxCzAJBgNVBAYT
+MIICTTCCAdOgAwIBAgIJAKG1hnW6pX5xMAoGCCqGSM49BAMDMFIxCzAJBgNVBAYT
 AkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxIDAeBgNVBAMM
-F1N1aXRlIEIgMTkyLWJpdCBSb290IENBMB4XDTE1MDEyNTExMzIwM1oXDTE2MDEy
-NTExMzIwM1owNDELMAkGA1UEBhMCRkkxDjAMBgNVBAoMBXcxLmZpMRUwEwYDVQQD
-DAxzZXJ2ZXIudzEuZmkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARWq1ut1b6ctOFB
-kEOjULL3VjJFP15g0gk+sBTMBogU5WRN7Qod/jfem5k4O7FKYZNAarDFMh2yDMXZ
-vRooiNyL0AH2wk0qzN5un02JOt9Q76TVYflE91C5DTxjgLOgxByjgZIwgY8wDAYD
-VR0TAQH/BAIwADAdBgNVHQ4EFgQUGddX0DuRhKSvkwMyPKvE+aewJxkwHwYDVR0j
-BBgwFoAUrgW8pyJ7x9L5/CCmXDG7QU6PbL0wGgYDVR0RAQH/BBAwDoIMc2VydmVy
+F1N1aXRlIEIgMTkyLWJpdCBSb290IENBMB4XDTE2MDIwMTA5MjYyNFoXDTI2MDEy
+OTA5MjYyNFowNDELMAkGA1UEBhMCRkkxDjAMBgNVBAoMBXcxLmZpMRUwEwYDVQQD
+DAxzZXJ2ZXIudzEuZmkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAS4CCNfatEOzJsw
+kLMlEn+bPMUEYQEYQwaduiJ3hJHkHxKnjjamvn+OCHxZwX0I2ci19y+cxgCIAKHR
+I2C/iijvr12ZcOkVEysfPODhGzHDloYyEfLcPSJ9hTk1ZIvyRSWjgZIwgY8wDAYD
+VR0TAQH/BAIwADAdBgNVHQ4EFgQU6krr0q0F/P1foMqKUztN7fVr73UwHwYDVR0j
+BBgwFoAUuJfJvmMSq/agjLZe+5duEI7cSPUwGgYDVR0RAQH/BBAwDoIMc2VydmVy
 LncxLmZpMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMBMAsGA1UdDwQEAwIFoDAKBggq
-hkjOPQQDAwNoADBlAjB5aDev60bodzUTd9Xb6/l1QM3UPQoD7GegIv5l9dfKU0qF
-9RRLQfm5mKaFi6zgyGwCMQCDEgK+kyvCAHTsy/xajKZeUu4gdj1zK/v+YExS87we
-TOj56vbi9srGqDstmhfrTQo=
+hkjOPQQDAwNoADBlAjAfJtJ551RZGrg7kiYFHfdXQ52OAT1XylThmy7sOjKgDYt8
+cMIn0jGLOVxkbYHdFFYCMQDxrFglmp7NHPp2ndoaayi1QxVOx6pNJk1EJiOGqF9u
+9UJtJjeZHXC5jpZNaZmpb8Y=
 -----END CERTIFICATE-----
index adfa937..035e25c 100644 (file)
@@ -2,8 +2,8 @@
 BgUrgQQAIg==
 -----END EC PARAMETERS-----
 -----BEGIN EC PRIVATE KEY-----
-MIGkAgEBBDB7tpaHBuZZG+MVYjRVpZvZvZxxFOu/reH2Ms3DiBH5DHW7dLP7T4Gs
-X+yw8bQZwCqgBwYFK4EEACKhZANiAATJYVk5woo/LAFd+znRAoMOClGXtfO2yZlp
-3n6jYUsG48W03XOlYd2/aCJVtGp6SwRVxumfYT4TejEj/Ky44vOlmQ9pasNfMYYN
-kpHcAWJ8sV7mP7LM9YVksksfhon91+E=
+MIGkAgEBBDCkY69v8ff6oUI3wxJYeJdT500cYU9SE7LOLByjFyW5kKh0wfNI+PTj
+QCboPDTNgy6gBwYFK4EEACKhZANiAATuB6iYrTnzUXstmwJhnMBpU3SB6Hwa92ne
+S3VaDG2HGjdfBCV5JUHXt4o4JTtknjum/cKR/99xQ6pvBemWQjEcyeAyK18zIQrP
+Kce5MCGEcJ8c5GwKVwVYlBPzr85IcBg=
 -----END EC PRIVATE KEY-----
index ef86cd1..03253b7 100644 (file)
@@ -1,32 +1,32 @@
 Certificate:
     Data:
         Version: 3 (0x2)
-        Serial Number: 9347590364512421239 (0x81b94fe92ea08577)
+        Serial Number: 11652367451091730034 (0xa1b58675baa57e72)
     Signature Algorithm: ecdsa-with-SHA384
         Issuer: C=FI, L=Helsinki, O=w1.fi, CN=Suite B 192-bit Root CA
         Validity
-            Not Before: Jan 25 11:32:03 2015 GMT
-            Not After : Jan 25 11:32:03 2016 GMT
+            Not Before: Feb  1 09:26:24 2016 GMT
+            Not After : Jan 29 09:26:24 2026 GMT
         Subject: C=FI, O=w1.fi, CN=user
         Subject Public Key Info:
             Public Key Algorithm: id-ecPublicKey
                 Public-Key: (384 bit)
                 pub: 
-                    04:c9:61:59:39:c2:8a:3f:2c:01:5d:fb:39:d1:02:
-                    83:0e:0a:51:97:b5:f3:b6:c9:99:69:de:7e:a3:61:
-                    4b:06:e3:c5:b4:dd:73:a5:61:dd:bf:68:22:55:b4:
-                    6a:7a:4b:04:55:c6:e9:9f:61:3e:13:7a:31:23:fc:
-                    ac:b8:e2:f3:a5:99:0f:69:6a:c3:5f:31:86:0d:92:
-                    91:dc:01:62:7c:b1:5e:e6:3f:b2:cc:f5:85:64:b2:
-                    4b:1f:86:89:fd:d7:e1
+                    04:ee:07:a8:98:ad:39:f3:51:7b:2d:9b:02:61:9c:
+                    c0:69:53:74:81:e8:7c:1a:f7:69:de:4b:75:5a:0c:
+                    6d:87:1a:37:5f:04:25:79:25:41:d7:b7:8a:38:25:
+                    3b:64:9e:3b:a6:fd:c2:91:ff:df:71:43:aa:6f:05:
+                    e9:96:42:31:1c:c9:e0:32:2b:5f:33:21:0a:cf:29:
+                    c7:b9:30:21:84:70:9f:1c:e4:6c:0a:57:05:58:94:
+                    13:f3:af:ce:48:70:18
                 ASN1 OID: secp384r1
         X509v3 extensions:
             X509v3 Basic Constraints: 
                 CA:FALSE
             X509v3 Subject Key Identifier: 
-                75:EA:7B:CE:8A:99:D2:E7:77:B4:3B:80:68:59:E9:B6:88:B2:FA:F6
+                63:19:63:3E:D9:CB:7F:DC:C9:E0:DD:4D:75:A4:34:63:18:16:C3:EF
             X509v3 Authority Key Identifier: 
-                keyid:AE:05:BC:A7:22:7B:C7:D2:F9:FC:20:A6:5C:31:BB:41:4E:8F:6C:BD
+                keyid:B8:97:C9:BE:63:12:AB:F6:A0:8C:B6:5E:FB:97:6E:10:8E:DC:48:F5
 
             X509v3 Subject Alternative Name: 
                 email:user@w1.fi
@@ -35,23 +35,23 @@ Certificate:
             X509v3 Key Usage: 
                 Digital Signature, Key Encipherment
     Signature Algorithm: ecdsa-with-SHA384
-         30:65:02:31:00:c2:b7:35:4e:5e:d1:da:7f:35:a0:ac:54:92:
-         18:08:0d:9c:86:e9:4e:cf:3a:09:48:23:eb:4d:56:77:e5:d0:
-         e7:b0:55:b3:0e:91:2d:f8:3e:1c:4e:0d:b7:32:dc:11:1b:02:
-         30:49:c2:6b:63:39:3c:4b:d9:e9:8d:b9:ce:6e:8e:9f:88:43:
-         03:e0:5f:7e:75:44:12:66:f8:c6:ae:8e:f1:da:10:02:36:8c:
-         7b:a2:89:a0:05:3b:c6:39:d6:e1:7a:b7:85
+         30:66:02:31:00:91:55:b8:e4:26:b6:19:10:b3:f5:47:fb:a0:
+         dc:6a:a1:1b:c6:53:28:be:bd:9e:94:48:34:45:cc:87:41:64:
+         14:2d:d0:bb:dd:75:0a:c3:47:3a:05:7f:35:5c:1c:be:51:02:
+         31:00:ce:4e:8d:cb:05:73:0d:f5:03:74:c5:b1:11:14:a8:0b:
+         e7:d8:26:36:bc:3b:90:60:5a:0e:bf:06:df:27:a3:59:79:52:
+         7b:8e:7c:06:57:70:46:4c:dd:6f:dc:13:95:94
 -----BEGIN CERTIFICATE-----
-MIICOjCCAcCgAwIBAgIJAIG5T+kuoIV3MAoGCCqGSM49BAMDMFIxCzAJBgNVBAYT
+MIICOzCCAcCgAwIBAgIJAKG1hnW6pX5yMAoGCCqGSM49BAMDMFIxCzAJBgNVBAYT
 AkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxIDAeBgNVBAMM
-F1N1aXRlIEIgMTkyLWJpdCBSb290IENBMB4XDTE1MDEyNTExMzIwM1oXDTE2MDEy
-NTExMzIwM1owLDELMAkGA1UEBhMCRkkxDjAMBgNVBAoMBXcxLmZpMQ0wCwYDVQQD
-DAR1c2VyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEyWFZOcKKPywBXfs50QKDDgpR
-l7XztsmZad5+o2FLBuPFtN1zpWHdv2giVbRqeksEVcbpn2E+E3oxI/ysuOLzpZkP
-aWrDXzGGDZKR3AFifLFe5j+yzPWFZLJLH4aJ/dfho4GHMIGEMAkGA1UdEwQCMAAw
-HQYDVR0OBBYEFHXqe86KmdLnd7Q7gGhZ6baIsvr2MB8GA1UdIwQYMBaAFK4FvKci
-e8fS+fwgplwxu0FOj2y9MBUGA1UdEQQOMAyBCnVzZXJAdzEuZmkwEwYDVR0lBAww
-CgYIKwYBBQUHAwIwCwYDVR0PBAQDAgWgMAoGCCqGSM49BAMDA2gAMGUCMQDCtzVO
-XtHafzWgrFSSGAgNnIbpTs86CUgj601Wd+XQ57BVsw6RLfg+HE4NtzLcERsCMEnC
-a2M5PEvZ6Y25zm6On4hDA+BffnVEEmb4xq6O8doQAjaMe6KJoAU7xjnW4Xq3hQ==
+F1N1aXRlIEIgMTkyLWJpdCBSb290IENBMB4XDTE2MDIwMTA5MjYyNFoXDTI2MDEy
+OTA5MjYyNFowLDELMAkGA1UEBhMCRkkxDjAMBgNVBAoMBXcxLmZpMQ0wCwYDVQQD
+DAR1c2VyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE7geomK0581F7LZsCYZzAaVN0
+geh8Gvdp3kt1Wgxthxo3XwQleSVB17eKOCU7ZJ47pv3Ckf/fcUOqbwXplkIxHMng
+MitfMyEKzynHuTAhhHCfHORsClcFWJQT86/OSHAYo4GHMIGEMAkGA1UdEwQCMAAw
+HQYDVR0OBBYEFGMZYz7Zy3/cyeDdTXWkNGMYFsPvMB8GA1UdIwQYMBaAFLiXyb5j
+Eqv2oIy2XvuXbhCO3Ej1MBUGA1UdEQQOMAyBCnVzZXJAdzEuZmkwEwYDVR0lBAww
+CgYIKwYBBQUHAwIwCwYDVR0PBAQDAgWgMAoGCCqGSM49BAMDA2kAMGYCMQCRVbjk
+JrYZELP1R/ug3GqhG8ZTKL69npRINEXMh0FkFC3Qu911CsNHOgV/NVwcvlECMQDO
+To3LBXMN9QN0xbERFKgL59gmNrw7kGBaDr8G3yejWXlSe458BldwRkzdb9wTlZQ=
 -----END CERTIFICATE-----
index ecd06d7..1c494f7 100644 (file)
@@ -8,6 +8,9 @@
 # IMSI Ki OPc AMF SQN
 232010000000000 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000
 
+# Modified version of the previous to allow testing with replaced SIM.
+232010000000009 a0dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000
+
 # These values are from Test Set 19 which has the AMF separation bit set to 1
 # and as such, is suitable for EAP-AKA' test.
 555444333222111 5122250214c33e723a5dd523fc145fc0 981d464c7c52eb6e5036234984ad0bcf c3ab 16f3b3f70fc1
index 95b052e..d530d25 100644 (file)
@@ -4,5 +4,5 @@ V       140102000000Z           D8D3E3A6CBE3CCCA        unknown /C=FI/O=w1.fi/CN=server4.w1.fi
 V      150215083008Z           D8D3E3A6CBE3CCCB        unknown /C=FI/O=w1.fi/CN=server5.w1.fi
 V      150228224144Z           D8D3E3A6CBE3CCCC        unknown /C=FI/O=w1.fi/CN=server6.w1.fi
 V      160111185024Z           D8D3E3A6CBE3CCCD        unknown /C=FI/O=w1.fi/CN=ocsp.w1.fi
-R      150929211122Z   160111185024Z   D8D3E3A6CBE3CCD0        unknown /C=FI/O=w1.fi/CN=server.w1.fi
+R      150929211122Z   160111185024Z   D8D3E3A6CBE3CCE2        unknown /C=FI/O=w1.fi/CN=server.w1.fi
 R      150929211300Z   160111185024Z   D8D3E3A6CBE3CCD1        unknown /C=FI/O=w1.fi/CN=Test User
index 52c8e0c..06a2bf4 100644 (file)
@@ -4,5 +4,5 @@ V       140102000000Z           D8D3E3A6CBE3CCCA        unknown /C=FI/O=w1.fi/CN=server4.w1.fi
 V      150215083008Z           D8D3E3A6CBE3CCCB        unknown /C=FI/O=w1.fi/CN=server5.w1.fi
 V      150228224144Z           D8D3E3A6CBE3CCCC        unknown /C=FI/O=w1.fi/CN=server6.w1.fi
 V      160111185024Z           D8D3E3A6CBE3CCCD        unknown /C=FI/O=w1.fi/CN=ocsp.w1.fi
-V      150929211122Z           D8D3E3A6CBE3CCD0        unknown /C=FI/O=w1.fi/CN=server.w1.fi
+V      170930181357Z           D8D3E3A6CBE3CCE9        unknown /C=FI/O=w1.fi/CN=server.w1.fi
 V      150929211300Z           D8D3E3A6CBE3CCD1        unknown /C=FI/O=w1.fi/CN=Test User
index 20999b9..974ed1e 100644 (file)
Binary files a/libeap/tests/hwsim/auth_serv/ocsp-req.der and b/libeap/tests/hwsim/auth_serv/ocsp-req.der differ
index bbde1e8..240cec1 100644 (file)
@@ -1,12 +1,12 @@
 Certificate:
     Data:
         Version: 3 (0x2)
-        Serial Number: 15624081837803162829 (0xd8d3e3a6cbe3cccd)
+        Serial Number: 15624081837803162831 (0xd8d3e3a6cbe3cccf)
     Signature Algorithm: sha256WithRSAEncryption
         Issuer: C=FI, O=w1.fi, CN=Root CA
         Validity
-            Not Before: Jan 11 18:50:24 2015 GMT
-            Not After : Jan 11 18:50:24 2016 GMT
+            Not Before: Jan 12 22:37:50 2016 GMT
+            Not After : Jan 11 22:37:50 2021 GMT
         Subject: C=FI, O=w1.fi, CN=ocsp.w1.fi
         Subject Public Key Info:
             Public Key Algorithm: rsaEncryption
@@ -30,25 +30,25 @@ Certificate:
             X509v3 Extended Key Usage: 
                 OCSP Signing
     Signature Algorithm: sha256WithRSAEncryption
-         41:42:b6:70:4a:70:1f:ad:d9:25:f7:02:94:bd:91:b7:69:ad:
-         31:59:c6:2a:4e:5e:4a:ed:5d:c1:24:09:98:94:15:42:86:2c:
-         b2:9d:62:7a:e0:ec:60:39:47:93:c9:c7:61:01:b5:2c:00:53:
-         86:6e:66:99:ee:b3:57:5d:fb:83:6b:d3:77:26:0c:c7:2d:16:
-         ea:84:69:59:b7:a8:de:35:61:0b:7a:f3:62:1e:1a:94:91:c4:
-         bd:85:4a:63:10:09:11:88:75:c9:f5:57:84:9a:ef:d1:78:29:
-         5e:76:fc:33:76:84:b2:b5:f6:88:cc:fb:f9:cf:9f:b4:88:29:
-         3c:9d
+         ae:47:b6:23:18:58:9a:d4:26:63:ad:41:c1:5d:3e:34:78:c3:
+         80:29:f6:10:2b:95:3b:dc:ef:f2:b3:b8:4b:23:07:a0:11:e5:
+         5c:b6:4e:7c:6d:d4:62:a2:ae:0f:fd:25:ef:bf:9a:1a:4a:d5:
+         21:c1:9a:0f:57:e6:da:96:b5:e6:d9:02:1e:5b:98:e3:35:8b:
+         b6:0d:24:22:d3:35:a4:20:e7:42:ea:ba:11:72:a0:64:84:73:
+         3c:ce:28:5b:b0:24:53:e9:47:a4:ee:07:85:b2:7a:ec:95:8f:
+         5b:4b:02:b7:c9:3b:2f:e3:30:57:f9:0c:df:f8:a9:7c:4d:b5:
+         0f:01
 -----BEGIN CERTIFICATE-----
-MIICDjCCAXegAwIBAgIJANjT46bL48zNMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
-BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNTAx
-MTExODUwMjRaFw0xNjAxMTExODUwMjRaMDIxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+MIICDjCCAXegAwIBAgIJANjT46bL48zPMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNjAx
+MTIyMjM3NTBaFw0yMTAxMTEyMjM3NTBaMDIxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
 DAV3MS5maTETMBEGA1UEAwwKb2NzcC53MS5maTCBnzANBgkqhkiG9w0BAQEFAAOB
 jQAwgYkCgYEAsl4vHecs9myrsBae+hIvskzII3toCHY4g5f1PwWsXdmBqc51kqG8
 lsbIAO4e1/DaitjnwNdCwyVi58dg+qiCTBvOc5qrjbP+PbZ/Af5ZZEJ1qAQYBy0i
 ZCe58a8BtO2/puqReNGcMPVhN//5G/gWX2t3MvnX450M1cO5QxbwOsMCAwEAAaMv
 MC0wCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwEwYDVR0lBAwwCgYIKwYBBQUHAwkw
-DQYJKoZIhvcNAQELBQADgYEAQUK2cEpwH63ZJfcClL2Rt2mtMVnGKk5eSu1dwSQJ
-mJQVQoYssp1ieuDsYDlHk8nHYQG1LABThm5mme6zV137g2vTdyYMxy0W6oRpWbeo
-3jVhC3rzYh4alJHEvYVKYxAJEYh1yfVXhJrv0XgpXnb8M3aEsrX2iMz7+c+ftIgp
-PJ0=
+DQYJKoZIhvcNAQELBQADgYEArke2IxhYmtQmY61BwV0+NHjDgCn2ECuVO9zv8rO4
+SyMHoBHlXLZOfG3UYqKuD/0l77+aGkrVIcGaD1fm2pa15tkCHluY4zWLtg0kItM1
+pCDnQuq6EXKgZIRzPM4oW7AkU+lHpO4HhbJ67JWPW0sCt8k7L+MwV/kM3/ipfE21
+DwE=
 -----END CERTIFICATE-----
index 33e6753..4b2fd1f 100644 (file)
Binary files a/libeap/tests/hwsim/auth_serv/ocsp-server-cache.der and b/libeap/tests/hwsim/auth_serv/ocsp-server-cache.der differ
index 7ed4014..8c4100c 100644 (file)
@@ -1,12 +1,12 @@
 Certificate:
     Data:
         Version: 3 (0x2)
-        Serial Number: 15624081837803162841 (0xd8d3e3a6cbe3ccd9)
-    Signature Algorithm: sha1WithRSAEncryption
+        Serial Number: 15624081837803162852 (0xd8d3e3a6cbe3cce4)
+    Signature Algorithm: sha256WithRSAEncryption
         Issuer: C=FI, O=w1.fi, CN=Root CA
         Validity
-            Not Before: Feb 19 12:18:22 2015 GMT
-            Not After : Feb 19 12:18:22 2016 GMT
+            Not Before: Feb 19 16:39:44 2016 GMT
+            Not After : Feb 18 16:39:44 2017 GMT
         Subject: C=FI, O=w1.fi, CN=server6.w1.fi
         Subject Public Key Info:
             Public Key Algorithm: rsaEncryption
@@ -35,19 +35,19 @@ Certificate:
 
             X509v3 Extended Key Usage: 
                 TLS Web Client Authentication, TLS Web Server Authentication
-    Signature Algorithm: sha1WithRSAEncryption
-         b8:35:8c:b6:18:ac:e9:f6:cb:2c:df:d8:50:88:48:50:33:50:
-         fa:92:21:94:b7:82:04:0c:c2:c4:16:bc:dd:2f:75:f8:9d:1a:
-         d5:1a:50:dc:7c:97:78:10:25:33:ba:01:6d:47:b8:28:4f:7c:
-         d8:c4:a6:85:0d:f5:84:5f:31:68:1e:44:13:16:fd:ce:8b:98:
-         39:46:03:de:aa:62:16:ee:ae:aa:15:27:4a:f2:9d:9c:1f:5a:
-         61:04:ef:3a:7b:c4:5a:3d:a1:d0:2e:f6:31:ea:92:7e:5f:6b:
-         4d:d3:06:d2:ee:a9:4a:56:68:38:76:25:58:e0:07:fb:d5:d8:
-         fa:b0
+    Signature Algorithm: sha256WithRSAEncryption
+         23:91:f7:da:2a:7d:a4:2c:81:e1:0e:3f:43:fb:cc:67:3d:11:
+         f2:4b:b8:2c:2c:41:d0:90:13:38:6a:5a:12:ea:a7:f1:52:b4:
+         4b:5e:ba:98:b9:b4:36:fc:fe:88:53:2d:4a:f7:08:8f:40:49:
+         aa:90:60:a7:ee:5f:38:af:66:11:f8:31:2b:48:b9:7e:98:1c:
+         ed:38:68:80:b2:18:7e:e9:4f:07:48:7e:a5:ab:fb:e4:46:a6:
+         2c:e7:66:67:93:bd:41:7f:49:d8:c1:e5:1c:08:c5:ed:17:0c:
+         f4:d9:3a:d8:bb:15:4a:44:c6:c7:42:3a:bf:c5:0f:df:8e:a1:
+         05:7f
 -----BEGIN CERTIFICATE-----
-MIIChzCCAfCgAwIBAgIJANjT46bL48zZMA0GCSqGSIb3DQEBBQUAMC8xCzAJBgNV
-BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNTAy
-MTkxMjE4MjJaFw0xNjAyMTkxMjE4MjJaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+MIIChzCCAfCgAwIBAgIJANjT46bL48zkMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNjAy
+MTkxNjM5NDRaFw0xNzAyMTgxNjM5NDRaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
 DAV3MS5maTEWMBQGA1UEAwwNc2VydmVyNi53MS5maTCBnzANBgkqhkiG9w0BAQEF
 AAOBjQAwgYkCgYEAyjAe/RNqAihRmg6pHnJ+51rIywx+ipmBjQWzCbCphueuRPrg
 x+7zGLQxZeMFb2ZO4+SFgZtHf1+1FiuwWZGcxVXT08osgc7wJ6hU3g5P2PARvQsQ
@@ -55,8 +55,8 @@ Vjgm36k6lRWTphbt0h60tcCoYY6uEAT95ibKSg2QS7msyZTysWuXa2Ak6r0CAwEA
 AaOBpDCBoTAJBgNVHRMEAjAAMB0GA1UdDgQWBBTHxu/1YdKgCIFqa0Qs9XL32t5b
 uTAfBgNVHSMEGDAWgBS4kt79ihizMMOfVfMzXbTIKYpBFDA1BggrBgEFBQcBAQQp
 MCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9zZXJ2ZXIudzEuZmk6ODg4OC8wHQYDVR0l
-BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA0GCSqGSIb3DQEBBQUAA4GBALg1jLYY
-rOn2yyzf2FCISFAzUPqSIZS3ggQMwsQWvN0vdfidGtUaUNx8l3gQJTO6AW1HuChP
-fNjEpoUN9YRfMWgeRBMW/c6LmDlGA96qYhburqoVJ0rynZwfWmEE7zp7xFo9odAu
-9jHqkn5fa03TBtLuqUpWaDh2JVjgB/vV2Pqw
+BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4GBACOR99oq
+faQsgeEOP0P7zGc9EfJLuCwsQdCQEzhqWhLqp/FStEteupi5tDb8/ohTLUr3CI9A
+SaqQYKfuXzivZhH4MStIuX6YHO04aICyGH7pTwdIfqWr++RGpiznZmeTvUF/SdjB
+5RwIxe0XDPTZOti7FUpExsdCOr/FD9+OoQV/
 -----END CERTIFICATE-----
index cbb8437..b17f4ff 100644 (file)
@@ -1,12 +1,12 @@
 Certificate:
     Data:
         Version: 3 (0x2)
-        Serial Number: 15624081837803162840 (0xd8d3e3a6cbe3ccd8)
-    Signature Algorithm: sha1WithRSAEncryption
+        Serial Number: 15624081837803162851 (0xd8d3e3a6cbe3cce3)
+    Signature Algorithm: sha256WithRSAEncryption
         Issuer: C=FI, O=w1.fi, CN=Root CA
         Validity
-            Not Before: Feb 19 12:18:03 2015 GMT
-            Not After : Feb 19 12:18:03 2016 GMT
+            Not Before: Feb 19 16:37:01 2016 GMT
+            Not After : Feb 18 16:37:01 2017 GMT
         Subject: C=FI, O=w1.fi, CN=server5.w1.fi
         Subject Public Key Info:
             Public Key Algorithm: rsaEncryption
@@ -35,19 +35,19 @@ Certificate:
 
             X509v3 Extended Key Usage: 
                 TLS Web Client Authentication
-    Signature Algorithm: sha1WithRSAEncryption
-         49:88:dd:04:23:86:22:49:cb:73:57:9a:f7:d8:71:cf:33:62:
-         cc:24:a8:e9:ae:cd:22:91:16:2f:17:86:fc:09:8f:79:c0:93:
-         22:e6:77:25:21:8c:45:38:a3:4d:07:6e:d0:c3:ca:49:8a:3e:
-         86:1f:4e:dd:72:93:f3:47:7d:c3:5b:95:f1:98:50:a5:4e:36:
-         ed:71:94:3a:55:ee:ae:21:e3:27:3d:90:df:4a:be:f5:93:a5:
-         e2:0b:1a:3d:7d:c7:02:98:c1:17:67:9e:9b:a2:1d:65:fc:81:
-         59:72:2b:89:a9:47:31:ad:30:c0:82:39:47:a2:d2:eb:0e:71:
-         d6:3c
+    Signature Algorithm: sha256WithRSAEncryption
+         a0:1e:a7:a7:ce:f9:df:0d:6b:d8:eb:cd:f8:61:69:56:37:0c:
+         15:91:07:a3:e8:ba:c4:9d:bf:10:1f:b2:21:48:59:b7:9e:80:
+         30:80:56:eb:fa:e7:f6:07:89:ab:04:be:9c:b0:96:80:9d:12:
+         90:23:20:b6:f3:3c:3f:08:1c:00:67:2d:9f:b1:bd:72:ce:ed:
+         64:74:d5:cc:86:e5:26:a5:f1:3f:9f:8d:96:b5:a6:6e:94:10:
+         84:cb:8c:45:c3:86:c7:79:48:89:6a:fc:1b:00:23:ac:84:ba:
+         be:13:73:82:73:00:c1:fb:e1:8a:bc:7a:d6:d0:19:3f:43:11:
+         82:26
 -----BEGIN CERTIFICATE-----
-MIICfTCCAeagAwIBAgIJANjT46bL48zYMA0GCSqGSIb3DQEBBQUAMC8xCzAJBgNV
-BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNTAy
-MTkxMjE4MDNaFw0xNjAyMTkxMjE4MDNaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+MIICfTCCAeagAwIBAgIJANjT46bL48zjMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNjAy
+MTkxNjM3MDFaFw0xNzAyMTgxNjM3MDFaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
 DAV3MS5maTEWMBQGA1UEAwwNc2VydmVyNS53MS5maTCBnzANBgkqhkiG9w0BAQEF
 AAOBjQAwgYkCgYEAo5np4uEXYDtwNBp0XEbjuL27qsnz7vsSMKBpw3Q4gDq6I1LH
 wWrPut1B49JpNaSmYGwxH4W9Vmx7CWPNp1FrhECQd36XaHs4tcQVO3Q3NCi6euLX
@@ -55,8 +55,8 @@ hFN4dk0Wt7jfCXLnhyZ0LATKxc4p9bTO2yjrRUdCj+2IWqMjSZt7vDnhAVMCAwEA
 AaOBmjCBlzAJBgNVHRMEAjAAMB0GA1UdDgQWBBQzFp07FxWCKzRuOOjMIr9Jp14q
 KzAfBgNVHSMEGDAWgBS4kt79ihizMMOfVfMzXbTIKYpBFDA1BggrBgEFBQcBAQQp
 MCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9zZXJ2ZXIudzEuZmk6ODg4OC8wEwYDVR0l
-BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADgYEASYjdBCOGIknLc1ea99hx
-zzNizCSo6a7NIpEWLxeG/AmPecCTIuZ3JSGMRTijTQdu0MPKSYo+hh9O3XKT80d9
-w1uV8ZhQpU427XGUOlXuriHjJz2Q30q+9ZOl4gsaPX3HApjBF2eem6IdZfyBWXIr
-ialHMa0wwII5R6LS6w5x1jw=
+BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADgYEAoB6np8753w1r2OvN+GFp
+VjcMFZEHo+i6xJ2/EB+yIUhZt56AMIBW6/rn9geJqwS+nLCWgJ0SkCMgtvM8Pwgc
+AGctn7G9cs7tZHTVzIblJqXxP5+NlrWmbpQQhMuMRcOGx3lIiWr8GwAjrIS6vhNz
+gnMAwfvhirx61tAZP0MRgiY=
 -----END CERTIFICATE-----
index 93d0ec2..3b046b7 100644 (file)
@@ -1,12 +1,12 @@
 Certificate:
     Data:
         Version: 3 (0x2)
-        Serial Number: 15624081837803162838 (0xd8d3e3a6cbe3ccd6)
-    Signature Algorithm: sha1WithRSAEncryption
+        Serial Number: 15624081837803162853 (0xd8d3e3a6cbe3cce5)
+    Signature Algorithm: sha256WithRSAEncryption
         Issuer: C=FI, O=w1.fi, CN=Root CA
         Validity
-            Not Before: Feb 19 12:16:15 2015 GMT
-            Not After : Feb 19 12:16:15 2016 GMT
+            Not Before: Feb 19 16:40:33 2016 GMT
+            Not After : Feb 18 16:40:33 2017 GMT
         Subject: C=FI, O=w1.fi, CN=server3.w1.fi
         Subject Public Key Info:
             Public Key Algorithm: rsaEncryption
@@ -35,19 +35,19 @@ Certificate:
 
             X509v3 Extended Key Usage: 
                 TLS Web Server Authentication
-    Signature Algorithm: sha1WithRSAEncryption
-         91:6b:2b:90:41:55:93:9a:70:d9:56:57:21:56:08:6e:fb:04:
-         e3:40:0d:eb:25:b5:56:21:7d:7b:81:12:97:22:e8:38:95:bc:
-         ba:cb:db:97:a8:6f:dd:da:61:40:dd:fc:0d:82:e6:a0:b5:b0:
-         13:d9:dc:ee:84:d7:27:f2:b3:be:01:31:11:5b:23:29:6d:37:
-         8b:24:3c:d9:6c:21:7c:cc:d6:a2:68:32:39:40:00:5f:04:af:
-         db:32:f7:10:af:e8:53:c4:d3:2f:03:61:cb:fa:67:c5:18:20:
-         63:f9:d9:42:01:34:c9:eb:9d:33:c8:a3:7e:b5:fb:fe:6b:5f:
-         f8:86
+    Signature Algorithm: sha256WithRSAEncryption
+         8d:b6:aa:0a:f5:7f:1c:6b:0b:6b:34:87:35:c4:76:0e:fd:38:
+         a9:80:5c:79:36:fd:f5:71:10:90:ba:db:07:a1:65:f8:8a:04:
+         6d:17:94:53:51:cb:e9:76:c2:d3:c3:60:d9:64:fd:f1:b7:b2:
+         69:4f:aa:18:ef:98:41:58:3d:8d:b5:b5:1b:b0:a1:af:e9:f5:
+         e7:20:8f:44:22:85:00:72:a7:24:78:fd:9a:84:fe:93:87:df:
+         f9:3d:26:76:7b:27:4b:c9:a6:5f:20:10:46:4b:3e:02:b2:39:
+         b0:2f:ef:a9:4b:0c:a5:a0:2f:63:fc:b9:18:44:8f:ff:a2:2b:
+         27:7d
 -----BEGIN CERTIFICATE-----
-MIICfTCCAeagAwIBAgIJANjT46bL48zWMA0GCSqGSIb3DQEBBQUAMC8xCzAJBgNV
-BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNTAy
-MTkxMjE2MTVaFw0xNjAyMTkxMjE2MTVaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+MIICfTCCAeagAwIBAgIJANjT46bL48zlMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNjAy
+MTkxNjQwMzNaFw0xNzAyMTgxNjQwMzNaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
 DAV3MS5maTEWMBQGA1UEAwwNc2VydmVyMy53MS5maTCBnzANBgkqhkiG9w0BAQEF
 AAOBjQAwgYkCgYEA2/wPoUiHaIbEnnr4GCh3baNYD9u+a9RDQ8S6FzebqP+WonMU
 ExyuGQ+BVDUQZJTjZGW+mwsW0p6SmHeH4pqZ/B1XDIoNTCEvrmfXY2HrkVtYL61n
@@ -55,8 +55,8 @@ ZmXkgwfKajal5iD2XJkn22PlhtgrfB2QRIEiIXcKAwXD62Nhs0wywIeHOkcCAwEA
 AaOBmjCBlzAJBgNVHRMEAjAAMB0GA1UdDgQWBBSOmk9NRq1ZrH9MnL5tW9eZY43H
 cDAfBgNVHSMEGDAWgBS4kt79ihizMMOfVfMzXbTIKYpBFDA1BggrBgEFBQcBAQQp
 MCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9zZXJ2ZXIudzEuZmk6ODg4OC8wEwYDVR0l
-BAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQEFBQADgYEAkWsrkEFVk5pw2VZXIVYI
-bvsE40AN6yW1ViF9e4ESlyLoOJW8usvbl6hv3dphQN38DYLmoLWwE9nc7oTXJ/Kz
-vgExEVsjKW03iyQ82WwhfMzWomgyOUAAXwSv2zL3EK/oU8TTLwNhy/pnxRggY/nZ
-QgE0yeudM8ijfrX7/mtf+IY=
+BAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADgYEAjbaqCvV/HGsLazSHNcR2
+Dv04qYBceTb99XEQkLrbB6Fl+IoEbReUU1HL6XbC08Ng2WT98beyaU+qGO+YQVg9
+jbW1G7Chr+n15yCPRCKFAHKnJHj9moT+k4ff+T0mdnsnS8mmXyAQRks+ArI5sC/v
+qUsMpaAvY/y5GESP/6IrJ30=
 -----END CERTIFICATE-----
index fa3e0ae..b0458b9 100644 (file)
@@ -1,12 +1,12 @@
 Certificate:
     Data:
         Version: 3 (0x2)
-        Serial Number: 15624081837803162832 (0xd8d3e3a6cbe3ccd0)
+        Serial Number: 15624081837803162857 (0xd8d3e3a6cbe3cce9)
     Signature Algorithm: sha256WithRSAEncryption
         Issuer: C=FI, O=w1.fi, CN=Root CA
         Validity
-            Not Before: Sep 29 21:11:22 2014 GMT
-            Not After : Sep 29 21:11:22 2015 GMT
+            Not Before: Sep 30 18:13:57 2016 GMT
+            Not After : Sep 30 18:13:57 2017 GMT
         Subject: C=FI, O=w1.fi, CN=server.w1.fi
         Subject Public Key Info:
             Public Key Algorithm: rsaEncryption
@@ -38,18 +38,18 @@ Certificate:
             X509v3 Extended Key Usage: 
                 TLS Web Server Authentication
     Signature Algorithm: sha256WithRSAEncryption
-         92:b7:19:2f:15:84:00:c6:68:01:ba:96:67:11:df:7d:0c:1e:
-         45:eb:59:e5:64:ad:db:f0:23:ce:22:af:a0:35:a2:6f:99:96:
-         9d:2d:bc:b5:8d:58:36:c7:71:f4:fb:c8:a5:e8:44:45:52:7e:
-         1e:44:dd:99:3b:1c:40:f1:f7:73:ec:f9:b7:fc:06:cc:a9:a5:
-         37:41:d1:20:2b:b5:93:75:26:1b:46:2e:3d:25:a3:5e:e9:7e:
-         73:37:9d:e7:71:6f:bb:21:22:cc:31:3e:a2:3f:18:05:ca:35:
-         d2:98:b8:53:6b:92:ac:73:10:8d:8a:09:a4:e3:46:ad:28:72:
-         ab:51
+         24:da:48:be:a8:ae:6e:25:ed:12:bd:f5:a3:32:1f:40:4c:ab:
+         50:87:23:b1:46:45:b0:e5:9b:02:ad:c9:d3:fb:c0:52:78:b5:
+         91:2a:d4:8f:f8:c8:a4:48:b4:66:f7:2e:f1:cf:8c:3a:7a:54:
+         fc:e2:41:a7:af:e3:d1:66:d6:02:d8:93:de:52:b2:c2:6e:d9:
+         7a:bd:8c:ce:e5:dc:3b:0b:7a:f6:fc:a0:4e:9c:64:84:14:3f:
+         9b:24:fc:d0:8f:9c:78:c8:57:0f:32:dd:ed:97:f1:c1:a2:b3:
+         0a:14:9e:c8:35:68:30:1a:10:22:14:66:4a:6b:a4:47:b4:c6:
+         4f:3b
 -----BEGIN CERTIFICATE-----
-MIIClTCCAf6gAwIBAgIJANjT46bL48zQMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
-BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNDA5
-MjkyMTExMjJaFw0xNTA5MjkyMTExMjJaMDQxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+MIIClTCCAf6gAwIBAgIJANjT46bL48zpMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNjA5
+MzAxODEzNTdaFw0xNzA5MzAxODEzNTdaMDQxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
 DAV3MS5maTEVMBMGA1UEAwwMc2VydmVyLncxLmZpMIGfMA0GCSqGSIb3DQEBAQUA
 A4GNADCBiQKBgQC6oHdVIhSFVWWbZCyt7ZvdZTHJ2mBQzjjWNNzovBueMOcS41Ns
 ye1IA3mBaZjOirh3RzZFz8bg8XsecYlU9wHMIq2gQrGoNZ5gqjqYUdD/H+6+jQpj
@@ -58,7 +58,7 @@ o4GzMIGwMAkGA1UdEwQCMAAwHQYDVR0OBBYEFDFPEFxnn75OiNbcxaueEoiGaQJP
 MB8GA1UdIwQYMBaAFLiS3v2KGLMww59V8zNdtMgpikEUMDUGCCsGAQUFBwEBBCkw
 JzAlBggrBgEFBQcwAYYZaHR0cDovL3NlcnZlci53MS5maTo4ODg4LzAXBgNVHREE
 EDAOggxzZXJ2ZXIudzEuZmkwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcN
-AQELBQADgYEAkrcZLxWEAMZoAbqWZxHffQweRetZ5WSt2/AjziKvoDWib5mWnS28
-tY1YNsdx9PvIpehERVJ+HkTdmTscQPH3c+z5t/wGzKmlN0HRICu1k3UmG0YuPSWj
-Xul+czed53FvuyEizDE+oj8YBco10pi4U2uSrHMQjYoJpONGrShyq1E=
+AQELBQADgYEAJNpIvqiubiXtEr31ozIfQEyrUIcjsUZFsOWbAq3J0/vAUni1kSrU
+j/jIpEi0Zvcu8c+MOnpU/OJBp6/j0WbWAtiT3lKywm7Zer2MzuXcOwt69vygTpxk
+hBQ/myT80I+ceMhXDzLd7ZfxwaKzChSeyDVoMBoQIhRmSmukR7TGTzs=
 -----END CERTIFICATE-----
index 7061fd7..a2f360a 100644 (file)
Binary files a/libeap/tests/hwsim/auth_serv/server.pkcs12 and b/libeap/tests/hwsim/auth_serv/server.pkcs12 differ
index 4bc2e1a..81a0860 100644 (file)
@@ -1,12 +1,12 @@
 Certificate:
     Data:
         Version: 3 (0x2)
-        Serial Number: 15624081837803162833 (0xd8d3e3a6cbe3ccd1)
+        Serial Number: 15624081837803162859 (0xd8d3e3a6cbe3cceb)
     Signature Algorithm: sha256WithRSAEncryption
         Issuer: C=FI, O=w1.fi, CN=Root CA
         Validity
-            Not Before: Sep 29 21:13:00 2014 GMT
-            Not After : Sep 29 21:13:00 2015 GMT
+            Not Before: Sep 30 18:20:27 2016 GMT
+            Not After : Sep 30 18:20:27 2017 GMT
         Subject: C=FI, O=w1.fi, CN=Test User
         Subject Public Key Info:
             Public Key Algorithm: rsaEncryption
@@ -36,18 +36,18 @@ Certificate:
             X509v3 Extended Key Usage: 
                 TLS Web Client Authentication
     Signature Algorithm: sha256WithRSAEncryption
-         76:24:5a:f8:de:ef:8b:65:02:67:ab:8f:3a:42:88:22:35:40:
-         48:df:97:91:9b:5a:d4:60:af:61:ef:53:7a:2c:76:04:5f:80:
-         27:79:7e:1f:0a:ed:ab:71:0c:6e:90:7a:69:04:4e:21:cb:31:
-         47:ee:e9:36:87:a9:f4:a1:dd:e9:8a:fd:41:cc:d2:ae:dd:47:
-         66:d1:71:08:b2:e8:5e:e3:36:9e:98:c8:66:51:5b:41:95:02:
-         29:fd:b6:46:d2:40:ec:0e:46:40:92:b1:b7:e2:28:6e:85:17:
-         1e:8d:52:40:c8:20:ca:9b:ab:f0:10:30:8c:0b:5d:91:91:8c:
-         ff:ca
+         47:2e:3d:23:86:d0:3e:fb:b5:7f:d6:32:6b:12:fb:7c:76:78:
+         ec:82:db:ab:fa:5e:0f:1d:97:36:f9:de:b3:cb:fd:08:9e:d5:
+         cd:3d:97:78:c5:00:ce:78:f1:39:3b:84:c9:d0:e6:17:58:ed:
+         ac:e2:d2:a8:7a:fd:b9:19:a4:1c:57:08:17:8c:7f:70:88:82:
+         d5:89:0f:1e:18:22:6d:62:69:4c:12:92:32:bc:cc:1b:a0:05:
+         bc:af:7f:53:a9:dc:a9:55:48:e0:28:34:3e:60:3f:82:16:ac:
+         70:a1:01:e7:75:cf:a0:72:ad:39:ad:52:65:a8:64:fa:7f:11:
+         f2:f5
 -----BEGIN CERTIFICATE-----
-MIICeTCCAeKgAwIBAgIJANjT46bL48zRMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
-BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNDA5
-MjkyMTEzMDBaFw0xNTA5MjkyMTEzMDBaMDExCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+MIICeTCCAeKgAwIBAgIJANjT46bL48zrMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNjA5
+MzAxODIwMjdaFw0xNzA5MzAxODIwMjdaMDExCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
 DAV3MS5maTESMBAGA1UEAwwJVGVzdCBVc2VyMIGfMA0GCSqGSIb3DQEBAQUAA4GN
 ADCBiQKBgQCmli6bIozflL6LiUn2eHaiYH4UlfOW/qsZJQM0ZHQBPqiffPFHYWBM
 gpIofCugDsuHv1nr1/NhIjsU86sx9lqVH7h6uCw8qWFTeJvoPlDswtZE50PNvD5O
@@ -55,8 +55,8 @@ gpIofCugDsuHv1nr1/NhIjsU86sx9lqVH7h6uCw8qWFTeJvoPlDswtZE50PNvD5O
 MIGXMAkGA1UdEwQCMAAwHQYDVR0OBBYEFIHe3+laABrKZ9YG3WWyTsWaBEN9MB8G
 A1UdIwQYMBaAFLiS3v2KGLMww59V8zNdtMgpikEUMDUGCCsGAQUFBwEBBCkwJzAl
 BggrBgEFBQcwAYYZaHR0cDovL3NlcnZlci53MS5maTo4ODg4LzATBgNVHSUEDDAK
-BggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOBgQB2JFr43u+LZQJnq486QogiNUBI
-35eRm1rUYK9h71N6LHYEX4AneX4fCu2rcQxukHppBE4hyzFH7uk2h6n0od3piv1B
-zNKu3Udm0XEIsuhe4zaemMhmUVtBlQIp/bZG0kDsDkZAkrG34ihuhRcejVJAyCDK
-m6vwEDCMC12RkYz/yg==
+BggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOBgQBHLj0jhtA++7V/1jJrEvt8dnjs
+gtur+l4PHZc2+d6zy/0IntXNPZd4xQDOePE5O4TJ0OYXWO2s4tKoev25GaQcVwgX
+jH9wiILViQ8eGCJtYmlMEpIyvMwboAW8r39TqdypVUjgKDQ+YD+CFqxwoQHndc+g
+cq05rVJlqGT6fxHy9Q==
 -----END CERTIFICATE-----
index 0d50201..a1d6366 100644 (file)
Binary files a/libeap/tests/hwsim/auth_serv/user.pkcs12 and b/libeap/tests/hwsim/auth_serv/user.pkcs12 differ
index eb17d9c..67ef81c 100644 (file)
Binary files a/libeap/tests/hwsim/auth_serv/user2.pkcs12 and b/libeap/tests/hwsim/auth_serv/user2.pkcs12 differ
index 953d7cb..c9ed0b4 100644 (file)
Binary files a/libeap/tests/hwsim/auth_serv/user3.pkcs12 and b/libeap/tests/hwsim/auth_serv/user3.pkcs12 differ
index 085092a..036c16c 100644 (file)
@@ -43,6 +43,7 @@ CONFIG_TLSV11=y
 CONFIG_TLSV12=y
 
 CONFIG_FULL_DYNAMIC_VLAN=y
+CONFIG_VLAN_NETLINK=y
 CONFIG_LIBNL32=y
 CONFIG_LIBNL3_ROUTE=y
 CONFIG_PEERKEY=y
@@ -99,3 +100,7 @@ CONFIG_SUITEB=y
 #LIBS_h += -fsanitize=undefined
 #LIBS_n += -fsanitize=undefined
 #LIBS_c += -fsanitize=undefined
+CONFIG_MBO=y
+
+CONFIG_IAPP=y
+CONFIG_TAXONOMY=y
index 2396b97..a30f8f8 100644 (file)
@@ -32,7 +32,10 @@ Install Ubuntu Server 14.04.1 in the virtual machine
 
 Install the prerequisite packages that may not have been installed by default
 
-sudo apt-get install build-essential git libpcap-dev libsqlite3-dev binutils-dev libnl-3-dev libnl-genl-3-dev libnl-route-3-dev libssl-dev libiberty-dev libdbus-1-dev iw bridge-utils python-pyrad python-crypto
+sudo apt-get install build-essential git libpcap-dev libsqlite3-dev binutils-dev libnl-3-dev libnl-genl-3-dev libnl-route-3-dev libssl-dev libiberty-dev libdbus-1-dev iw bridge-utils python-pyrad python-crypto tshark
+
+optional:
+sudo apt-get install python-netifaces
 
 
 Install a recent kernel wireless components (mac80211_hwsim, mac80211,
index 67b767c..c22c4b6 100644 (file)
@@ -60,6 +60,7 @@ CONFIG_PEERKEY=y
 CONFIG_IEEE80211W=y
 CONFIG_IEEE80211R=y
 CONFIG_IEEE80211N=y
+CONFIG_IEEE80211AC=y
 
 CONFIG_DEBUG_FILE=y
 
@@ -83,6 +84,8 @@ CONFIG_MESH=y
 CONFIG_P2P=y
 CONFIG_WIFI_DISPLAY=y
 
+CONFIG_ACS=y
+
 CONFIG_BGSCAN_SIMPLE=y
 CONFIG_BGSCAN_LEARN=y
 
@@ -142,3 +145,4 @@ CONFIG_SUITEB=y
 ##LIBS += -fno-sanitize-recover
 #LIBS_c += -fsanitize=undefined
 #LIBS_p += -fsanitize=undefined
+CONFIG_MBO=y
index 286fa85..fa60788 100644 (file)
@@ -5,7 +5,6 @@
 # See README for more details.
 
 import logging
-import subprocess
 import os
 import signal
 import time
@@ -256,11 +255,13 @@ class FstDevice:
         function"""
         if self.peer_obj is None:
             raise Exception("Peer wasn't added before starting session")
+        self.dump_monitor()
         grp = ' ' + self.fst_group if self.fst_group != '' else ''
         sid = self.grequest("FST-MANAGER SESSION_ADD" + grp)
         sid = sid.strip()
         if sid.startswith("FAIL"):
             raise Exception("Cannot add FST session with groupid ==" + grp)
+        self.dump_monitor()
         return sid
 
     def set_session_param(self, params):
@@ -316,6 +317,7 @@ class FstDevice:
         in "self" while others are passed to this function explicitly. If
         old_iface is None, current iface is used; if old_iface is an empty
         string."""
+        self.dump_monitor()
         oldiface = old_iface if old_iface is not None else self.iface
         s = self.set_session_param(sid + ' old_ifname=' + oldiface)
         if not s.startswith("OK"):
@@ -336,6 +338,7 @@ class FstDevice:
             s = self.set_session_param(sid + " llt=" + self.fst_llt)
             if not s.startswith("OK"):
                 raise Exception("Cannot set FST session llt:" + s)
+        self.dump_monitor()
 
     def send_iface_attach_request(self, ifname, group, llt, priority):
         request = "FST-ATTACH " + ifname + ' ' + group
@@ -508,6 +511,7 @@ class FstDevice:
         Returns: REASON_SWITCH - the session has been transferred successfully
         or a REASON_... reported by the reset event."""
         request = "FST-MANAGER SESSION_TRANSFER"
+        self.dump_monitor()
         if sid != '':
             request += ' ' + sid
         s = self.grequest(request)
@@ -527,6 +531,7 @@ class FstDevice:
                 raise Exception("Unrecognized FST event: " % ev)
             if event['new_state'] == 'INITIAL':
                 result = event['reason']
+        self.dump_monitor()
         return result
 
     def wait_for_tear_down(self):
@@ -621,7 +626,10 @@ class FstAP (FstDevice):
         hostapd."""
         if len(self.fst_group) != 0:
             self.remove_all_sessions()
-            self.send_iface_detach_request(self.iface)
+            try:
+                self.send_iface_detach_request(self.iface)
+            except Exception, e:
+                logger.info(str(e))
         self.reg_ctrl.stop()
         del self.global_instance
         self.global_instance = None
@@ -671,6 +679,11 @@ class FstAP (FstDevice):
     def get_ssid(self):
         return self.ssid
 
+    def dump_monitor(self):
+        """Dump control interface monitor events"""
+        if self.instance:
+            self.instance.dump_monitor()
+
 #
 # FstSTA class
 #
@@ -701,9 +714,11 @@ class FstSTA (FstDevice):
         the STA will be removed when the fst wpa_supplicant process is killed by
         fstap.cleanup()."""
         h = self.get_instance()
+        h.dump_monitor()
         if len(self.fst_group) != 0:
             self.remove_all_sessions()
             self.send_iface_detach_request(self.iface)
+            h.dump_monitor()
         h.interface_remove(self.iface)
         h.close_ctrl()
         del h
@@ -748,8 +763,10 @@ class FstSTA (FstDevice):
         no_wait=True. Note, request("SCAN_RESULTS") can be used to get all the
         results at once."""
         h = self.get_instance()
+        h.dump_monitor()
         h.scan(None, freq, no_wait, only_new)
         r = h.get_bss('0')
+        h.dump_monitor()
         return r
 
     def connect(self, ap, **kwargs):
@@ -758,7 +775,9 @@ class FstSTA (FstDevice):
             raise Exception("Bad AP object to connect to")
         h = self.get_instance()
         hap = ap.get_instance()
+        h.dump_monitor()
         h.connect(ap.get_ssid(), **kwargs)
+        h.dump_monitor()
         self.connected = ap
 
     def connect_to_external_ap(self, ap, ssid, check_connection=True, **kwargs):
@@ -766,6 +785,7 @@ class FstSTA (FstDevice):
         if not isinstance(ap, hostapd.Hostapd):
             raise Exception("Bad AP object to connect to")
         h = self.get_instance()
+        h.dump_monitor()
         h.connect(ssid, **kwargs)
         self.connected = ap
         if check_connection:
@@ -773,17 +793,20 @@ class FstSTA (FstDevice):
             if ev is None:
                 self.connected = None
                 raise Exception("No connection event received from %s" % ssid)
+            h.dump_monitor()
 
     def disconnect(self, check_disconnect=True):
         """Disconnects from the AP the station is currently connected to"""
         if self.connected is not None:
             h = self.get_instance()
+            h.dump_monitor()
             h.request("DISCONNECT")
             if check_disconnect:
                 hap = self.connected.get_instance()
                 ev = hap.wait_event([ "AP-STA-DISCONNECTED" ], timeout=10)
                 if ev is None:
                     raise Exception("No disconnection event received from %s" % self.connected.get_ssid())
+                h.dump_monitor()
             self.connected = None
 
 
@@ -792,10 +815,17 @@ class FstSTA (FstDevice):
         to"""
         if self.connected is not None:
             h = self.get_instance()
+            h.dump_monitor()
             h.request("DISCONNECT")
             if check_disconnect:
                 hap = self.connected
                 ev = hap.wait_event([ "AP-STA-DISCONNECTED" ], timeout=10)
                 if ev is None:
                     raise Exception("No disconnection event received from AP")
+                h.dump_monitor()
             self.connected = None
+
+    def dump_monitor(self):
+        """Dump control interface monitor events"""
+        if self.instance:
+            self.instance.dump_monitor()
index 33cfa62..51ad02e 100644 (file)
@@ -10,6 +10,9 @@ import logging
 import binascii
 import struct
 import wpaspy
+import remotehost
+import utils
+import subprocess
 
 logger = logging.getLogger()
 hapd_ctrl = '/var/run/hostapd'
@@ -19,20 +22,50 @@ def mac2tuple(mac):
     return struct.unpack('6B', binascii.unhexlify(mac.replace(':','')))
 
 class HostapdGlobal:
-    def __init__(self):
-        self.ctrl = wpaspy.Ctrl(hapd_global)
-        self.mon = wpaspy.Ctrl(hapd_global)
+    def __init__(self, apdev=None):
+        try:
+            hostname = apdev['hostname']
+            port = apdev['port']
+        except:
+            hostname = None
+            port = 8878
+        self.host = remotehost.Host(hostname)
+        self.hostname = hostname
+        self.port = port
+        if hostname is None:
+            self.ctrl = wpaspy.Ctrl(hapd_global)
+            self.mon = wpaspy.Ctrl(hapd_global)
+            self.dbg = ""
+        else:
+            self.ctrl = wpaspy.Ctrl(hostname, port)
+            self.mon = wpaspy.Ctrl(hostname, port)
+            self.dbg = hostname + "/" + str(port)
         self.mon.attach()
 
-    def request(self, cmd):
-        return self.ctrl.request(cmd)
+    def cmd_execute(self, cmd_array, shell=False):
+        if self.hostname is None:
+            if shell:
+                cmd = ' '.join(cmd_array)
+            else:
+                cmd = cmd_array
+            proc = subprocess.Popen(cmd, stderr=subprocess.STDOUT,
+                                    stdout=subprocess.PIPE, shell=shell)
+            out = proc.communicate()[0]
+            ret = proc.returncode
+            return ret, out
+        else:
+            return self.host.execute(cmd_array)
+
+    def request(self, cmd, timeout=10):
+        logger.debug(self.dbg + ": CTRL(global): " + cmd)
+        return self.ctrl.request(cmd, timeout)
 
     def wait_event(self, events, timeout):
         start = os.times()[4]
         while True:
             while self.mon.pending():
                 ev = self.mon.recv()
-                logger.debug("(global): " + ev)
+                logger.debug(self.dbg + "(global): " + ev)
                 for event in events:
                     if event in ev:
                         return ev
@@ -44,54 +77,107 @@ class HostapdGlobal:
                 break
         return None
 
-    def request(self, cmd):
-        return self.ctrl.request(cmd)
-
     def add(self, ifname, driver=None):
         cmd = "ADD " + ifname + " " + hapd_ctrl
         if driver:
             cmd += " " + driver
-        res = self.ctrl.request(cmd)
+        res = self.request(cmd)
         if not "OK" in res:
             raise Exception("Could not add hostapd interface " + ifname)
 
     def add_iface(self, ifname, confname):
-        res = self.ctrl.request("ADD " + ifname + " config=" + confname)
+        res = self.request("ADD " + ifname + " config=" + confname)
         if not "OK" in res:
             raise Exception("Could not add hostapd interface")
 
     def add_bss(self, phy, confname, ignore_error=False):
-        res = self.ctrl.request("ADD bss_config=" + phy + ":" + confname)
+        res = self.request("ADD bss_config=" + phy + ":" + confname)
         if not "OK" in res:
             if not ignore_error:
                 raise Exception("Could not add hostapd BSS")
 
     def remove(self, ifname):
-        self.ctrl.request("REMOVE " + ifname, timeout=30)
+        self.request("REMOVE " + ifname, timeout=30)
 
     def relog(self):
-        self.ctrl.request("RELOG")
+        self.request("RELOG")
 
     def flush(self):
-        self.ctrl.request("FLUSH")
+        self.request("FLUSH")
 
+    def get_ctrl_iface_port(self, ifname):
+        if self.hostname is None:
+            return None
+
+        res = self.request("INTERFACES ctrl")
+        lines = res.splitlines()
+        found = False
+        for line in lines:
+            words = line.split()
+            if words[0] == ifname:
+                found = True
+                break
+        if not found:
+            raise Exception("Could not find UDP port for " + ifname)
+        res = line.find("ctrl_iface=udp:")
+        if res == -1:
+            raise Exception("Wrong ctrl_interface format")
+        words = line.split(":")
+        return int(words[1])
+
+    def terminate(self):
+        self.mon.detach()
+        self.mon.close()
+        self.mon = None
+        self.ctrl.terminate()
+        self.ctrl = None
 
 class Hostapd:
-    def __init__(self, ifname, bssidx=0):
+    def __init__(self, ifname, bssidx=0, hostname=None, port=8877):
+        self.hostname = hostname
+        self.host = remotehost.Host(hostname, ifname)
         self.ifname = ifname
-        self.ctrl = wpaspy.Ctrl(os.path.join(hapd_ctrl, ifname))
-        self.mon = wpaspy.Ctrl(os.path.join(hapd_ctrl, ifname))
+        if hostname is None:
+            self.ctrl = wpaspy.Ctrl(os.path.join(hapd_ctrl, ifname))
+            self.mon = wpaspy.Ctrl(os.path.join(hapd_ctrl, ifname))
+            self.dbg = ifname
+        else:
+            self.ctrl = wpaspy.Ctrl(hostname, port)
+            self.mon = wpaspy.Ctrl(hostname, port)
+            self.dbg = hostname + "/" + ifname
         self.mon.attach()
         self.bssid = None
         self.bssidx = bssidx
 
+    def cmd_execute(self, cmd_array, shell=False):
+        if self.hostname is None:
+            if shell:
+                cmd = ' '.join(cmd_array)
+            else:
+                cmd = cmd_array
+            proc = subprocess.Popen(cmd, stderr=subprocess.STDOUT,
+                                    stdout=subprocess.PIPE, shell=shell)
+            out = proc.communicate()[0]
+            ret = proc.returncode
+            return ret, out
+        else:
+            return self.host.execute(cmd_array)
+
+    def close_ctrl(self):
+        if self.mon is not None:
+            self.mon.detach()
+            self.mon.close()
+            self.mon = None
+            self.ctrl.close()
+            self.ctrl = None
+
     def own_addr(self):
         if self.bssid is None:
             self.bssid = self.get_status_field('bssid[%d]' % self.bssidx)
         return self.bssid
 
     def request(self, cmd):
-        logger.debug(self.ifname + ": CTRL: " + cmd)
+        logger.debug(self.dbg + ": CTRL: " + cmd)
         return self.ctrl.request(cmd)
 
     def ping(self):
@@ -154,14 +240,14 @@ class Hostapd:
     def dump_monitor(self):
         while self.mon.pending():
             ev = self.mon.recv()
-            logger.debug(self.ifname + ": " + ev)
+            logger.debug(self.dbg + ": " + ev)
 
     def wait_event(self, events, timeout):
         start = os.times()[4]
         while True:
             while self.mon.pending():
                 ev = self.mon.recv()
-                logger.debug(self.ifname + ": " + ev)
+                logger.debug(self.dbg + ": " + ev)
                 for event in events:
                     if event in ev:
                         return ev
@@ -275,12 +361,42 @@ class Hostapd:
                 vals[name_val[0]] = name_val[1]
         return vals
 
-def add_ap(ifname, params, wait_enabled=True, no_enable=False):
-        logger.info("Starting AP " + ifname)
-        hapd_global = HostapdGlobal()
+    def get_pmksa(self, addr):
+        res = self.request("PMKSA")
+        lines = res.splitlines()
+        for l in lines:
+            if addr not in l:
+                continue
+            vals = dict()
+            [index,aa,pmkid,expiration,opportunistic] = l.split(' ')
+            vals['index'] = index
+            vals['pmkid'] = pmkid
+            vals['expiration'] = expiration
+            vals['opportunistic'] = opportunistic
+            return vals
+        return None
+
+def add_ap(apdev, params, wait_enabled=True, no_enable=False, timeout=30):
+        if isinstance(apdev, dict):
+            ifname = apdev['ifname']
+            try:
+                hostname = apdev['hostname']
+                port = apdev['port']
+                logger.info("Starting AP " + hostname + "/" + port + " " + ifname)
+            except:
+                logger.info("Starting AP " + ifname)
+                hostname = None
+                port = 8878
+        else:
+            ifname = apdev
+            logger.info("Starting AP " + ifname + " (old add_ap argument type)")
+            hostname = None
+            port = 8878
+        hapd_global = HostapdGlobal(apdev)
         hapd_global.remove(ifname)
         hapd_global.add(ifname)
-        hapd = Hostapd(ifname)
+        port = hapd_global.get_ctrl_iface_port(ifname)
+        hapd = Hostapd(ifname, hostname=hostname, port=port)
         if not hapd.ping():
             raise Exception("Could not ping hostapd")
         hapd.set_defaults()
@@ -303,34 +419,71 @@ def add_ap(ifname, params, wait_enabled=True, no_enable=False):
             return hapd
         hapd.enable()
         if wait_enabled:
-            ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=30)
+            ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=timeout)
             if ev is None:
                 raise Exception("AP startup timed out")
             if "AP-ENABLED" not in ev:
                 raise Exception("AP startup failed")
         return hapd
 
-def add_bss(phy, ifname, confname, ignore_error=False):
-    logger.info("Starting BSS phy=" + phy + " ifname=" + ifname)
-    hapd_global = HostapdGlobal()
+def add_bss(apdev, ifname, confname, ignore_error=False):
+    phy = utils.get_phy(apdev)
+    try:
+        hostname = apdev['hostname']
+        port = apdev['port']
+        logger.info("Starting BSS " + hostname + "/" + port + " phy=" + phy + " ifname=" + ifname)
+    except:
+        logger.info("Starting BSS phy=" + phy + " ifname=" + ifname)
+        hostname = None
+        port = 8878
+    hapd_global = HostapdGlobal(apdev)
     hapd_global.add_bss(phy, confname, ignore_error)
-    hapd = Hostapd(ifname)
+    port = hapd_global.get_ctrl_iface_port(ifname)
+    hapd = Hostapd(ifname, hostname=hostname, port=port)
     if not hapd.ping():
         raise Exception("Could not ping hostapd")
-
-def add_iface(ifname, confname):
-    logger.info("Starting interface " + ifname)
-    hapd_global = HostapdGlobal()
+    return hapd
+
+def add_iface(apdev, confname):
+    ifname = apdev['ifname']
+    try:
+        hostname = apdev['hostname']
+        port = apdev['port']
+        logger.info("Starting interface " + hostname + "/" + port + " " + ifname)
+    except:
+        logger.info("Starting interface " + ifname)
+        hostname = None
+        port = 8878
+    hapd_global = HostapdGlobal(apdev)
     hapd_global.add_iface(ifname, confname)
-    hapd = Hostapd(ifname)
+    port = hapd_global.get_ctrl_iface_port(ifname)
+    hapd = Hostapd(ifname, hostname=hostname, port=port)
     if not hapd.ping():
         raise Exception("Could not ping hostapd")
-
-def remove_bss(ifname):
-    logger.info("Removing BSS " + ifname)
-    hapd_global = HostapdGlobal()
+    return hapd
+
+def remove_bss(apdev, ifname=None):
+    if ifname == None:
+        ifname = apdev['ifname']
+    try:
+        hostname = apdev['hostname']
+        port = apdev['port']
+        logger.info("Removing BSS " + hostname + "/" + port + " " + ifname)
+    except:
+        logger.info("Removing BSS " + ifname)
+    hapd_global = HostapdGlobal(apdev)
     hapd_global.remove(ifname)
 
+def terminate(apdev):
+    try:
+        hostname = apdev['hostname']
+        port = apdev['port']
+        logger.info("Terminating hostapd " + hostname + "/" + port)
+    except:
+        logger.info("Terminating hostapd")
+    hapd_global = HostapdGlobal(apdev)
+    hapd_global.terminate()
+
 def wpa2_params(ssid=None, passphrase=None):
     params = { "wpa": "2",
                "wpa_key_mgmt": "WPA-PSK",
@@ -388,3 +541,56 @@ def wpa2_eap_params(ssid=None):
     if ssid:
         params["ssid"] = ssid
     return params
+
+def b_only_params(channel="1", ssid=None, country=None):
+    params = { "hw_mode" : "b",
+               "channel" : channel }
+    if ssid:
+        params["ssid"] = ssid
+    if country:
+        params["country_code"] = country
+    return params
+
+def g_only_params(channel="1", ssid=None, country=None):
+    params = { "hw_mode" : "g",
+               "channel" : channel }
+    if ssid:
+        params["ssid"] = ssid
+    if country:
+        params["country_code"] = country
+    return params
+
+def a_only_params(channel="36", ssid=None, country=None):
+    params = { "hw_mode" : "a",
+               "channel" : channel }
+    if ssid:
+        params["ssid"] = ssid
+    if country:
+        params["country_code"] = country
+    return params
+
+def ht20_params(channel="1", ssid=None, country=None):
+    params = { "ieee80211n" : "1",
+               "channel" : channel,
+               "hw_mode" : "g" }
+    if int(channel) > 14:
+        params["hw_mode"] = "a"
+    if ssid:
+        params["ssid"] = ssid
+    if country:
+        params["country_code"] = country
+    return params
+
+def ht40_plus_params(channel="1", ssid=None, country=None):
+    params = ht20_params(channel, ssid, country)
+    params['ht_capab'] = "[HT40+]"
+    return params
+
+def ht40_minus_params(channel="1", ssid=None, country=None):
+    params = ht20_params(channel, ssid, country)
+    params['ht_capab'] = "[HT40-]"
+    return params
+
+def cmd_execute(apdev, cmd, shell=False):
+    hapd_global = HostapdGlobal(apdev)
+    return hapd_global.cmd_execute(cmd, shell=shell)
index 85f54a2..06df859 100644 (file)
@@ -5,7 +5,6 @@
 # See README for more details.
 
 import os
-import subprocess
 import time
 import logging
 logger = logging.getLogger()
@@ -25,6 +24,11 @@ def run_connectivity_test(dev1, dev2, tos, dev1group=False, dev2group=False,
     dev1.dump_monitor()
     dev2.dump_monitor()
 
+    if dev1.hostname is None and dev2.hostname is None:
+        broadcast_retry_c = 1
+    else:
+        broadcast_retry_c = 10
+
     try:
         if config:
             cmd = "DATA_TEST_CONFIG 1"
@@ -62,18 +66,25 @@ def run_connectivity_test(dev1, dev2, tos, dev1group=False, dev2group=False,
             raise Exception("Unexpected dev1->dev2 unicast data result")
 
         cmd = "DATA_TEST_TX ff:ff:ff:ff:ff:ff {} {}".format(addr1, tos)
-        if dev1group:
-            dev1.group_request(cmd)
-        else:
-            dev1.request(cmd)
-        if dev2group:
-            ev = dev2.wait_group_event(["DATA-TEST-RX"], timeout=timeout)
-        else:
-            ev = dev2.wait_event(["DATA-TEST-RX"], timeout=timeout)
-        if ev is None:
-            raise Exception("dev1->dev2 broadcast data delivery failed")
-        if "DATA-TEST-RX ff:ff:ff:ff:ff:ff {}".format(addr1) not in ev:
-            raise Exception("Unexpected dev1->dev2 broadcast data result")
+        for i in xrange(broadcast_retry_c):
+            try:
+                if dev1group:
+                    dev1.group_request(cmd)
+                else:
+                    dev1.request(cmd)
+                if dev2group:
+                    ev = dev2.wait_group_event(["DATA-TEST-RX"],
+                                               timeout=timeout)
+                else:
+                    ev = dev2.wait_event(["DATA-TEST-RX"], timeout=timeout)
+                if ev is None:
+                    raise Exception("dev1->dev2 broadcast data delivery failed")
+                if "DATA-TEST-RX ff:ff:ff:ff:ff:ff {}".format(addr1) not in ev:
+                    raise Exception("Unexpected dev1->dev2 broadcast data result")
+                break
+            except Exception as e:
+                if i == broadcast_retry_c - 1:
+                    raise
 
         cmd = "DATA_TEST_TX {} {} {}".format(addr1, addr2, tos)
         if dev2group:
@@ -90,18 +101,25 @@ def run_connectivity_test(dev1, dev2, tos, dev1group=False, dev2group=False,
             raise Exception("Unexpected dev2->dev1 unicast data result")
 
         cmd = "DATA_TEST_TX ff:ff:ff:ff:ff:ff {} {}".format(addr2, tos)
-        if dev2group:
-            dev2.group_request(cmd)
-        else:
-            dev2.request(cmd)
-        if dev1group:
-            ev = dev1.wait_group_event(["DATA-TEST-RX"], timeout=timeout)
-        else:
-            ev = dev1.wait_event(["DATA-TEST-RX"], timeout=timeout)
-        if ev is None:
-            raise Exception("dev2->dev1 broadcast data delivery failed")
-        if "DATA-TEST-RX ff:ff:ff:ff:ff:ff {}".format(addr2) not in ev:
-            raise Exception("Unexpected dev2->dev1 broadcast data result")
+        for i in xrange(broadcast_retry_c):
+            try:
+                if dev2group:
+                    dev2.group_request(cmd)
+                else:
+                    dev2.request(cmd)
+                if dev1group:
+                    ev = dev1.wait_group_event(["DATA-TEST-RX"],
+                                               timeout=timeout)
+                else:
+                    ev = dev1.wait_event(["DATA-TEST-RX"], timeout=timeout)
+                if ev is None:
+                    raise Exception("dev2->dev1 broadcast data delivery failed")
+                if "DATA-TEST-RX ff:ff:ff:ff:ff:ff {}".format(addr2) not in ev:
+                    raise Exception("Unexpected dev2->dev1 broadcast data result")
+                break
+            except Exception as e:
+                if i == broadcast_retry_c - 1:
+                    raise
     finally:
         if config:
             if dev1group:
@@ -155,6 +173,8 @@ def test_connectivity_sta(dev1, dev2, dscp=None, tos=None):
 
 def set_powersave(dev, val):
     phy = dev.get_driver_status_field("phyname")
-    psf = open('/sys/kernel/debug/ieee80211/%s/hwsim/ps' % phy, 'w')
-    psf.write('%d\n' % val)
-    psf.close()
+    fname = '/sys/kernel/debug/ieee80211/%s/hwsim/ps' % phy
+    data = '%d' % val
+    (res, data) = dev.cmd_execute(["echo", data, ">", fname], shell=True)
+    if res != 0:
+        raise Exception("Failed to set power save for device")
index 440c820..80870d9 100644 (file)
@@ -346,7 +346,7 @@ def parse_nl80211_attrs(msg):
         alen,attr = struct.unpack("@HH", msg[0:4])
         if alen < 4:
             raise Exception("Too short nl80211 attribute")
-        alen -= 4;
+        alen -= 4
         msg = msg[4:]
         if alen > len(msg):
             raise Exception("nl80211 attribute underflow")
index 13e360b..499263f 100755 (executable)
@@ -252,13 +252,13 @@ def main():
 
     # read the modules from the modules file
     if args.mfile:
-       args.testmodules = []
-       with open(args.mfile) as f:
-           for line in f.readlines():
-               line = line.strip()
-               if not line or line.startswith('#'):
-                   continue
-               args.testmodules.append(line)
+        args.testmodules = []
+        with open(args.mfile) as f:
+            for line in f.readlines():
+                line = line.strip()
+                if not line or line.startswith('#'):
+                    continue
+                    args.testmodules.append(line)
 
     tests_to_run = []
     if args.tests:
@@ -400,6 +400,7 @@ def main():
             t = tests_to_run.pop(0)
 
         name = t.__name__.replace('test_', '', 1)
+        open('/dev/kmsg', 'w').write('running hwsim test case %s\n' % name)
         if log_handler:
             log_handler.stream.close()
             logger.removeHandler(log_handler)
@@ -452,8 +453,15 @@ def main():
             except HwsimSkip, e:
                 logger.info("Skip test case: %s" % e)
                 result = "SKIP"
+            except NameError, e:
+                import traceback
+                logger.info(e)
+                traceback.print_exc()
+                result = "FAIL"
             except Exception, e:
+                import traceback
                 logger.info(e)
+                traceback.print_exc()
                 if args.loglevel == logging.WARNING:
                     print "Exception: " + str(e)
                 result = "FAIL"
@@ -465,6 +473,10 @@ def main():
                     logger.info("Failed to issue TEST-STOP after {} for {}".format(name, d.ifname))
                     logger.info(e)
                     result = "FAIL"
+            if args.no_reset:
+                print "Leaving devices in current state"
+            else:
+                reset_ok = reset_devs(dev, apdev)
             wpas = None
             try:
                 wpas = WpaSupplicant(global_iface="/tmp/wpas-wlan5")
@@ -475,10 +487,6 @@ def main():
                 pass
             if wpas:
                 wpas.close_ctrl()
-            if args.no_reset:
-                print "Leaving devices in current state"
-            else:
-                reset_ok = reset_devs(dev, apdev)
 
             for i in range(0, 3):
                 rename_log(args.logdir, 'log' + str(i), name, dev[i])
@@ -495,6 +503,9 @@ def main():
                 del hapd
                 hapd = None
 
+            # Use None here since this instance of Wlantest() will never be
+            # used for remote host hwsim tests on real hardware.
+            Wlantest.setup(None)
             wt = Wlantest()
             rename_log(args.logdir, 'hwsim0.pcapng', name, wt)
             rename_log(args.logdir, 'hwsim0', name, wt)
index f71f64f..1d2d507 100755 (executable)
@@ -103,7 +103,7 @@ fi
 test -f /proc/modules && sudo modprobe mac80211_hwsim radios=7 channels=$NUM_CH support_p2p_device=0
 
 sudo ifconfig hwsim0 up
-sudo $WLANTEST -i hwsim0 -n $LOGDIR/hwsim0.pcapng -c -dt -L $LOGDIR/hwsim0 &
+sudo $WLANTEST -i hwsim0 -n $LOGDIR/hwsim0.pcapng -c -dtN -L $LOGDIR/hwsim0 &
 for i in 0 1 2; do
     DBUSARG=""
     if [ $i = "0" -a -r /var/run/dbus/pid -a -r /var/run/dbus/hwsim-test ]; then
@@ -136,6 +136,19 @@ if [ ! -r $LOGDIR/ocsp-server-cache.der ]; then
     cp $DIR/auth_serv/ocsp-server-cache.der $LOGDIR/ocsp-server-cache.der
 fi
 
+cp $DIR/auth_serv/ocsp-multi-server-cache.der $LOGDIR/ocsp-multi-server-cache.der
+
+openssl ocsp -index $DIR/auth_serv/index.txt \
+    -rsigner $DIR/auth_serv/ocsp-responder.pem \
+    -rkey $DIR/auth_serv/ocsp-responder.key \
+    -resp_key_id \
+    -CA $DIR/auth_serv/ca.pem \
+    -issuer $DIR/auth_serv/ca.pem \
+    -verify_other $DIR/auth_serv/ca.pem -trust_other \
+    -ndays 7 \
+    -reqin $DIR/auth_serv/ocsp-req.der \
+    -respout $LOGDIR/ocsp-server-cache-key-id.der > $LOGDIR/ocsp.log 2>&1
+
 for i in unknown revoked; do
     openssl ocsp -index $DIR/auth_serv/index-$i.txt \
        -rsigner $DIR/auth_serv/ocsp-responder.pem \
@@ -147,6 +160,27 @@ for i in unknown revoked; do
        -reqin $DIR/auth_serv/ocsp-req.der \
        -respout $LOGDIR/ocsp-server-cache-$i.der >> $LOGDIR/ocsp.log 2>&1
 done
+
+openssl ocsp -reqout $LOGDIR/ocsp-req.der -issuer $DIR/auth_serv/ca.pem \
+    -serial 0xD8D3E3A6CBE3CCE9 -no_nonce -sha256 >> $LOGDIR/ocsp.log 2>&1
+for i in "" "-unknown" "-revoked"; do
+    openssl ocsp -index $DIR/auth_serv/index$i.txt \
+       -rsigner $DIR/auth_serv/ca.pem \
+       -rkey $DIR/auth_serv/ca-key.pem \
+       -CA $DIR/auth_serv/ca.pem \
+       -ndays 7 \
+       -reqin $LOGDIR/ocsp-req.der \
+       -resp_no_certs \
+       -respout $LOGDIR/ocsp-resp-ca-signed$i.der >> $LOGDIR/ocsp.log 2>&1
+done
+openssl ocsp -index $DIR/auth_serv/index.txt \
+    -rsigner $DIR/auth_serv/server.pem \
+    -rkey $DIR/auth_serv/server.key \
+    -CA $DIR/auth_serv/ca.pem \
+    -ndays 7 \
+    -reqin $LOGDIR/ocsp-req.der \
+    -respout $LOGDIR/ocsp-resp-server-signed.der >> $LOGDIR/ocsp.log 2>&1
+
 touch $LOGDIR/hostapd.db
 sudo $HAPD_AS -ddKt $LOGDIR/as.conf $LOGDIR/as2.conf > $LOGDIR/auth_serv &
 
index a4a4e30..fbfecb7 100644 (file)
@@ -6,7 +6,6 @@
 
 import logging
 logger = logging.getLogger()
-import subprocess
 import time
 
 import hostapd
@@ -16,19 +15,17 @@ from test_ap_ht import clear_scan_cache
 def force_prev_ap_on_24g(ap):
     # For now, make sure the last operating channel was on 2.4 GHz band to get
     # sufficient survey data from mac80211_hwsim.
-    hostapd.add_ap(ap['ifname'], { "ssid": "open" })
+    hostapd.add_ap(ap, { "ssid": "open" })
     time.sleep(0.1)
-    hapd_global = hostapd.HostapdGlobal()
-    hapd_global.remove(ap['ifname'])
+    hostapd.remove_bss(ap)
 
 def force_prev_ap_on_5g(ap):
     # For now, make sure the last operating channel was on 5 GHz band to get
     # sufficient survey data from mac80211_hwsim.
-    hostapd.add_ap(ap['ifname'], { "ssid": "open", "hw_mode": "a",
-                                   "channel": "36", "country_code": "US" })
+    hostapd.add_ap(ap, { "ssid": "open", "hw_mode": "a",
+                         "channel": "36", "country_code": "US" })
     time.sleep(0.1)
-    hapd_global = hostapd.HostapdGlobal()
-    hapd_global.remove(ap['ifname'])
+    hostapd.remove_bss(ap)
 
 def wait_acs(hapd):
     ev = hapd.wait_event(["ACS-STARTED", "ACS-COMPLETED", "ACS-FAILED",
@@ -64,7 +61,7 @@ def test_ap_acs(dev, apdev):
     force_prev_ap_on_24g(apdev[0])
     params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
     params['channel'] = '0'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
     wait_acs(hapd)
 
     freq = hapd.get_status_field("freq")
@@ -79,7 +76,7 @@ def test_ap_acs_chanlist(dev, apdev):
     params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
     params['channel'] = '0'
     params['chanlist'] = '1 6 11'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
     wait_acs(hapd)
 
     freq = hapd.get_status_field("freq")
@@ -91,12 +88,10 @@ def test_ap_acs_chanlist(dev, apdev):
 def test_ap_multi_bss_acs(dev, apdev):
     """hostapd start with a multi-BSS configuration file using ACS"""
     skip_with_fips(dev[0])
-    ifname = apdev[0]['ifname']
     force_prev_ap_on_24g(apdev[0])
 
     # start the actual test
-    hostapd.add_iface(ifname, 'multi-bss-acs.conf')
-    hapd = hostapd.Hostapd(ifname)
+    hapd = hostapd.add_iface(apdev[0], 'multi-bss-acs.conf')
     hapd.enable()
     wait_acs(hapd)
 
@@ -110,12 +105,12 @@ def test_ap_multi_bss_acs(dev, apdev):
 
 def test_ap_acs_40mhz(dev, apdev):
     """Automatic channel selection for 40 MHz channel"""
-    clear_scan_cache(apdev[0]['ifname'])
+    clear_scan_cache(apdev[0])
     force_prev_ap_on_24g(apdev[0])
     params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
     params['channel'] = '0'
     params['ht_capab'] = '[HT40+]'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
     wait_acs(hapd)
 
     freq = hapd.get_status_field("freq")
@@ -136,7 +131,7 @@ def test_ap_acs_5ghz(dev, apdev):
         params['hw_mode'] = 'a'
         params['channel'] = '0'
         params['country_code'] = 'US'
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
         wait_acs(hapd)
         freq = hapd.get_status_field("freq")
         if int(freq) < 5000:
@@ -148,7 +143,7 @@ def test_ap_acs_5ghz(dev, apdev):
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['iw', 'reg', 'set', '00'])
+        hostapd.cmd_execute(apdev[0], ['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_ap_acs_5ghz_40mhz(dev, apdev):
@@ -161,7 +156,7 @@ def test_ap_acs_5ghz_40mhz(dev, apdev):
         params['channel'] = '0'
         params['ht_capab'] = '[HT40+]'
         params['country_code'] = 'US'
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
         wait_acs(hapd)
         freq = hapd.get_status_field("freq")
         if int(freq) < 5000:
@@ -177,7 +172,7 @@ def test_ap_acs_5ghz_40mhz(dev, apdev):
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['iw', 'reg', 'set', '00'])
+        hostapd.cmd_execute(apdev[0], ['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_ap_acs_vht(dev, apdev):
@@ -192,7 +187,7 @@ def test_ap_acs_vht(dev, apdev):
         params['country_code'] = 'US'
         params['ieee80211ac'] = '1'
         params['vht_oper_chwidth'] = '1'
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
         wait_acs(hapd)
         freq = hapd.get_status_field("freq")
         if int(freq) < 5000:
@@ -208,7 +203,7 @@ def test_ap_acs_vht(dev, apdev):
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['iw', 'reg', 'set', '00'])
+        hostapd.cmd_execute(apdev[0], ['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_ap_acs_bias(dev, apdev):
@@ -217,7 +212,7 @@ def test_ap_acs_bias(dev, apdev):
     params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
     params['channel'] = '0'
     params['acs_chan_bias'] = '1:0.8 3:1.2 6:0.7 11:0.8'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
     wait_acs(hapd)
 
     freq = hapd.get_status_field("freq")
index 9d4e868..86523fd 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import time
 import logging
 logger = logging.getLogger()
@@ -22,16 +23,12 @@ def check_cipher(dev, ap, cipher):
                "wpa": "2",
                "wpa_key_mgmt": "WPA-PSK",
                "rsn_pairwise": cipher }
-    hapd = hostapd.add_ap(ap['ifname'], params)
+    hapd = hostapd.add_ap(ap, params)
     dev.connect("test-wpa2-psk", psk="12345678",
                 pairwise=cipher, group=cipher, scan_freq="2412")
     hwsim_utils.test_connectivity(dev, hapd)
 
 def check_group_mgmt_cipher(dev, ap, cipher):
-    wt = Wlantest()
-    wt.flush()
-    wt.add_passphrase("12345678")
-
     if cipher not in dev.get_capability("group_mgmt"):
         raise HwsimSkip("Cipher %s not supported" % cipher)
     params = { "ssid": "test-wpa2-psk-pmf",
@@ -41,7 +38,13 @@ def check_group_mgmt_cipher(dev, ap, cipher):
                "wpa_key_mgmt": "WPA-PSK-SHA256",
                "rsn_pairwise": "CCMP",
                "group_mgmt_cipher": cipher }
-    hapd = hostapd.add_ap(ap['ifname'], params)
+    hapd = hostapd.add_ap(ap, params)
+
+    Wlantest.setup(hapd)
+    wt = Wlantest()
+    wt.flush()
+    wt.add_passphrase("12345678")
+
     dev.connect("test-wpa2-psk-pmf", psk="12345678", ieee80211w="2",
                 key_mgmt="WPA-PSK-SHA256",
                 pairwise="CCMP", group="CCMP", scan_freq="2412")
@@ -61,16 +64,18 @@ def check_group_mgmt_cipher(dev, ap, cipher):
     if res != group_mgmt:
         raise Exception("Unexpected group mgmt cipher: " + res)
 
+@remote_compatible
 def test_ap_cipher_tkip(dev, apdev):
     """WPA2-PSK/TKIP connection"""
     skip_with_fips(dev[0])
     check_cipher(dev[0], apdev[0], "TKIP")
 
+@remote_compatible
 def test_ap_cipher_tkip_countermeasures_ap(dev, apdev):
     """WPA-PSK/TKIP countermeasures (detected by AP)"""
     skip_with_fips(dev[0])
     testfile = "/sys/kernel/debug/ieee80211/%s/netdev:%s/tkip_mic_test" % (dev[0].get_driver_status_field("phyname"), dev[0].ifname)
-    if not os.path.exists(testfile):
+    if dev[0].cmd_execute([ "ls", testfile ])[0] != 0:
         raise HwsimSkip("tkip_mic_test not supported in mac80211")
 
     params = { "ssid": "tkip-countermeasures",
@@ -78,20 +83,20 @@ def test_ap_cipher_tkip_countermeasures_ap(dev, apdev):
                "wpa": "1",
                "wpa_key_mgmt": "WPA-PSK",
                "wpa_pairwise": "TKIP" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("tkip-countermeasures", psk="12345678",
                    pairwise="TKIP", group="TKIP", scan_freq="2412")
 
     dev[0].dump_monitor()
-    with open(testfile, "w") as f:
-        f.write(apdev[0]['bssid'])
+    dev[0].cmd_execute([ "echo", "-n", apdev[0]['bssid'], ">", testfile ],
+                       shell=True)
     ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
     if ev is not None:
         raise Exception("Unexpected disconnection on first Michael MIC failure")
 
-    with open(testfile, "w") as f:
-        f.write("ff:ff:ff:ff:ff:ff")
+    dev[0].cmd_execute([ "echo", "-n", "ff:ff:ff:ff:ff:ff", ">", testfile ],
+                       shell=True)
     ev = dev[0].wait_disconnected(timeout=10,
                                   error="No disconnection after two Michael MIC failures")
     if "reason=14" not in ev:
@@ -100,6 +105,7 @@ def test_ap_cipher_tkip_countermeasures_ap(dev, apdev):
     if ev is not None:
         raise Exception("Unexpected connection during TKIP countermeasures")
 
+@remote_compatible
 def test_ap_cipher_tkip_countermeasures_sta(dev, apdev):
     """WPA-PSK/TKIP countermeasures (detected by STA)"""
     skip_with_fips(dev[0])
@@ -108,24 +114,24 @@ def test_ap_cipher_tkip_countermeasures_sta(dev, apdev):
                "wpa": "1",
                "wpa_key_mgmt": "WPA-PSK",
                "wpa_pairwise": "TKIP" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     testfile = "/sys/kernel/debug/ieee80211/%s/netdev:%s/tkip_mic_test" % (hapd.get_driver_status_field("phyname"), apdev[0]['ifname'])
-    if not os.path.exists(testfile):
+    if hapd.cmd_execute([ "ls", testfile ])[0] != 0:
         raise HwsimSkip("tkip_mic_test not supported in mac80211")
 
     dev[0].connect("tkip-countermeasures", psk="12345678",
                    pairwise="TKIP", group="TKIP", scan_freq="2412")
 
     dev[0].dump_monitor()
-    with open(testfile, "w") as f:
-        f.write(dev[0].p2p_dev_addr())
+    hapd.cmd_execute([ "echo", "-n", dev[0].own_addr(), ">", testfile ],
+                     shell=True)
     ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
     if ev is not None:
         raise Exception("Unexpected disconnection on first Michael MIC failure")
 
-    with open(testfile, "w") as f:
-        f.write("ff:ff:ff:ff:ff:ff")
+    hapd.cmd_execute([ "echo", "-n", "ff:ff:ff:ff:ff:ff", ">", testfile ],
+                     shell=True)
     ev = dev[0].wait_disconnected(timeout=10,
                                   error="No disconnection after two Michael MIC failures")
     if "reason=14 locally_generated=1" not in ev:
@@ -134,6 +140,7 @@ def test_ap_cipher_tkip_countermeasures_sta(dev, apdev):
     if ev is not None:
         raise Exception("Unexpected connection during TKIP countermeasures")
 
+@remote_compatible
 def test_ap_cipher_ccmp(dev, apdev):
     """WPA2-PSK/CCMP connection"""
     check_cipher(dev[0], apdev[0], "CCMP")
@@ -150,6 +157,7 @@ def test_ap_cipher_gcmp_256(dev, apdev):
     """WPA2-PSK/GCMP-256 connection"""
     check_cipher(dev[0], apdev[0], "GCMP-256")
 
+@remote_compatible
 def test_ap_cipher_mixed_wpa_wpa2(dev, apdev):
     """WPA2-PSK/CCMP/ and WPA-PSK/TKIP mixed configuration"""
     skip_with_fips(dev[0])
@@ -161,7 +169,7 @@ def test_ap_cipher_mixed_wpa_wpa2(dev, apdev):
                "wpa_key_mgmt": "WPA-PSK",
                "rsn_pairwise": "CCMP",
                "wpa_pairwise": "TKIP" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, proto="WPA2",
                    pairwise="CCMP", group="TKIP", scan_freq="2412")
     status = dev[0].get_status()
@@ -192,6 +200,7 @@ def test_ap_cipher_mixed_wpa_wpa2(dev, apdev):
     hwsim_utils.test_connectivity(dev[1], hapd)
     hwsim_utils.test_connectivity(dev[0], dev[1])
 
+@remote_compatible
 def test_ap_cipher_bip(dev, apdev):
     """WPA2-PSK with BIP"""
     check_group_mgmt_cipher(dev[0], apdev[0], "AES-128-CMAC")
index aec70f7..7fb3bf6 100644 (file)
@@ -4,65 +4,65 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import hostapd
 
+@remote_compatible
 def test_ap_config_errors(dev, apdev):
     """Various hostapd configuration errors"""
-    hapd_global = hostapd.HostapdGlobal()
-    ifname = apdev[0]['ifname']
 
     # IEEE 802.11d without country code
     params = { "ssid": "foo", "ieee80211d": "1" }
-    hapd = hostapd.add_ap(ifname, params, no_enable=True)
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
     if "FAIL" not in hapd.request("ENABLE"):
         raise Exception("Unexpected ENABLE success (ieee80211d without country_code)")
-    hapd_global.remove(ifname)
+    hostapd.remove_bss(apdev[0])
 
     # IEEE 802.11h without IEEE 802.11d
     params = { "ssid": "foo", "ieee80211h": "1" }
-    hapd = hostapd.add_ap(ifname, params, no_enable=True)
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
     if "FAIL" not in hapd.request("ENABLE"):
         raise Exception("Unexpected ENABLE success (ieee80211h without ieee80211d")
-    hapd_global.remove(ifname)
+    hostapd.remove_bss(apdev[0])
 
     # Power Constraint without IEEE 802.11d
     params = { "ssid": "foo", "local_pwr_constraint": "1" }
-    hapd = hostapd.add_ap(ifname, params, no_enable=True)
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
     if "FAIL" not in hapd.request("ENABLE"):
         raise Exception("Unexpected ENABLE success (local_pwr_constraint without ieee80211d)")
-    hapd_global.remove(ifname)
+    hostapd.remove_bss(apdev[0])
 
     # Spectrum management without Power Constraint
     params = { "ssid": "foo", "spectrum_mgmt_required": "1" }
-    hapd = hostapd.add_ap(ifname, params, no_enable=True)
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
     if "FAIL" not in hapd.request("ENABLE"):
         raise Exception("Unexpected ENABLE success (spectrum_mgmt_required without local_pwr_constraint)")
-    hapd_global.remove(ifname)
+    hostapd.remove_bss(apdev[0])
 
     # IEEE 802.1X without authentication server
     params = { "ssid": "foo", "ieee8021x": "1" }
-    hapd = hostapd.add_ap(ifname, params, no_enable=True)
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
     if "FAIL" not in hapd.request("ENABLE"):
         raise Exception("Unexpected ENABLE success (ieee8021x)")
-    hapd_global.remove(ifname)
+    hostapd.remove_bss(apdev[0])
 
     # RADIUS-PSK without macaddr_acl=2
     params = hostapd.wpa2_params(ssid="foo", passphrase="12345678")
     params["wpa_psk_radius"] = "1"
-    hapd = hostapd.add_ap(ifname, params, no_enable=True)
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
     if "FAIL" not in hapd.request("ENABLE"):
         raise Exception("Unexpected ENABLE success (wpa_psk_radius)")
-    hapd_global.remove(ifname)
+    hostapd.remove_bss(apdev[0])
 
     # FT without NAS-Identifier
     params = { "wpa": "2",
                "wpa_key_mgmt": "FT-PSK",
                "rsn_pairwise": "CCMP",
                "wpa_passphrase": "12345678" }
-    hapd = hostapd.add_ap(ifname, params, no_enable=True)
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
     if "FAIL" not in hapd.request("ENABLE"):
         raise Exception("Unexpected ENABLE success (FT without nas_identifier)")
-    hapd_global.remove(ifname)
+    hostapd.remove_bss(apdev[0])
 
     # Hotspot 2.0 without WPA2/CCMP
     params = hostapd.wpa2_params(ssid="foo")
@@ -74,7 +74,7 @@ def test_ap_config_errors(dev, apdev):
     params['interworking'] = "1"
     params['hs20'] = "1"
     params['wpa'] = "1"
-    hapd = hostapd.add_ap(ifname, params, no_enable=True)
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
     if "FAIL" not in hapd.request("ENABLE"):
         raise Exception("Unexpected ENABLE success (HS 2.0 without WPA2/CCMP)")
-    hapd_global.remove(ifname)
+    hostapd.remove_bss(apdev[0])
index c88e517..902d428 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import time
 import logging
 logger = logging.getLogger()
@@ -12,11 +13,12 @@ import hwsim_utils
 import hostapd
 from utils import HwsimSkip
 
-def connect(dev, apdev):
+def connect(dev, apdev, **kwargs):
     params = { "ssid": "ap-csa",
                "channel": "1" }
-    ap = hostapd.add_ap(apdev[0]['ifname'], params)
-    dev.connect("ap-csa", key_mgmt="NONE")
+    params.update(kwargs)
+    ap = hostapd.add_ap(apdev[0], params)
+    dev.connect("ap-csa", key_mgmt="NONE", scan_freq="2412")
     return ap
 
 def switch_channel(ap, count, freq):
@@ -26,7 +28,13 @@ def switch_channel(ap, count, freq):
         raise Exception("CSA finished event timed out")
     if "freq=" + str(freq) not in ev:
         raise Exception("Unexpected channel in CSA finished event")
-    time.sleep(0.1)
+
+def wait_channel_switch(dev, freq):
+    ev = dev.wait_event(["CTRL-EVENT-CHANNEL-SWITCH"], timeout=5)
+    if ev is None:
+        raise Exception("Channel switch not reported")
+    if "freq=%d" % freq not in ev:
+        raise Exception("Unexpected frequency: " + ev)
 
 # This function checks whether the provided dev, which may be either
 # WpaSupplicant or Hostapd supports CSA.
@@ -35,6 +43,7 @@ def csa_supported(dev):
     if (int(res['capa.flags'], 0) & 0x80000000) == 0:
         raise HwsimSkip("CSA not supported")
 
+@remote_compatible
 def test_ap_csa_1_switch(dev, apdev):
     """AP Channel Switch, one switch"""
     csa_supported(dev[0])
@@ -42,8 +51,10 @@ def test_ap_csa_1_switch(dev, apdev):
 
     hwsim_utils.test_connectivity(dev[0], ap)
     switch_channel(ap, 10, 2462)
+    wait_channel_switch(dev[0], 2462)
     hwsim_utils.test_connectivity(dev[0], ap)
 
+@remote_compatible
 def test_ap_csa_2_switches(dev, apdev):
     """AP Channel Switch, two switches"""
     csa_supported(dev[0])
@@ -51,10 +62,13 @@ def test_ap_csa_2_switches(dev, apdev):
 
     hwsim_utils.test_connectivity(dev[0], ap)
     switch_channel(ap, 10, 2462)
+    wait_channel_switch(dev[0], 2462)
     hwsim_utils.test_connectivity(dev[0], ap)
     switch_channel(ap, 10, 2412)
+    wait_channel_switch(dev[0], 2412)
     hwsim_utils.test_connectivity(dev[0], ap)
 
+@remote_compatible
 def test_ap_csa_1_switch_count_0(dev, apdev):
     """AP Channel Switch, one switch with count 0"""
     csa_supported(dev[0])
@@ -65,6 +79,7 @@ def test_ap_csa_1_switch_count_0(dev, apdev):
     # this does not result in CSA currently, so do not bother checking
     # connectivity
 
+@remote_compatible
 def test_ap_csa_2_switches_count_0(dev, apdev):
     """AP Channel Switch, two switches with count 0"""
     csa_supported(dev[0])
@@ -78,6 +93,7 @@ def test_ap_csa_2_switches_count_0(dev, apdev):
     # this does not result in CSA currently, so do not bother checking
     # connectivity
 
+@remote_compatible
 def test_ap_csa_1_switch_count_1(dev, apdev):
     """AP Channel Switch, one switch with count 1"""
     csa_supported(dev[0])
@@ -88,6 +104,7 @@ def test_ap_csa_1_switch_count_1(dev, apdev):
     # this does not result in CSA currently, so do not bother checking
     # connectivity
 
+@remote_compatible
 def test_ap_csa_2_switches_count_1(dev, apdev):
     """AP Channel Switch, two switches with count 1"""
     csa_supported(dev[0])
@@ -101,6 +118,7 @@ def test_ap_csa_2_switches_count_1(dev, apdev):
     # this does not result in CSA currently, so do not bother checking
     # connectivity
 
+@remote_compatible
 def test_ap_csa_1_switch_count_2(dev, apdev):
     """AP Channel Switch, one switch with count 2"""
     csa_supported(dev[0])
@@ -108,4 +126,27 @@ def test_ap_csa_1_switch_count_2(dev, apdev):
 
     hwsim_utils.test_connectivity(dev[0], ap)
     switch_channel(ap, 2, 2462)
+    wait_channel_switch(dev[0], 2462)
+    hwsim_utils.test_connectivity(dev[0], ap)
+
+@remote_compatible
+def test_ap_csa_ecsa_only(dev, apdev):
+    """AP Channel Switch, one switch with only ECSA IE"""
+    csa_supported(dev[0])
+    ap = connect(dev[0], apdev, ecsa_ie_only="1")
+
     hwsim_utils.test_connectivity(dev[0], ap)
+    switch_channel(ap, 10, 2462)
+    wait_channel_switch(dev[0], 2462)
+    hwsim_utils.test_connectivity(dev[0], ap)
+
+@remote_compatible
+def test_ap_csa_invalid(dev, apdev):
+    """AP Channel Switch - invalid channel"""
+    csa_supported(dev[0])
+    ap = connect(dev[0], apdev)
+
+    vals = [ 2461, 4900, 4901, 5181, 5746, 5699, 5895, 5899 ]
+    for val in vals:
+        if "FAIL" not in ap.request("CHAN_SWITCH 1 %d" % val):
+            raise Exception("Invalid channel accepted: %d" % val)
index 19eb9c4..33db463 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import time
 import subprocess
 import logging
@@ -12,20 +13,20 @@ import os
 
 import hwsim_utils
 import hostapd
-from utils import alloc_fail
+from utils import alloc_fail, require_under_vm
 from test_ap_acs import force_prev_ap_on_24g
 
+@remote_compatible
 def test_ap_change_ssid(dev, apdev):
     """Dynamic SSID change with hostapd and WPA2-PSK"""
     params = hostapd.wpa2_params(ssid="test-wpa2-psk-start",
                                  passphrase="12345678")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     id = dev[0].connect("test-wpa2-psk-start", psk="12345678",
                         scan_freq="2412")
     dev[0].request("DISCONNECT")
 
     logger.info("Change SSID dynamically")
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
     res = hapd.request("SET ssid test-wpa2-psk-new")
     if "OK" not in res:
         raise Exception("SET command failed")
@@ -90,118 +91,116 @@ def test_ap_bss_add_remove(dev, apdev):
 
 def _test_ap_bss_add_remove(dev, apdev):
     for i in range(3):
+        dev[i].flush_scan_cache()
         dev[i].request("SCAN_INTERVAL 1")
     ifname1 = apdev[0]['ifname']
     ifname2 = apdev[0]['ifname'] + '-2'
     ifname3 = apdev[0]['ifname'] + '-3'
     logger.info("Set up three BSSes one by one")
-    hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
+    hostapd.add_bss(apdev[0], ifname1, 'bss-1.conf')
     multi_check(dev, [ True, False, False ])
-    hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
+    hostapd.add_bss(apdev[0], ifname2, 'bss-2.conf')
     multi_check(dev, [ True, True, False ])
-    hostapd.add_bss('phy3', ifname3, 'bss-3.conf')
+    hostapd.add_bss(apdev[0], ifname3, 'bss-3.conf')
     multi_check(dev, [ True, True, True ])
 
     logger.info("Remove the last BSS and re-add it")
-    hostapd.remove_bss(ifname3)
+    hostapd.remove_bss(apdev[0], ifname3)
     multi_check(dev, [ True, True, False ])
-    hostapd.add_bss('phy3', ifname3, 'bss-3.conf')
+    hostapd.add_bss(apdev[0], ifname3, 'bss-3.conf')
     multi_check(dev, [ True, True, True ])
 
     logger.info("Remove the middle BSS and re-add it")
-    hostapd.remove_bss(ifname2)
+    hostapd.remove_bss(apdev[0], ifname2)
     multi_check(dev, [ True, False, True ])
-    hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
+    hostapd.add_bss(apdev[0], ifname2, 'bss-2.conf')
     multi_check(dev, [ True, True, True ])
 
     logger.info("Remove the first BSS and re-add it and other BSSs")
-    hostapd.remove_bss(ifname1)
+    hostapd.remove_bss(apdev[0], ifname1)
     multi_check(dev, [ False, False, False ])
-    hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
-    hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
-    hostapd.add_bss('phy3', ifname3, 'bss-3.conf')
+    hostapd.add_bss(apdev[0], ifname1, 'bss-1.conf')
+    hostapd.add_bss(apdev[0], ifname2, 'bss-2.conf')
+    hostapd.add_bss(apdev[0], ifname3, 'bss-3.conf')
     multi_check(dev, [ True, True, True ])
 
     logger.info("Remove two BSSes and re-add them")
-    hostapd.remove_bss(ifname2)
+    hostapd.remove_bss(apdev[0], ifname2)
     multi_check(dev, [ True, False, True ])
-    hostapd.remove_bss(ifname3)
+    hostapd.remove_bss(apdev[0], ifname3)
     multi_check(dev, [ True, False, False ])
-    hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
+    hostapd.add_bss(apdev[0], ifname2, 'bss-2.conf')
     multi_check(dev, [ True, True, False ])
-    hostapd.add_bss('phy3', ifname3, 'bss-3.conf')
+    hostapd.add_bss(apdev[0], ifname3, 'bss-3.conf')
     multi_check(dev, [ True, True, True ])
 
     logger.info("Remove three BSSes in and re-add them")
-    hostapd.remove_bss(ifname3)
+    hostapd.remove_bss(apdev[0], ifname3)
     multi_check(dev, [ True, True, False ])
-    hostapd.remove_bss(ifname2)
+    hostapd.remove_bss(apdev[0], ifname2)
     multi_check(dev, [ True, False, False ])
-    hostapd.remove_bss(ifname1)
+    hostapd.remove_bss(apdev[0], ifname1)
     multi_check(dev, [ False, False, False ])
-    hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
+    hostapd.add_bss(apdev[0], ifname1, 'bss-1.conf')
     multi_check(dev, [ True, False, False ])
-    hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
+    hostapd.add_bss(apdev[0], ifname2, 'bss-2.conf')
     multi_check(dev, [ True, True, False ])
-    hostapd.add_bss('phy3', ifname3, 'bss-3.conf')
+    hostapd.add_bss(apdev[0], ifname3, 'bss-3.conf')
     multi_check(dev, [ True, True, True ])
 
     logger.info("Test error handling if a duplicate ifname is tried")
-    hostapd.add_bss('phy3', ifname3, 'bss-3.conf', ignore_error=True)
+    hostapd.add_bss(apdev[0], ifname3, 'bss-3.conf', ignore_error=True)
     multi_check(dev, [ True, True, True ])
 
 def test_ap_bss_add_remove_during_ht_scan(dev, apdev):
     """Dynamic BSS add during HT40 co-ex scan"""
+    for i in range(3):
+        dev[i].flush_scan_cache()
     ifname1 = apdev[0]['ifname']
     ifname2 = apdev[0]['ifname'] + '-2'
-    hostapd.add_bss('phy3', ifname1, 'bss-ht40-1.conf')
-    hostapd.add_bss('phy3', ifname2, 'bss-ht40-2.conf')
+    hostapd.add_bss(apdev[0], ifname1, 'bss-ht40-1.conf')
+    hostapd.add_bss(apdev[0], ifname2, 'bss-ht40-2.conf')
     multi_check(dev, [ True, True ], scan_opt=False)
-    hostapd.remove_bss(ifname2)
-    hostapd.remove_bss(ifname1)
+    hostapd.remove_bss(apdev[0], ifname2)
+    hostapd.remove_bss(apdev[0], ifname1)
 
-    hostapd.add_bss('phy3', ifname1, 'bss-ht40-1.conf')
-    hostapd.add_bss('phy3', ifname2, 'bss-ht40-2.conf')
-    hostapd.remove_bss(ifname2)
+    hostapd.add_bss(apdev[0], ifname1, 'bss-ht40-1.conf')
+    hostapd.add_bss(apdev[0], ifname2, 'bss-ht40-2.conf')
+    hostapd.remove_bss(apdev[0], ifname2)
     multi_check(dev, [ True, False ], scan_opt=False)
-    hostapd.remove_bss(ifname1)
+    hostapd.remove_bss(apdev[0], ifname1)
 
-    hostapd.add_bss('phy3', ifname1, 'bss-ht40-1.conf')
-    hostapd.add_bss('phy3', ifname2, 'bss-ht40-2.conf')
-    hostapd.remove_bss(ifname1)
+    hostapd.add_bss(apdev[0], ifname1, 'bss-ht40-1.conf')
+    hostapd.add_bss(apdev[0], ifname2, 'bss-ht40-2.conf')
+    hostapd.remove_bss(apdev[0], ifname1)
     multi_check(dev, [ False, False ])
 
 def test_ap_multi_bss_config(dev, apdev):
     """hostapd start with a multi-BSS configuration file"""
+    for i in range(3):
+        dev[i].flush_scan_cache()
     ifname1 = apdev[0]['ifname']
     ifname2 = apdev[0]['ifname'] + '-2'
     ifname3 = apdev[0]['ifname'] + '-3'
     logger.info("Set up three BSSes with one configuration file")
-    hostapd.add_iface(ifname1, 'multi-bss.conf')
-    hapd = hostapd.Hostapd(ifname1)
+    hapd = hostapd.add_iface(apdev[0], 'multi-bss.conf')
     hapd.enable()
     multi_check(dev, [ True, True, True ])
-    hostapd.remove_bss(ifname2)
+    hostapd.remove_bss(apdev[0], ifname2)
     multi_check(dev, [ True, False, True ])
-    hostapd.remove_bss(ifname3)
+    hostapd.remove_bss(apdev[0], ifname3)
     multi_check(dev, [ True, False, False ])
-    hostapd.remove_bss(ifname1)
+    hostapd.remove_bss(apdev[0], ifname1)
     multi_check(dev, [ False, False, False ])
 
-    hostapd.add_iface(ifname1, 'multi-bss.conf')
-    hapd = hostapd.Hostapd(ifname1)
+    hapd = hostapd.add_iface(apdev[0], 'multi-bss.conf')
     hapd.enable()
-    hostapd.remove_bss(ifname1)
+    hostapd.remove_bss(apdev[0], ifname1)
     multi_check(dev, [ False, False, False ])
 
-def invalid_ap(hapd_global, ifname):
-    logger.info("Trying to start AP " + ifname + " with invalid configuration")
-    hapd_global.remove(ifname)
-    hapd_global.add(ifname)
-    hapd = hostapd.Hostapd(ifname)
-    if not hapd.ping():
-        raise Exception("Could not ping hostapd")
-    hapd.set_defaults()
+def invalid_ap(ap):
+    logger.info("Trying to start AP " + ap['ifname'] + " with invalid configuration")
+    hapd = hostapd.add_ap(ap, {}, no_enable=True)
     hapd.set("ssid", "invalid-config")
     hapd.set("channel", "12345")
     try:
@@ -213,116 +212,97 @@ def invalid_ap(hapd_global, ifname):
         raise Exception("ENABLE command succeeded unexpectedly")
     return hapd
 
+@remote_compatible
 def test_ap_invalid_config(dev, apdev):
     """Try to start AP with invalid configuration and fix configuration"""
-    hapd_global = hostapd.HostapdGlobal()
-    ifname = apdev[0]['ifname']
-    hapd = invalid_ap(hapd_global, ifname)
+    hapd = invalid_ap(apdev[0])
 
     logger.info("Fix configuration and start AP again")
     hapd.set("channel", "1")
     hapd.enable()
     dev[0].connect("invalid-config", key_mgmt="NONE", scan_freq="2412")
 
+@remote_compatible
 def test_ap_invalid_config2(dev, apdev):
     """Try to start AP with invalid configuration and remove interface"""
-    hapd_global = hostapd.HostapdGlobal()
-    ifname = apdev[0]['ifname']
-    hapd = invalid_ap(hapd_global, ifname)
+    hapd = invalid_ap(apdev[0])
     logger.info("Remove interface with failed configuration")
-    hapd_global.remove(ifname)
+    hostapd.remove_bss(apdev[0])
 
 def test_ap_remove_during_acs(dev, apdev):
     """Remove interface during ACS"""
     force_prev_ap_on_24g(apdev[0])
     params = hostapd.wpa2_params(ssid="test-acs-remove", passphrase="12345678")
     params['channel'] = '0'
-    ifname = apdev[0]['ifname']
-    hapd = hostapd.HostapdGlobal()
-    hostapd.add_ap(ifname, params)
-    hapd.remove(ifname)
+    hostapd.add_ap(apdev[0], params)
+    hostapd.remove_bss(apdev[0])
 
 def test_ap_remove_during_acs2(dev, apdev):
     """Remove BSS during ACS in multi-BSS configuration"""
     force_prev_ap_on_24g(apdev[0])
     ifname = apdev[0]['ifname']
     ifname2 = ifname + "-2"
-    hapd_global = hostapd.HostapdGlobal()
-    hapd_global.add(ifname)
-    hapd = hostapd.Hostapd(ifname)
-    hapd.set_defaults()
+    hapd = hostapd.add_ap(apdev[0], {}, no_enable=True)
     hapd.set("ssid", "test-acs-remove")
     hapd.set("channel", "0")
     hapd.set("bss", ifname2)
     hapd.set("ssid", "test-acs-remove2")
     hapd.enable()
-    hapd_global.remove(ifname)
+    hostapd.remove_bss(apdev[0])
 
 def test_ap_remove_during_acs3(dev, apdev):
     """Remove second BSS during ACS in multi-BSS configuration"""
     force_prev_ap_on_24g(apdev[0])
     ifname = apdev[0]['ifname']
     ifname2 = ifname + "-2"
-    hapd_global = hostapd.HostapdGlobal()
-    hapd_global.add(ifname)
-    hapd = hostapd.Hostapd(ifname)
-    hapd.set_defaults()
+    hapd = hostapd.add_ap(apdev[0], {}, no_enable=True)
     hapd.set("ssid", "test-acs-remove")
     hapd.set("channel", "0")
     hapd.set("bss", ifname2)
     hapd.set("ssid", "test-acs-remove2")
     hapd.enable()
-    hapd_global.remove(ifname2)
+    hostapd.remove_bss(apdev[0], ifname2)
 
+@remote_compatible
 def test_ap_remove_during_ht_coex_scan(dev, apdev):
     """Remove interface during HT co-ex scan"""
     params = hostapd.wpa2_params(ssid="test-ht-remove", passphrase="12345678")
     params['channel'] = '1'
     params['ht_capab'] = "[HT40+]"
     ifname = apdev[0]['ifname']
-    hapd = hostapd.HostapdGlobal()
-    hostapd.add_ap(ifname, params)
-    hapd.remove(ifname)
+    hostapd.add_ap(apdev[0], params)
+    hostapd.remove_bss(apdev[0])
 
 def test_ap_remove_during_ht_coex_scan2(dev, apdev):
     """Remove BSS during HT co-ex scan in multi-BSS configuration"""
     ifname = apdev[0]['ifname']
     ifname2 = ifname + "-2"
-    hapd_global = hostapd.HostapdGlobal()
-    hapd_global.add(ifname)
-    hapd = hostapd.Hostapd(ifname)
-    hapd.set_defaults()
+    hapd = hostapd.add_ap(apdev[0], {}, no_enable=True)
     hapd.set("ssid", "test-ht-remove")
     hapd.set("channel", "1")
     hapd.set("ht_capab", "[HT40+]")
     hapd.set("bss", ifname2)
     hapd.set("ssid", "test-ht-remove2")
     hapd.enable()
-    hapd_global.remove(ifname)
+    hostapd.remove_bss(apdev[0])
 
 def test_ap_remove_during_ht_coex_scan3(dev, apdev):
     """Remove second BSS during HT co-ex scan in multi-BSS configuration"""
     ifname = apdev[0]['ifname']
     ifname2 = ifname + "-2"
-    hapd_global = hostapd.HostapdGlobal()
-    hapd_global.add(ifname)
-    hapd = hostapd.Hostapd(ifname)
-    hapd.set_defaults()
+    hapd = hostapd.add_ap(apdev[0], {}, no_enable=True)
     hapd.set("ssid", "test-ht-remove")
     hapd.set("channel", "1")
     hapd.set("ht_capab", "[HT40+]")
     hapd.set("bss", ifname2)
     hapd.set("ssid", "test-ht-remove2")
     hapd.enable()
-    hapd_global.remove(ifname2)
+    hostapd.remove_bss(apdev[0], ifname2)
 
+@remote_compatible
 def test_ap_enable_disable_reenable(dev, apdev):
     """Enable, disable, re-enable AP"""
-    ifname = apdev[0]['ifname']
-    hapd_global = hostapd.HostapdGlobal()
-    hapd_global.add(ifname)
-    hapd = hostapd.Hostapd(ifname)
-    hapd.set_defaults()
+    hapd = hostapd.add_ap(apdev[0], {}, no_enable=True)
     hapd.set("ssid", "dynamic")
     hapd.enable()
     ev = hapd.wait_event(["AP-ENABLED"], timeout=30)
@@ -343,9 +323,8 @@ def test_ap_enable_disable_reenable(dev, apdev):
 
 def test_ap_double_disable(dev, apdev):
     """Double DISABLE regression test"""
-    hostapd.add_bss('phy3', apdev[0]['ifname'], 'bss-1.conf')
-    hostapd.add_bss('phy3', apdev[0]['ifname'] + '-2', 'bss-2.conf')
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_bss(apdev[0], apdev[0]['ifname'], 'bss-1.conf')
+    hostapd.add_bss(apdev[0], apdev[0]['ifname'] + '-2', 'bss-2.conf')
     hapd.disable()
     if "FAIL" not in hapd.request("DISABLE"):
         raise Exception("Second DISABLE accepted unexpectedly")
@@ -361,7 +340,7 @@ def test_ap_bss_add_many(dev, apdev):
     finally:
         dev[0].request("SCAN_INTERVAL 5")
         ifname = apdev[0]['ifname']
-        hapd = hostapd.HostapdGlobal()
+        hapd = hostapd.HostapdGlobal(apdev[0])
         hapd.flush()
         for i in range(16):
             ifname2 = ifname + '-' + str(i)
@@ -373,9 +352,7 @@ def test_ap_bss_add_many(dev, apdev):
 
 def _test_ap_bss_add_many(dev, apdev):
     ifname = apdev[0]['ifname']
-    phy = 'phy3'
-    hostapd.add_bss(phy, ifname, 'bss-1.conf')
-    hapd = hostapd.HostapdGlobal()
+    hostapd.add_bss(apdev[0], ifname, 'bss-1.conf')
     fname = '/tmp/hwsim-bss.conf'
     for i in range(16):
         ifname2 = ifname + '-' + str(i)
@@ -388,7 +365,7 @@ def _test_ap_bss_add_many(dev, apdev):
             f.write("bssid=02:00:00:00:03:%02x\n" % (i + 1))
             f.write("ctrl_interface=/var/run/hostapd\n")
             f.write("ssid=test-%d\n" % i)
-        hostapd.add_bss(phy, ifname2, fname)
+        hostapd.add_bss(apdev[0], ifname2, fname)
         os.remove(fname)
 
     dev[0].request("SCAN_INTERVAL 1")
@@ -400,17 +377,17 @@ def _test_ap_bss_add_many(dev, apdev):
         dev[0].request("DISCONNECT")
         dev[0].wait_disconnected(timeout=5)
         ifname2 = ifname + '-' + str(i)
-        hapd.remove(ifname2)
+        hostapd.remove_bss(apdev[0], ifname2)
 
 def test_ap_bss_add_reuse_existing(dev, apdev):
     """Dynamic BSS add operation reusing existing interface"""
     ifname1 = apdev[0]['ifname']
     ifname2 = apdev[0]['ifname'] + '-2'
-    hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
+    hostapd.add_bss(apdev[0], ifname1, 'bss-1.conf')
     subprocess.check_call(["iw", "dev", ifname1, "interface", "add", ifname2,
                            "type", "__ap"])
-    hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
-    hostapd.remove_bss(ifname2)
+    hostapd.add_bss(apdev[0], ifname2, 'bss-2.conf')
+    hostapd.remove_bss(apdev[0], ifname2)
     subprocess.check_call(["iw", "dev", ifname2, "del"])
 
 def hapd_bss_out_of_mem(hapd, phy, confname, count, func):
@@ -422,7 +399,7 @@ def hapd_bss_out_of_mem(hapd, phy, confname, count, func):
 
 def test_ap_bss_add_out_of_memory(dev, apdev):
     """Running out of memory while adding a BSS"""
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], { "ssid": "open" })
+    hapd2 = hostapd.add_ap(apdev[1], { "ssid": "open" })
 
     ifname1 = apdev[0]['ifname']
     ifname2 = apdev[0]['ifname'] + '-2'
@@ -434,29 +411,26 @@ def test_ap_bss_add_out_of_memory(dev, apdev):
     hapd_bss_out_of_mem(hapd2, 'phy3', 'bss-1.conf',
                         1, 'ieee802_11_build_ap_params')
 
-    hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
+    hostapd.add_bss(apdev[0], ifname1, 'bss-1.conf')
 
     hapd_bss_out_of_mem(hapd2, 'phy3', 'bss-2.conf',
                         1, 'hostapd_interface_init_bss')
     hapd_bss_out_of_mem(hapd2, 'phy3', 'bss-2.conf',
                         1, 'ieee802_11_build_ap_params')
 
-    hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
-    hostapd.remove_bss(ifname2)
-    hostapd.remove_bss(ifname1)
+    hostapd.add_bss(apdev[0], ifname2, 'bss-2.conf')
+    hostapd.remove_bss(apdev[0], ifname2)
+    hostapd.remove_bss(apdev[0], ifname1)
 
 def test_ap_multi_bss(dev, apdev):
     """Multiple BSSes with hostapd"""
     ifname1 = apdev[0]['ifname']
     ifname2 = apdev[0]['ifname'] + '-2'
-    hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
-    hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
+    hapd1 = hostapd.add_bss(apdev[0], ifname1, 'bss-1.conf')
+    hapd2 = hostapd.add_bss(apdev[0], ifname2, 'bss-2.conf')
     dev[0].connect("bss-1", key_mgmt="NONE", scan_freq="2412")
     dev[1].connect("bss-2", key_mgmt="NONE", scan_freq="2412")
 
-    hapd1 = hostapd.Hostapd(ifname1)
-    hapd2 = hostapd.Hostapd(ifname2)
-
     hwsim_utils.test_connectivity(dev[0], hapd1)
     hwsim_utils.test_connectivity(dev[1], hapd2)
 
@@ -467,12 +441,18 @@ def test_ap_multi_bss(dev, apdev):
     if 'rx_packets' not in sta1 or int(sta1['rx_packets']) < 1:
         raise Exception("sta1 did not report receiving packets")
 
+@remote_compatible
 def test_ap_add_with_driver(dev, apdev):
     """Add hostapd interface with driver specified"""
     ifname = apdev[0]['ifname']
-    hapd_global = hostapd.HostapdGlobal()
+    try:
+       hostname = apdev[0]['hostname']
+    except:
+       hostname = None
+    hapd_global = hostapd.HostapdGlobal(apdev[0])
     hapd_global.add(ifname, driver="nl80211")
-    hapd = hostapd.Hostapd(ifname)
+    port = hapd_global.get_ctrl_iface_port(ifname)
+    hapd = hostapd.Hostapd(ifname, hostname, port)
     hapd.set_defaults()
     hapd.set("ssid", "dynamic")
     hapd.enable()
@@ -483,3 +463,44 @@ def test_ap_add_with_driver(dev, apdev):
     dev[0].request("DISCONNECT")
     dev[0].wait_disconnected()
     hapd.disable()
+
+def test_ap_iapp(dev, apdev):
+    """IAPP and multiple BSSes"""
+    require_under_vm()
+    try:
+        _test_ap_iapp(dev, apdev)
+    finally:
+        subprocess.call(['ifconfig', 'br-multicast', 'down'],
+                        stderr=open('/dev/null', 'w'))
+        subprocess.call(['brctl', 'delbr', 'br-multicast'],
+                        stderr=open('/dev/null', 'w'))
+
+def _test_ap_iapp(dev, apdev):
+    br_ifname = 'br-multicast'
+    subprocess.call(['brctl', 'addbr', br_ifname])
+    subprocess.call(['brctl', 'setfd', br_ifname, '0'])
+    subprocess.call(['ip', 'addr', 'add', '10.174.65.206/31', 'dev', br_ifname])
+    subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'up'])
+    subprocess.call(['ip', 'route', 'add', '224.0.0.0/4', 'dev', br_ifname])
+
+    params = { "ssid": "test-1",
+               "bridge": br_ifname,
+               "iapp_interface": br_ifname }
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412)
+    dev[0].connect("test-1", key_mgmt="NONE", scan_freq="2412")
+    dev[1].connect("test-1", key_mgmt="NONE", scan_freq="2412")
+
+    hapd2 = hostapd.add_ap(apdev[1], params)
+    dev[0].scan_for_bss(apdev[1]['bssid'], freq=2412)
+    dev[0].roam(apdev[1]['bssid'])
+    dev[0].roam(apdev[0]['bssid'])
+
+    dev[0].request("DISCONNECT")
+    dev[1].request("DISCONNECT")
+    dev[0].wait_disconnected()
+    dev[1].wait_disconnected()
+
+    hapd.disable()
+    hapd2.disable()
index f7d910e..d851c4e 100644 (file)
@@ -12,12 +12,22 @@ import subprocess
 import logging
 logger = logging.getLogger()
 import os
+import socket
+import SocketServer
+import struct
+import tempfile
 
 import hwsim_utils
 import hostapd
-from utils import HwsimSkip, alloc_fail, fail_test, skip_with_fips
+from utils import HwsimSkip, alloc_fail, fail_test, skip_with_fips, wait_fail_trigger
 from wpasupplicant import WpaSupplicant
-from test_ap_psk import check_mib, find_wpas_process, read_process_memory, verify_not_present, get_key_locations
+from test_ap_psk import check_mib, find_wpas_process, read_process_memory, verify_not_present, get_key_locations, set_test_assoc_ie
+
+try:
+    import OpenSSL
+    openssl_imported = True
+except ImportError:
+    openssl_imported = False
 
 def check_hlr_auc_gw_support():
     if not os.path.exists("/tmp/hlr_auc_gw.sock"):
@@ -38,6 +48,16 @@ def check_altsubject_match_support(dev):
     if not tls.startswith("OpenSSL"):
         raise HwsimSkip("altsubject_match not supported with this TLS library: " + tls)
 
+def check_domain_match(dev):
+    tls = dev.request("GET tls_library")
+    if tls.startswith("internal"):
+        raise HwsimSkip("domain_match not supported with this TLS library: " + tls)
+
+def check_domain_suffix_match(dev):
+    tls = dev.request("GET tls_library")
+    if tls.startswith("internal"):
+        raise HwsimSkip("domain_suffix_match not supported with this TLS library: " + tls)
+
 def check_domain_match_full(dev):
     tls = dev.request("GET tls_library")
     if not tls.startswith("OpenSSL"):
@@ -45,13 +65,40 @@ def check_domain_match_full(dev):
 
 def check_cert_probe_support(dev):
     tls = dev.request("GET tls_library")
-    if not tls.startswith("OpenSSL"):
+    if not tls.startswith("OpenSSL") and not tls.startswith("internal"):
         raise HwsimSkip("Certificate probing not supported with this TLS library: " + tls)
 
+def check_ext_cert_check_support(dev):
+    tls = dev.request("GET tls_library")
+    if not tls.startswith("OpenSSL"):
+        raise HwsimSkip("ext_cert_check not supported with this TLS library: " + tls)
+
 def check_ocsp_support(dev):
     tls = dev.request("GET tls_library")
-    if "BoringSSL" in tls:
-        raise HwsimSkip("OCSP not supported with this TLS library: " + tls)
+    #if tls.startswith("internal"):
+    #    raise HwsimSkip("OCSP not supported with this TLS library: " + tls)
+    #if "BoringSSL" in tls:
+    #    raise HwsimSkip("OCSP not supported with this TLS library: " + tls)
+
+def check_ocsp_multi_support(dev):
+    tls = dev.request("GET tls_library")
+    if not tls.startswith("internal"):
+        raise HwsimSkip("OCSP-multi not supported with this TLS library: " + tls)
+    as_hapd = hostapd.Hostapd("as")
+    res = as_hapd.request("GET tls_library")
+    del as_hapd
+    if not res.startswith("internal"):
+        raise HwsimSkip("Authentication server does not support ocsp_multi")
+
+def check_pkcs12_support(dev):
+    tls = dev.request("GET tls_library")
+    #if tls.startswith("internal"):
+    #    raise HwsimSkip("PKCS#12 not supported with this TLS library: " + tls)
+
+def check_dh_dsa_support(dev):
+    tls = dev.request("GET tls_library")
+    if tls.startswith("internal"):
+        raise HwsimSkip("DH DSA not supported with this TLS library: " + tls)
 
 def read_pem(fname):
     with open(fname, "r") as f:
@@ -67,10 +114,9 @@ def read_pem(fname):
                 copy = True
     return base64.b64decode(cert)
 
-def eap_connect(dev, ap, method, identity,
+def eap_connect(dev, hapd, method, identity,
                 sha256=False, expect_failure=False, local_error_report=False,
                 maybe_local_error=False, **kwargs):
-    hapd = hostapd.Hostapd(ap['ifname'])
     id = dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP WPA-EAP-SHA256",
                      eap=method, identity=identity,
                      wait_connect=False, scan_freq="2412", ieee80211w="1",
@@ -89,7 +135,7 @@ def eap_connect(dev, ap, method, identity,
 def eap_check_auth(dev, method, initial, rsn=True, sha256=False,
                    expect_failure=False, local_error_report=False,
                    maybe_local_error=False):
-    ev = dev.wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=10)
+    ev = dev.wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=16)
     if ev is None:
         raise Exception("Association and EAP start timed out")
     ev = dev.wait_event(["CTRL-EVENT-EAP-METHOD",
@@ -129,6 +175,9 @@ def eap_check_auth(dev, method, initial, rsn=True, sha256=False,
 
     if status["suppPortStatus"] != "Authorized":
         raise Exception("Port not authorized")
+    if "selectedMethod" not in status:
+        logger.info("Status: " + str(status))
+        raise Exception("No selectedMethod in status")
     if method not in status["selectedMethod"]:
         raise Exception("Incorrect EAP method status")
     if sha256:
@@ -150,51 +199,51 @@ def test_ap_wpa2_eap_sim(dev, apdev):
     """WPA2-Enterprise connection using EAP-SIM"""
     check_hlr_auc_gw_support()
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "SIM", "1232010000000000",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "SIM", "1232010000000000",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
     hwsim_utils.test_connectivity(dev[0], hapd)
     eap_reauth(dev[0], "SIM")
 
-    eap_connect(dev[1], apdev[0], "SIM", "1232010000000001",
+    eap_connect(dev[1], hapd, "SIM", "1232010000000001",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
-    eap_connect(dev[2], apdev[0], "SIM", "1232010000000002",
+    eap_connect(dev[2], hapd, "SIM", "1232010000000002",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
                 expect_failure=True)
 
     logger.info("Negative test with incorrect key")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "SIM", "1232010000000000",
+    eap_connect(dev[0], hapd, "SIM", "1232010000000000",
                 password="ffdca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
                 expect_failure=True)
 
     logger.info("Invalid GSM-Milenage key")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "SIM", "1232010000000000",
+    eap_connect(dev[0], hapd, "SIM", "1232010000000000",
                 password="ffdca4eda45b53cf0f12d7c9c3bc6a",
                 expect_failure=True)
 
     logger.info("Invalid GSM-Milenage key(2)")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "SIM", "1232010000000000",
+    eap_connect(dev[0], hapd, "SIM", "1232010000000000",
                 password="ffdca4eda45b53cf0f12d7c9c3bc6a8q:cb9cccc4b9258e6dca4760379fb82581",
                 expect_failure=True)
 
     logger.info("Invalid GSM-Milenage key(3)")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "SIM", "1232010000000000",
+    eap_connect(dev[0], hapd, "SIM", "1232010000000000",
                 password="ffdca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb8258q",
                 expect_failure=True)
 
     logger.info("Invalid GSM-Milenage key(4)")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "SIM", "1232010000000000",
+    eap_connect(dev[0], hapd, "SIM", "1232010000000000",
                 password="ffdca4eda45b53cf0f12d7c9c3bc6a89qcb9cccc4b9258e6dca4760379fb82581",
                 expect_failure=True)
 
     logger.info("Missing key configuration")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "SIM", "1232010000000000",
+    eap_connect(dev[0], hapd, "SIM", "1232010000000000",
                 expect_failure=True)
 
 def test_ap_wpa2_eap_sim_sql(dev, apdev, params):
@@ -207,8 +256,8 @@ def test_ap_wpa2_eap_sim_sql(dev, apdev, params):
     con = sqlite3.connect(os.path.join(params['logdir'], "hostapd.db"))
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params['auth_server_port'] = "1814"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "SIM", "1232010000000000",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "SIM", "1232010000000000",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
 
     logger.info("SIM fast re-authentication")
@@ -234,7 +283,7 @@ def test_ap_wpa2_eap_sim_sql(dev, apdev, params):
     eap_reauth(dev[0], "SIM", expect_failure=True)
     dev[0].request("REMOVE_NETWORK all")
 
-    eap_connect(dev[0], apdev[0], "SIM", "1232010000000000",
+    eap_connect(dev[0], hapd, "SIM", "1232010000000000",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
     with con:
         cur = con.cursor()
@@ -247,7 +296,7 @@ def test_ap_wpa2_eap_sim_sql(dev, apdev, params):
     eap_reauth(dev[0], "SIM")
     dev[0].request("REMOVE_NETWORK all")
 
-    eap_connect(dev[0], apdev[0], "SIM", "1232010000000000",
+    eap_connect(dev[0], hapd, "SIM", "1232010000000000",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
     with con:
         cur = con.cursor()
@@ -258,7 +307,7 @@ def test_ap_wpa2_eap_sim_sql(dev, apdev, params):
 def test_ap_wpa2_eap_sim_config(dev, apdev):
     """EAP-SIM configuration options"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="SIM",
                    identity="1232010000000000",
                    password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
@@ -279,10 +328,10 @@ def test_ap_wpa2_eap_sim_config(dev, apdev):
         raise Exception("No EAP error message seen (2)")
     dev[0].request("REMOVE_NETWORK all")
 
-    eap_connect(dev[0], apdev[0], "SIM", "1232010000000000",
+    eap_connect(dev[0], hapd, "SIM", "1232010000000000",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
                 phase1="sim_min_num_chal=2")
-    eap_connect(dev[1], apdev[0], "SIM", "1232010000000000",
+    eap_connect(dev[1], hapd, "SIM", "1232010000000000",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
                 anonymous_identity="345678")
 
@@ -296,7 +345,7 @@ def test_ap_wpa2_eap_sim_ext(dev, apdev):
 def _test_ap_wpa2_eap_sim_ext(dev, apdev):
     check_hlr_auc_gw_support()
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].request("SET external_sim 1")
     id = dev[0].connect("test-wpa2-eap", eap="SIM", key_mgmt="WPA-EAP",
                         identity="1232010000000000",
@@ -429,10 +478,331 @@ def _test_ap_wpa2_eap_sim_ext(dev, apdev):
     if ev is None:
         raise Exception("EAP failure not reported")
 
+def test_ap_wpa2_eap_sim_ext_replace_sim(dev, apdev):
+    """EAP-SIM with external GSM auth and replacing SIM without clearing pseudonym id"""
+    try:
+        _test_ap_wpa2_eap_sim_ext_replace_sim(dev, apdev)
+    finally:
+        dev[0].request("SET external_sim 0")
+
+def _test_ap_wpa2_eap_sim_ext_replace_sim(dev, apdev):
+    check_hlr_auc_gw_support()
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0], params)
+    dev[0].request("SET external_sim 1")
+    id = dev[0].connect("test-wpa2-eap", eap="SIM", key_mgmt="WPA-EAP",
+                        identity="1232010000000000",
+                        wait_connect=False, scan_freq="2412")
+
+    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
+    if ev is None:
+        raise Exception("Wait for external SIM processing request timed out")
+    p = ev.split(':', 2)
+    if p[1] != "GSM-AUTH":
+        raise Exception("Unexpected CTRL-REQ-SIM type")
+    rid = p[0].split('-')[3]
+    rand = p[2].split(' ')[0]
+
+    res = subprocess.check_output(["../../hostapd/hlr_auc_gw",
+                                   "-m",
+                                   "auth_serv/hlr_auc_gw.milenage_db",
+                                   "GSM-AUTH-REQ 232010000000000 " + rand])
+    if "GSM-AUTH-RESP" not in res:
+        raise Exception("Unexpected hlr_auc_gw response")
+    resp = res.split(' ')[2].rstrip()
+
+    dev[0].request("CTRL-RSP-SIM-" + rid + ":GSM-AUTH:" + resp)
+    dev[0].wait_connected(timeout=15)
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+    # Replace SIM, but forget to drop the previous pseudonym identity
+    dev[0].set_network_quoted(id, "identity", "1232010000000009")
+    dev[0].select_network(id, freq="2412")
+
+    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
+    if ev is None:
+        raise Exception("Wait for external SIM processing request timed out")
+    p = ev.split(':', 2)
+    if p[1] != "GSM-AUTH":
+        raise Exception("Unexpected CTRL-REQ-SIM type")
+    rid = p[0].split('-')[3]
+    rand = p[2].split(' ')[0]
+
+    res = subprocess.check_output(["../../hostapd/hlr_auc_gw",
+                                   "-m",
+                                   "auth_serv/hlr_auc_gw.milenage_db",
+                                   "GSM-AUTH-REQ 232010000000009 " + rand])
+    if "GSM-AUTH-RESP" not in res:
+        raise Exception("Unexpected hlr_auc_gw response")
+    resp = res.split(' ')[2].rstrip()
+
+    dev[0].request("CTRL-RSP-SIM-" + rid + ":GSM-AUTH:" + resp)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=15)
+    if ev is None:
+        raise Exception("EAP-Failure not reported")
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+def test_ap_wpa2_eap_sim_ext_replace_sim2(dev, apdev):
+    """EAP-SIM with external GSM auth and replacing SIM and clearing pseudonym identity"""
+    try:
+        _test_ap_wpa2_eap_sim_ext_replace_sim2(dev, apdev)
+    finally:
+        dev[0].request("SET external_sim 0")
+
+def _test_ap_wpa2_eap_sim_ext_replace_sim2(dev, apdev):
+    check_hlr_auc_gw_support()
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0], params)
+    dev[0].request("SET external_sim 1")
+    id = dev[0].connect("test-wpa2-eap", eap="SIM", key_mgmt="WPA-EAP",
+                        identity="1232010000000000",
+                        wait_connect=False, scan_freq="2412")
+
+    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
+    if ev is None:
+        raise Exception("Wait for external SIM processing request timed out")
+    p = ev.split(':', 2)
+    if p[1] != "GSM-AUTH":
+        raise Exception("Unexpected CTRL-REQ-SIM type")
+    rid = p[0].split('-')[3]
+    rand = p[2].split(' ')[0]
+
+    res = subprocess.check_output(["../../hostapd/hlr_auc_gw",
+                                   "-m",
+                                   "auth_serv/hlr_auc_gw.milenage_db",
+                                   "GSM-AUTH-REQ 232010000000000 " + rand])
+    if "GSM-AUTH-RESP" not in res:
+        raise Exception("Unexpected hlr_auc_gw response")
+    resp = res.split(' ')[2].rstrip()
+
+    dev[0].request("CTRL-RSP-SIM-" + rid + ":GSM-AUTH:" + resp)
+    dev[0].wait_connected(timeout=15)
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+    # Replace SIM and drop the previous pseudonym identity
+    dev[0].set_network_quoted(id, "identity", "1232010000000009")
+    dev[0].set_network(id, "anonymous_identity", "NULL")
+    dev[0].select_network(id, freq="2412")
+
+    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
+    if ev is None:
+        raise Exception("Wait for external SIM processing request timed out")
+    p = ev.split(':', 2)
+    if p[1] != "GSM-AUTH":
+        raise Exception("Unexpected CTRL-REQ-SIM type")
+    rid = p[0].split('-')[3]
+    rand = p[2].split(' ')[0]
+
+    res = subprocess.check_output(["../../hostapd/hlr_auc_gw",
+                                   "-m",
+                                   "auth_serv/hlr_auc_gw.milenage_db",
+                                   "GSM-AUTH-REQ 232010000000009 " + rand])
+    if "GSM-AUTH-RESP" not in res:
+        raise Exception("Unexpected hlr_auc_gw response")
+    resp = res.split(' ')[2].rstrip()
+
+    dev[0].request("CTRL-RSP-SIM-" + rid + ":GSM-AUTH:" + resp)
+    dev[0].wait_connected()
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+def test_ap_wpa2_eap_sim_ext_replace_sim3(dev, apdev):
+    """EAP-SIM with external GSM auth, replacing SIM, and no identity in config"""
+    try:
+        _test_ap_wpa2_eap_sim_ext_replace_sim3(dev, apdev)
+    finally:
+        dev[0].request("SET external_sim 0")
+
+def _test_ap_wpa2_eap_sim_ext_replace_sim3(dev, apdev):
+    check_hlr_auc_gw_support()
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0], params)
+    dev[0].request("SET external_sim 1")
+    id = dev[0].connect("test-wpa2-eap", eap="SIM", key_mgmt="WPA-EAP",
+                        wait_connect=False, scan_freq="2412")
+
+    ev = dev[0].wait_event(["CTRL-REQ-IDENTITY"])
+    if ev is None:
+        raise Exception("Request for identity timed out")
+    rid = ev.split(':')[0].split('-')[-1]
+    dev[0].request("CTRL-RSP-IDENTITY-" + rid + ":1232010000000000")
+
+    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
+    if ev is None:
+        raise Exception("Wait for external SIM processing request timed out")
+    p = ev.split(':', 2)
+    if p[1] != "GSM-AUTH":
+        raise Exception("Unexpected CTRL-REQ-SIM type")
+    rid = p[0].split('-')[3]
+    rand = p[2].split(' ')[0]
+
+    res = subprocess.check_output(["../../hostapd/hlr_auc_gw",
+                                   "-m",
+                                   "auth_serv/hlr_auc_gw.milenage_db",
+                                   "GSM-AUTH-REQ 232010000000000 " + rand])
+    if "GSM-AUTH-RESP" not in res:
+        raise Exception("Unexpected hlr_auc_gw response")
+    resp = res.split(' ')[2].rstrip()
+
+    dev[0].request("CTRL-RSP-SIM-" + rid + ":GSM-AUTH:" + resp)
+    dev[0].wait_connected(timeout=15)
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+    # Replace SIM and drop the previous permanent and pseudonym identities
+    dev[0].set_network(id, "identity", "NULL")
+    dev[0].set_network(id, "anonymous_identity", "NULL")
+    dev[0].select_network(id, freq="2412")
+
+    ev = dev[0].wait_event(["CTRL-REQ-IDENTITY"])
+    if ev is None:
+        raise Exception("Request for identity timed out")
+    rid = ev.split(':')[0].split('-')[-1]
+    dev[0].request("CTRL-RSP-IDENTITY-" + rid + ":1232010000000009")
+
+    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
+    if ev is None:
+        raise Exception("Wait for external SIM processing request timed out")
+    p = ev.split(':', 2)
+    if p[1] != "GSM-AUTH":
+        raise Exception("Unexpected CTRL-REQ-SIM type")
+    rid = p[0].split('-')[3]
+    rand = p[2].split(' ')[0]
+
+    res = subprocess.check_output(["../../hostapd/hlr_auc_gw",
+                                   "-m",
+                                   "auth_serv/hlr_auc_gw.milenage_db",
+                                   "GSM-AUTH-REQ 232010000000009 " + rand])
+    if "GSM-AUTH-RESP" not in res:
+        raise Exception("Unexpected hlr_auc_gw response")
+    resp = res.split(' ')[2].rstrip()
+
+    dev[0].request("CTRL-RSP-SIM-" + rid + ":GSM-AUTH:" + resp)
+    dev[0].wait_connected()
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+def test_ap_wpa2_eap_sim_ext_auth_fail(dev, apdev):
+    """EAP-SIM with external GSM auth and auth failing"""
+    try:
+        _test_ap_wpa2_eap_sim_ext_auth_fail(dev, apdev)
+    finally:
+        dev[0].request("SET external_sim 0")
+
+def _test_ap_wpa2_eap_sim_ext_auth_fail(dev, apdev):
+    check_hlr_auc_gw_support()
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0], params)
+    dev[0].request("SET external_sim 1")
+    id = dev[0].connect("test-wpa2-eap", eap="SIM", key_mgmt="WPA-EAP",
+                        identity="1232010000000000",
+                        wait_connect=False, scan_freq="2412")
+
+    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
+    if ev is None:
+        raise Exception("Wait for external SIM processing request timed out")
+    p = ev.split(':', 2)
+    rid = p[0].split('-')[3]
+    dev[0].request("CTRL-RSP-SIM-" + rid + ":GSM-FAIL")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+    if ev is None:
+        raise Exception("EAP failure not reported")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+def test_ap_wpa2_eap_sim_change_bssid(dev, apdev):
+    """EAP-SIM and external GSM auth to check fast reauth with bssid change"""
+    try:
+        _test_ap_wpa2_eap_sim_change_bssid(dev, apdev)
+    finally:
+        dev[0].request("SET external_sim 0")
+
+def _test_ap_wpa2_eap_sim_change_bssid(dev, apdev):
+    check_hlr_auc_gw_support()
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0], params)
+    dev[0].request("SET external_sim 1")
+    id = dev[0].connect("test-wpa2-eap", eap="SIM", key_mgmt="WPA-EAP",
+                        identity="1232010000000000",
+                        wait_connect=False, scan_freq="2412")
+
+    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
+    if ev is None:
+        raise Exception("Wait for external SIM processing request timed out")
+    p = ev.split(':', 2)
+    if p[1] != "GSM-AUTH":
+        raise Exception("Unexpected CTRL-REQ-SIM type")
+    rid = p[0].split('-')[3]
+    rand = p[2].split(' ')[0]
+
+    res = subprocess.check_output(["../../hostapd/hlr_auc_gw",
+                                   "-m",
+                                   "auth_serv/hlr_auc_gw.milenage_db",
+                                   "GSM-AUTH-REQ 232010000000000 " + rand])
+    if "GSM-AUTH-RESP" not in res:
+        raise Exception("Unexpected hlr_auc_gw response")
+    resp = res.split(' ')[2].rstrip()
+
+    dev[0].request("CTRL-RSP-SIM-" + rid + ":GSM-AUTH:" + resp)
+    dev[0].wait_connected(timeout=15)
+
+    # Verify that EAP-SIM Reauthentication can be used after a profile change
+    # that does not affect EAP parameters.
+    dev[0].set_network(id, "bssid", "any")
+    eap_reauth(dev[0], "SIM")
+
+def test_ap_wpa2_eap_sim_no_change_set(dev, apdev):
+    """EAP-SIM and external GSM auth to check fast reauth with no-change SET_NETWORK"""
+    try:
+        _test_ap_wpa2_eap_sim_no_change_set(dev, apdev)
+    finally:
+        dev[0].request("SET external_sim 0")
+
+def _test_ap_wpa2_eap_sim_no_change_set(dev, apdev):
+    check_hlr_auc_gw_support()
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0], params)
+    dev[0].request("SET external_sim 1")
+    id = dev[0].connect("test-wpa2-eap", eap="SIM", key_mgmt="WPA-EAP",
+                        identity="1232010000000000",
+                        wait_connect=False, scan_freq="2412")
+
+    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
+    if ev is None:
+        raise Exception("Wait for external SIM processing request timed out")
+    p = ev.split(':', 2)
+    if p[1] != "GSM-AUTH":
+        raise Exception("Unexpected CTRL-REQ-SIM type")
+    rid = p[0].split('-')[3]
+    rand = p[2].split(' ')[0]
+
+    res = subprocess.check_output(["../../hostapd/hlr_auc_gw",
+                                   "-m",
+                                   "auth_serv/hlr_auc_gw.milenage_db",
+                                   "GSM-AUTH-REQ 232010000000000 " + rand])
+    if "GSM-AUTH-RESP" not in res:
+        raise Exception("Unexpected hlr_auc_gw response")
+    resp = res.split(' ')[2].rstrip()
+
+    dev[0].request("CTRL-RSP-SIM-" + rid + ":GSM-AUTH:" + resp)
+    dev[0].wait_connected(timeout=15)
+
+    # Verify that EAP-SIM Reauthentication can be used after network profile
+    # SET_NETWORK commands that do not actually change previously set
+    # parameter values.
+    dev[0].set_network(id, "key_mgmt", "WPA-EAP")
+    dev[0].set_network(id, "eap", "SIM")
+    dev[0].set_network_quoted(id, "identity", "1232010000000000")
+    dev[0].set_network_quoted(id, "ssid", "test-wpa2-eap")
+    eap_reauth(dev[0], "SIM")
+
 def test_ap_wpa2_eap_sim_oom(dev, apdev):
     """EAP-SIM and OOM"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     tests = [ (1, "milenage_f2345"),
               (2, "milenage_f2345"),
               (3, "milenage_f2345"),
@@ -446,7 +816,7 @@ def test_ap_wpa2_eap_sim_oom(dev, apdev):
               (11, "milenage_f2345"),
               (12, "milenage_f2345") ]
     for count, func in tests:
-        with alloc_fail(dev[0], count, func):
+        with fail_test(dev[0], count, func):
             dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="SIM",
                            identity="1232010000000000",
                            password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
@@ -461,54 +831,54 @@ def test_ap_wpa2_eap_aka(dev, apdev):
     """WPA2-Enterprise connection using EAP-AKA"""
     check_hlr_auc_gw_support()
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "AKA", "0232010000000000",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "AKA", "0232010000000000",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123")
     hwsim_utils.test_connectivity(dev[0], hapd)
     eap_reauth(dev[0], "AKA")
 
     logger.info("Negative test with incorrect key")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "AKA", "0232010000000000",
+    eap_connect(dev[0], hapd, "AKA", "0232010000000000",
                 password="ffdca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
                 expect_failure=True)
 
     logger.info("Invalid Milenage key")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "AKA", "0232010000000000",
+    eap_connect(dev[0], hapd, "AKA", "0232010000000000",
                 password="ffdca4eda45b53cf0f12d7c9c3bc6a",
                 expect_failure=True)
 
     logger.info("Invalid Milenage key(2)")
-    eap_connect(dev[0], apdev[0], "AKA", "0232010000000000",
+    eap_connect(dev[0], hapd, "AKA", "0232010000000000",
                 password="ffdca4eda45b53cf0f12d7c9c3bc6a8q:cb9cccc4b9258e6dca4760379fb82581:000000000123",
                 expect_failure=True)
 
     logger.info("Invalid Milenage key(3)")
-    eap_connect(dev[0], apdev[0], "AKA", "0232010000000000",
+    eap_connect(dev[0], hapd, "AKA", "0232010000000000",
                 password="ffdca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb8258q:000000000123",
                 expect_failure=True)
 
     logger.info("Invalid Milenage key(4)")
-    eap_connect(dev[0], apdev[0], "AKA", "0232010000000000",
+    eap_connect(dev[0], hapd, "AKA", "0232010000000000",
                 password="ffdca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:00000000012q",
                 expect_failure=True)
 
     logger.info("Invalid Milenage key(5)")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "AKA", "0232010000000000",
+    eap_connect(dev[0], hapd, "AKA", "0232010000000000",
                 password="ffdca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581q000000000123",
                 expect_failure=True)
 
     logger.info("Invalid Milenage key(6)")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "AKA", "0232010000000000",
+    eap_connect(dev[0], hapd, "AKA", "0232010000000000",
                 password="ffdca4eda45b53cf0f12d7c9c3bc6a89qcb9cccc4b9258e6dca4760379fb82581q000000000123",
                 expect_failure=True)
 
     logger.info("Missing key configuration")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "AKA", "0232010000000000",
+    eap_connect(dev[0], hapd, "AKA", "0232010000000000",
                 expect_failure=True)
 
 def test_ap_wpa2_eap_aka_sql(dev, apdev, params):
@@ -521,8 +891,8 @@ def test_ap_wpa2_eap_aka_sql(dev, apdev, params):
     con = sqlite3.connect(os.path.join(params['logdir'], "hostapd.db"))
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params['auth_server_port'] = "1814"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "AKA", "0232010000000000",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "AKA", "0232010000000000",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123")
 
     logger.info("AKA fast re-authentication")
@@ -548,7 +918,7 @@ def test_ap_wpa2_eap_aka_sql(dev, apdev, params):
     eap_reauth(dev[0], "AKA", expect_failure=True)
     dev[0].request("REMOVE_NETWORK all")
 
-    eap_connect(dev[0], apdev[0], "AKA", "0232010000000000",
+    eap_connect(dev[0], hapd, "AKA", "0232010000000000",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123")
     with con:
         cur = con.cursor()
@@ -561,7 +931,7 @@ def test_ap_wpa2_eap_aka_sql(dev, apdev, params):
     eap_reauth(dev[0], "AKA")
     dev[0].request("REMOVE_NETWORK all")
 
-    eap_connect(dev[0], apdev[0], "AKA", "0232010000000000",
+    eap_connect(dev[0], hapd, "AKA", "0232010000000000",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123")
     with con:
         cur = con.cursor()
@@ -572,8 +942,8 @@ def test_ap_wpa2_eap_aka_sql(dev, apdev, params):
 def test_ap_wpa2_eap_aka_config(dev, apdev):
     """EAP-AKA configuration options"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "AKA", "0232010000000000",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "AKA", "0232010000000000",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
                 anonymous_identity="2345678")
 
@@ -587,7 +957,7 @@ def test_ap_wpa2_eap_aka_ext(dev, apdev):
 def _test_ap_wpa2_eap_aka_ext(dev, apdev):
     check_hlr_auc_gw_support()
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].request("SET external_sim 1")
     id = dev[0].connect("test-wpa2-eap", eap="AKA", key_mgmt="WPA-EAP",
                         identity="0232010000000000",
@@ -615,6 +985,7 @@ def _test_ap_wpa2_eap_aka_ext(dev, apdev):
     dev[0].request("DISCONNECT")
     dev[0].wait_disconnected()
     time.sleep(0.1)
+    dev[0].dump_monitor()
 
     dev[0].select_network(id, freq="2412")
     ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
@@ -643,6 +1014,7 @@ def _test_ap_wpa2_eap_aka_ext(dev, apdev):
     dev[0].request("DISCONNECT")
     dev[0].wait_disconnected()
     time.sleep(0.1)
+    dev[0].dump_monitor()
 
     tests = [ ":UMTS-AUTH:00112233445566778899aabbccddeeff:00112233445566778899aabbccddeeff:0011223344",
               ":UMTS-AUTH:34",
@@ -669,13 +1041,42 @@ def _test_ap_wpa2_eap_aka_ext(dev, apdev):
         dev[0].request("DISCONNECT")
         dev[0].wait_disconnected()
         time.sleep(0.1)
+        dev[0].dump_monitor()
+
+def test_ap_wpa2_eap_aka_ext_auth_fail(dev, apdev):
+    """EAP-AKA with external UMTS auth and auth failing"""
+    try:
+        _test_ap_wpa2_eap_aka_ext_auth_fail(dev, apdev)
+    finally:
+        dev[0].request("SET external_sim 0")
+
+def _test_ap_wpa2_eap_aka_ext_auth_fail(dev, apdev):
+    check_hlr_auc_gw_support()
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0], params)
+    dev[0].request("SET external_sim 1")
+    id = dev[0].connect("test-wpa2-eap", eap="AKA", key_mgmt="WPA-EAP",
+                        identity="0232010000000000",
+                        wait_connect=False, scan_freq="2412")
+
+    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
+    if ev is None:
+        raise Exception("Wait for external SIM processing request timed out")
+    p = ev.split(':', 2)
+    rid = p[0].split('-')[3]
+    dev[0].request("CTRL-RSP-SIM-" + rid + ":UMTS-FAIL")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+    if ev is None:
+        raise Exception("EAP failure not reported")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
 
 def test_ap_wpa2_eap_aka_prime(dev, apdev):
     """WPA2-Enterprise connection using EAP-AKA'"""
     check_hlr_auc_gw_support()
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "AKA'", "6555444333222111",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "AKA'", "6555444333222111",
                 password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123")
     hwsim_utils.test_connectivity(dev[0], hapd)
     eap_reauth(dev[0], "AKA'")
@@ -689,7 +1090,7 @@ def test_ap_wpa2_eap_aka_prime(dev, apdev):
 
     logger.info("Negative test with incorrect key")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "AKA'", "6555444333222111",
+    eap_connect(dev[0], hapd, "AKA'", "6555444333222111",
                 password="ff22250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
                 expect_failure=True)
 
@@ -703,8 +1104,8 @@ def test_ap_wpa2_eap_aka_prime_sql(dev, apdev, params):
     con = sqlite3.connect(os.path.join(params['logdir'], "hostapd.db"))
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params['auth_server_port'] = "1814"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "AKA'", "6555444333222111",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "AKA'", "6555444333222111",
                 password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123")
 
     logger.info("AKA' fast re-authentication")
@@ -730,7 +1131,7 @@ def test_ap_wpa2_eap_aka_prime_sql(dev, apdev, params):
     eap_reauth(dev[0], "AKA'", expect_failure=True)
     dev[0].request("REMOVE_NETWORK all")
 
-    eap_connect(dev[0], apdev[0], "AKA'", "6555444333222111",
+    eap_connect(dev[0], hapd, "AKA'", "6555444333222111",
                 password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123")
     with con:
         cur = con.cursor()
@@ -743,7 +1144,7 @@ def test_ap_wpa2_eap_aka_prime_sql(dev, apdev, params):
     eap_reauth(dev[0], "AKA'")
     dev[0].request("REMOVE_NETWORK all")
 
-    eap_connect(dev[0], apdev[0], "AKA'", "6555444333222111",
+    eap_connect(dev[0], hapd, "AKA'", "6555444333222111",
                 password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123")
     with con:
         cur = con.cursor()
@@ -751,14 +1152,42 @@ def test_ap_wpa2_eap_aka_prime_sql(dev, apdev, params):
     logger.info("AKA' reauth with max reauth count reached")
     eap_reauth(dev[0], "AKA'")
 
+def test_ap_wpa2_eap_aka_prime_ext_auth_fail(dev, apdev):
+    """EAP-AKA' with external UMTS auth and auth failing"""
+    try:
+        _test_ap_wpa2_eap_aka_prime_ext_auth_fail(dev, apdev)
+    finally:
+        dev[0].request("SET external_sim 0")
+
+def _test_ap_wpa2_eap_aka_prime_ext_auth_fail(dev, apdev):
+    check_hlr_auc_gw_support()
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0], params)
+    dev[0].request("SET external_sim 1")
+    id = dev[0].connect("test-wpa2-eap", eap="AKA'", key_mgmt="WPA-EAP",
+                        identity="6555444333222111",
+                        wait_connect=False, scan_freq="2412")
+
+    ev = dev[0].wait_event(["CTRL-REQ-SIM"], timeout=15)
+    if ev is None:
+        raise Exception("Wait for external SIM processing request timed out")
+    p = ev.split(':', 2)
+    rid = p[0].split('-')[3]
+    dev[0].request("CTRL-RSP-SIM-" + rid + ":UMTS-FAIL")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+    if ev is None:
+        raise Exception("EAP failure not reported")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
 def test_ap_wpa2_eap_ttls_pap(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/PAP"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     key_mgmt = hapd.get_config()['key_mgmt']
     if key_mgmt.split(' ')[0] != "WPA-EAP":
         raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
-    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+    eap_connect(dev[0], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
     hwsim_utils.test_connectivity(dev[0], hapd)
@@ -771,8 +1200,8 @@ def test_ap_wpa2_eap_ttls_pap_subject_match(dev, apdev):
     check_subject_match_support(dev[0])
     check_altsubject_match_support(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
                 subject_match="/C=FI/O=w1.fi/CN=server.w1.fi",
@@ -782,12 +1211,12 @@ def test_ap_wpa2_eap_ttls_pap_subject_match(dev, apdev):
 def test_ap_wpa2_eap_ttls_pap_incorrect_password(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/PAP - incorrect password"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="wrong",
                 ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
                 expect_failure=True)
-    eap_connect(dev[1], apdev[0], "TTLS", "user",
+    eap_connect(dev[1], hapd, "TTLS", "user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
                 expect_failure=True)
@@ -796,8 +1225,8 @@ def test_ap_wpa2_eap_ttls_chap(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/CHAP"""
     skip_with_fips(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "chap user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "chap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.der", phase2="auth=CHAP")
     hwsim_utils.test_connectivity(dev[0], hapd)
@@ -808,8 +1237,8 @@ def test_ap_wpa2_eap_ttls_chap_altsubject_match(dev, apdev):
     skip_with_fips(dev[0])
     check_altsubject_match_support(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "chap user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "chap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.der", phase2="auth=CHAP",
                 altsubject_match="EMAIL:noone@example.com;URI:http://example.com/;DNS:server.w1.fi")
@@ -819,12 +1248,12 @@ def test_ap_wpa2_eap_ttls_chap_incorrect_password(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/CHAP - incorrect password"""
     skip_with_fips(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "chap user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "chap user",
                 anonymous_identity="ttls", password="wrong",
                 ca_cert="auth_serv/ca.pem", phase2="auth=CHAP",
                 expect_failure=True)
-    eap_connect(dev[1], apdev[0], "TTLS", "user",
+    eap_connect(dev[1], hapd, "TTLS", "user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=CHAP",
                 expect_failure=True)
@@ -832,45 +1261,52 @@ def test_ap_wpa2_eap_ttls_chap_incorrect_password(dev, apdev):
 def test_ap_wpa2_eap_ttls_mschap(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/MSCHAP"""
     skip_with_fips(dev[0])
+    check_domain_suffix_match(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "mschap user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "mschap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
                 domain_suffix_match="server.w1.fi")
     hwsim_utils.test_connectivity(dev[0], hapd)
     eap_reauth(dev[0], "TTLS")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "TTLS", "mschap user",
+    eap_connect(dev[0], hapd, "TTLS", "mschap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
                 fragment_size="200")
-
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+    eap_connect(dev[0], hapd, "TTLS", "mschap user",
+                anonymous_identity="ttls",
+                password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
+                ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP")
+
 def test_ap_wpa2_eap_ttls_mschap_incorrect_password(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/MSCHAP - incorrect password"""
     skip_with_fips(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "mschap user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "mschap user",
                 anonymous_identity="ttls", password="wrong",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
                 expect_failure=True)
-    eap_connect(dev[1], apdev[0], "TTLS", "user",
+    eap_connect(dev[1], hapd, "TTLS", "user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
                 expect_failure=True)
-    eap_connect(dev[2], apdev[0], "TTLS", "no such user",
+    eap_connect(dev[2], hapd, "TTLS", "no such user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
                 expect_failure=True)
 
 def test_ap_wpa2_eap_ttls_mschapv2(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/MSCHAPv2"""
+    check_domain_suffix_match(dev[0])
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
-    eap_connect(dev[0], apdev[0], "TTLS", "DOMAIN\mschapv2 user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "DOMAIN\mschapv2 user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                 domain_suffix_match="server.w1.fi")
@@ -889,19 +1325,42 @@ def test_ap_wpa2_eap_ttls_mschapv2(dev, apdev):
 
     logger.info("Password as hash value")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "TTLS", "DOMAIN\mschapv2 user",
+    eap_connect(dev[0], hapd, "TTLS", "DOMAIN\mschapv2 user",
                 anonymous_identity="ttls",
                 password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2")
 
+def test_ap_wpa2_eap_ttls_invalid_phase2(dev, apdev):
+    """EAP-TTLS with invalid phase2 parameter values"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0], params)
+    tests = [ "auth=MSCHAPv2", "auth=MSCHAPV2 autheap=MD5",
+              "autheap=MD5 auth=MSCHAPV2", "auth=PAP auth=CHAP",
+              "autheap=MD5 autheap=FOO autheap=MSCHAPV2" ]
+    for t in tests:
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                       identity="DOMAIN\mschapv2 user",
+                       anonymous_identity="ttls", password="password",
+                       ca_cert="auth_serv/ca.pem", phase2=t,
+                       wait_connect=False, scan_freq="2412")
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=10)
+        if ev is None or "method=21" not in ev:
+            raise Exception("EAP-TTLS not started")
+        ev = dev[0].wait_event(["EAP: Failed to initialize EAP method",
+                                "CTRL-EVENT-CONNECTED"], timeout=5)
+        if ev is None or "CTRL-EVENT-CONNECTED" in ev:
+            raise Exception("No EAP-TTLS failure reported for phase2=" + t)
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+        dev[0].dump_monitor()
+
 def test_ap_wpa2_eap_ttls_mschapv2_suffix_match(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/MSCHAPv2"""
     check_domain_match_full(dev[0])
     skip_with_fips(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
-    eap_connect(dev[0], apdev[0], "TTLS", "DOMAIN\mschapv2 user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "DOMAIN\mschapv2 user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                 domain_suffix_match="w1.fi")
@@ -910,11 +1369,11 @@ def test_ap_wpa2_eap_ttls_mschapv2_suffix_match(dev, apdev):
 
 def test_ap_wpa2_eap_ttls_mschapv2_domain_match(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/MSCHAPv2 (domain_match)"""
+    check_domain_match(dev[0])
     skip_with_fips(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
-    eap_connect(dev[0], apdev[0], "TTLS", "DOMAIN\mschapv2 user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "DOMAIN\mschapv2 user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                 domain_match="Server.w1.fi")
@@ -925,12 +1384,12 @@ def test_ap_wpa2_eap_ttls_mschapv2_incorrect_password(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/MSCHAPv2 - incorrect password"""
     skip_with_fips(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "DOMAIN\mschapv2 user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "DOMAIN\mschapv2 user",
                 anonymous_identity="ttls", password="password1",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                 expect_failure=True)
-    eap_connect(dev[1], apdev[0], "TTLS", "user",
+    eap_connect(dev[1], hapd, "TTLS", "user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                 expect_failure=True)
@@ -939,21 +1398,31 @@ def test_ap_wpa2_eap_ttls_mschapv2_utf8(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/MSCHAPv2 and UTF-8 password"""
     skip_with_fips(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
-    eap_connect(dev[0], apdev[0], "TTLS", "utf8-user-hash",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "utf8-user-hash",
                 anonymous_identity="ttls", password="secret-åäö-€-password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2")
-    eap_connect(dev[1], apdev[0], "TTLS", "utf8-user",
+    eap_connect(dev[1], hapd, "TTLS", "utf8-user",
                 anonymous_identity="ttls",
                 password_hex="hash:bd5844fad2489992da7fe8c5a01559cf",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2")
+    for p in [ "80", "41c041e04141e041", 257*"41" ]:
+        dev[2].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
+                       eap="TTLS", identity="utf8-user-hash",
+                       anonymous_identity="ttls", password_hex=p,
+                       ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                       wait_connect=False, scan_freq="2412")
+        ev = dev[2].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=1)
+        if ev is None:
+            raise Exception("No failure reported")
+        dev[2].request("REMOVE_NETWORK all")
+        dev[2].wait_disconnected()
 
 def test_ap_wpa2_eap_ttls_eap_gtc(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/EAP-GTC"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="autheap=GTC")
     hwsim_utils.test_connectivity(dev[0], hapd)
@@ -962,8 +1431,8 @@ def test_ap_wpa2_eap_ttls_eap_gtc(dev, apdev):
 def test_ap_wpa2_eap_ttls_eap_gtc_incorrect_password(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/EAP-GTC - incorrect password"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "user",
                 anonymous_identity="ttls", password="wrong",
                 ca_cert="auth_serv/ca.pem", phase2="autheap=GTC",
                 expect_failure=True)
@@ -971,8 +1440,8 @@ def test_ap_wpa2_eap_ttls_eap_gtc_incorrect_password(dev, apdev):
 def test_ap_wpa2_eap_ttls_eap_gtc_no_password(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/EAP-GTC - no password"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "user-no-passwd",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "user-no-passwd",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="autheap=GTC",
                 expect_failure=True)
@@ -980,9 +1449,9 @@ def test_ap_wpa2_eap_ttls_eap_gtc_no_password(dev, apdev):
 def test_ap_wpa2_eap_ttls_eap_gtc_server_oom(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/EAP-GTC - server OOM"""
     params = int_eap_server_params()
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     with alloc_fail(hapd, 1, "eap_gtc_init"):
-        eap_connect(dev[0], apdev[0], "TTLS", "user",
+        eap_connect(dev[0], hapd, "TTLS", "user",
                     anonymous_identity="ttls", password="password",
                     ca_cert="auth_serv/ca.pem", phase2="autheap=GTC",
                     expect_failure=True)
@@ -1001,12 +1470,31 @@ def test_ap_wpa2_eap_ttls_eap_gtc_server_oom(dev, apdev):
             if hapd.request("GET_ALLOC_FAIL").startswith('0'):
                 break
 
+def test_ap_wpa2_eap_ttls_eap_gtc_oom(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TTLS/EAP-GTC (OOM)"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    tests = [ "eap_gtc_init",
+              "eap_msg_alloc;eap_gtc_process" ]
+    for func in tests:
+        with alloc_fail(dev[0], 1, func):
+            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
+                           scan_freq="2412",
+                           eap="TTLS", identity="user",
+                           anonymous_identity="ttls", password="password",
+                           ca_cert="auth_serv/ca.pem", phase2="autheap=GTC",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
 def test_ap_wpa2_eap_ttls_eap_md5(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/EAP-MD5"""
     check_eap_capa(dev[0], "MD5")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="autheap=MD5")
     hwsim_utils.test_connectivity(dev[0], hapd)
@@ -1016,8 +1504,8 @@ def test_ap_wpa2_eap_ttls_eap_md5_incorrect_password(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/EAP-MD5 - incorrect password"""
     check_eap_capa(dev[0], "MD5")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "user",
                 anonymous_identity="ttls", password="wrong",
                 ca_cert="auth_serv/ca.pem", phase2="autheap=MD5",
                 expect_failure=True)
@@ -1026,8 +1514,8 @@ def test_ap_wpa2_eap_ttls_eap_md5_no_password(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/EAP-MD5 - no password"""
     check_eap_capa(dev[0], "MD5")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "user-no-passwd",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "user-no-passwd",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="autheap=MD5",
                 expect_failure=True)
@@ -1036,9 +1524,9 @@ def test_ap_wpa2_eap_ttls_eap_md5_server_oom(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/EAP-MD5 - server OOM"""
     check_eap_capa(dev[0], "MD5")
     params = int_eap_server_params()
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     with alloc_fail(hapd, 1, "eap_md5_init"):
-        eap_connect(dev[0], apdev[0], "TTLS", "user",
+        eap_connect(dev[0], hapd, "TTLS", "user",
                     anonymous_identity="ttls", password="password",
                     ca_cert="auth_serv/ca.pem", phase2="autheap=MD5",
                     expect_failure=True)
@@ -1061,8 +1549,8 @@ def test_ap_wpa2_eap_ttls_eap_mschapv2(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/EAP-MSCHAPv2"""
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="autheap=MSCHAPV2")
     hwsim_utils.test_connectivity(dev[0], hapd)
@@ -1070,7 +1558,7 @@ def test_ap_wpa2_eap_ttls_eap_mschapv2(dev, apdev):
 
     logger.info("Negative test with incorrect password")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "TTLS", "user",
+    eap_connect(dev[0], hapd, "TTLS", "user",
                 anonymous_identity="ttls", password="password1",
                 ca_cert="auth_serv/ca.pem", phase2="autheap=MSCHAPV2",
                 expect_failure=True)
@@ -1079,8 +1567,8 @@ def test_ap_wpa2_eap_ttls_eap_mschapv2_no_password(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/EAP-MSCHAPv2 - no password"""
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "user-no-passwd",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "user-no-passwd",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="autheap=MSCHAPV2",
                 expect_failure=True)
@@ -1089,9 +1577,9 @@ def test_ap_wpa2_eap_ttls_eap_mschapv2_server_oom(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/EAP-MSCHAPv2 - server OOM"""
     check_eap_capa(dev[0], "MSCHAPV2")
     params = int_eap_server_params()
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     with alloc_fail(hapd, 1, "eap_mschapv2_init"):
-        eap_connect(dev[0], apdev[0], "TTLS", "user",
+        eap_connect(dev[0], hapd, "TTLS", "user",
                     anonymous_identity="ttls", password="password",
                     ca_cert="auth_serv/ca.pem", phase2="autheap=MSCHAPV2",
                     expect_failure=True)
@@ -1142,8 +1630,8 @@ def test_ap_wpa2_eap_ttls_eap_mschapv2_server_oom(dev, apdev):
 def test_ap_wpa2_eap_ttls_eap_aka(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/EAP-AKA"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "0232010000000000",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "0232010000000000",
                 anonymous_identity="0232010000000000@ttls",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
                 ca_cert="auth_serv/ca.pem", phase2="autheap=AKA")
@@ -1151,8 +1639,8 @@ def test_ap_wpa2_eap_ttls_eap_aka(dev, apdev):
 def test_ap_wpa2_eap_peap_eap_aka(dev, apdev):
     """WPA2-Enterprise connection using EAP-PEAP/EAP-AKA"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "PEAP", "0232010000000000",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "PEAP", "0232010000000000",
                 anonymous_identity="0232010000000000@peap",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
                 ca_cert="auth_serv/ca.pem", phase2="auth=AKA")
@@ -1161,8 +1649,8 @@ def test_ap_wpa2_eap_fast_eap_aka(dev, apdev):
     """WPA2-Enterprise connection using EAP-FAST/EAP-AKA"""
     check_eap_capa(dev[0], "FAST")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "FAST", "0232010000000000",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "FAST", "0232010000000000",
                 anonymous_identity="0232010000000000@fast",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
                 phase1="fast_provisioning=2",
@@ -1173,28 +1661,28 @@ def test_ap_wpa2_eap_peap_eap_mschapv2(dev, apdev):
     """WPA2-Enterprise connection using EAP-PEAP/EAP-MSCHAPv2"""
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "PEAP", "user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "PEAP", "user",
                 anonymous_identity="peap", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2")
     hwsim_utils.test_connectivity(dev[0], hapd)
     eap_reauth(dev[0], "PEAP")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "PEAP", "user",
+    eap_connect(dev[0], hapd, "PEAP", "user",
                 anonymous_identity="peap", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                 fragment_size="200")
 
     logger.info("Password as hash value")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "PEAP", "user",
+    eap_connect(dev[0], hapd, "PEAP", "user",
                 anonymous_identity="peap",
                 password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2")
 
     logger.info("Negative test with incorrect password")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "PEAP", "user",
+    eap_connect(dev[0], hapd, "PEAP", "user",
                 anonymous_identity="peap", password="password1",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                 expect_failure=True)
@@ -1203,8 +1691,8 @@ def test_ap_wpa2_eap_peap_eap_mschapv2_domain(dev, apdev):
     """WPA2-Enterprise connection using EAP-PEAP/EAP-MSCHAPv2 with domain"""
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "PEAP", "DOMAIN\user3",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "PEAP", "DOMAIN\user3",
                 anonymous_identity="peap", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2")
     hwsim_utils.test_connectivity(dev[0], hapd)
@@ -1214,8 +1702,8 @@ def test_ap_wpa2_eap_peap_eap_mschapv2_incorrect_password(dev, apdev):
     """WPA2-Enterprise connection using EAP-PEAP/EAP-MSCHAPv2 - incorrect password"""
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "PEAP", "user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "PEAP", "user",
                 anonymous_identity="peap", password="wrong",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                 expect_failure=True)
@@ -1224,19 +1712,19 @@ def test_ap_wpa2_eap_peap_crypto_binding(dev, apdev):
     """WPA2-Enterprise connection using EAP-PEAPv0/EAP-MSCHAPv2 and crypto binding"""
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "PEAP", "user", password="password",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "PEAP", "user", password="password",
                 ca_cert="auth_serv/ca.pem",
                 phase1="peapver=0 crypto_binding=2",
                 phase2="auth=MSCHAPV2")
     hwsim_utils.test_connectivity(dev[0], hapd)
     eap_reauth(dev[0], "PEAP")
 
-    eap_connect(dev[1], apdev[0], "PEAP", "user", password="password",
+    eap_connect(dev[1], hapd, "PEAP", "user", password="password",
                 ca_cert="auth_serv/ca.pem",
                 phase1="peapver=0 crypto_binding=1",
                 phase2="auth=MSCHAPV2")
-    eap_connect(dev[2], apdev[0], "PEAP", "user", password="password",
+    eap_connect(dev[2], hapd, "PEAP", "user", password="password",
                 ca_cert="auth_serv/ca.pem",
                 phase1="peapver=0 crypto_binding=0",
                 phase2="auth=MSCHAPV2")
@@ -1245,9 +1733,9 @@ def test_ap_wpa2_eap_peap_crypto_binding_server_oom(dev, apdev):
     """WPA2-Enterprise connection using EAP-PEAPv0/EAP-MSCHAPv2 and crypto binding with server OOM"""
     check_eap_capa(dev[0], "MSCHAPV2")
     params = int_eap_server_params()
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     with alloc_fail(hapd, 1, "eap_mschapv2_getKey"):
-        eap_connect(dev[0], apdev[0], "PEAP", "user", password="password",
+        eap_connect(dev[0], hapd, "PEAP", "user", password="password",
                     ca_cert="auth_serv/ca.pem",
                     phase1="peapver=0 crypto_binding=2",
                     phase2="auth=MSCHAPV2",
@@ -1257,18 +1745,30 @@ def test_ap_wpa2_eap_peap_params(dev, apdev):
     """WPA2-Enterprise connection using EAP-PEAPv0/EAP-MSCHAPv2 and various parameters"""
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "PEAP", "user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "PEAP", "user",
                 anonymous_identity="peap", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                 phase1="peapver=0 peaplabel=1",
                 expect_failure=True)
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[1], apdev[0], "PEAP", "user", password="password",
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="PEAP",
+                   identity="user",
+                   anonymous_identity="peap", password="password",
+                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                   phase1="peap_outer_success=0",
+                   wait_connect=False, scan_freq="2412")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
+    if ev is None:
+        raise Exception("No EAP success seen")
+    # This won't succeed to connect with peap_outer_success=0, so stop here.
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+    eap_connect(dev[1], hapd, "PEAP", "user", password="password",
                 ca_cert="auth_serv/ca.pem",
                 phase1="peap_outer_success=1",
                 phase2="auth=MSCHAPV2")
-    eap_connect(dev[2], apdev[0], "PEAP", "user", password="password",
+    eap_connect(dev[2], hapd, "PEAP", "user", password="password",
                 ca_cert="auth_serv/ca.pem",
                 phase1="peap_outer_success=2",
                 phase2="auth=MSCHAPV2")
@@ -1285,11 +1785,43 @@ def test_ap_wpa2_eap_peap_params(dev, apdev):
     if ev is not None:
         raise Exception("Unexpected connection")
 
+    tests = [ ("peap-ver0", ""),
+              ("peap-ver1", ""),
+              ("peap-ver0", "peapver=0"),
+              ("peap-ver1", "peapver=1") ]
+    for anon,phase1 in tests:
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="PEAP",
+                       identity="user", anonymous_identity=anon,
+                       password="password", phase1=phase1,
+                       ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                       scan_freq="2412")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    tests = [ ("peap-ver0", "peapver=1"),
+              ("peap-ver1", "peapver=0") ]
+    for anon,phase1 in tests:
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="PEAP",
+                       identity="user", anonymous_identity=anon,
+                       password="password", phase1=phase1,
+                       ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                       wait_connect=False, scan_freq="2412")
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=15)
+        if ev is None:
+            raise Exception("No EAP-Failure seen")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    eap_connect(dev[0], hapd, "PEAP", "user", password="password",
+                ca_cert="auth_serv/ca.pem",
+                phase1="tls_allow_md5=1 tls_disable_session_ticket=1 tls_disable_tlsv1_0=0 tls_disable_tlsv1_1=0 tls_disable_tlsv1_2=0 tls_ext_cert_check=0",
+                phase2="auth=MSCHAPV2")
+
 def test_ap_wpa2_eap_peap_eap_tls(dev, apdev):
     """WPA2-Enterprise connection using EAP-PEAP/EAP-TLS"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "PEAP", "cert user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "PEAP", "cert user",
                 ca_cert="auth_serv/ca.pem", phase2="auth=TLS",
                 ca_cert2="auth_serv/ca.pem",
                 client_cert2="auth_serv/user.pem",
@@ -1299,16 +1831,34 @@ def test_ap_wpa2_eap_peap_eap_tls(dev, apdev):
 def test_ap_wpa2_eap_tls(dev, apdev):
     """WPA2-Enterprise connection using EAP-TLS"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TLS", "tls user", ca_cert="auth_serv/ca.pem",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
                 client_cert="auth_serv/user.pem",
                 private_key="auth_serv/user.key")
     eap_reauth(dev[0], "TLS")
 
+def test_eap_tls_pkcs8_pkcs5_v2_des3(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TLS and PKCS #8, PKCS #5 v2 DES3 key"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
+                client_cert="auth_serv/user.pem",
+                private_key="auth_serv/user.key.pkcs8",
+                private_key_passwd="whatever")
+
+def test_eap_tls_pkcs8_pkcs5_v15(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TLS and PKCS #8, PKCS #5 v1.5 key"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
+                client_cert="auth_serv/user.pem",
+                private_key="auth_serv/user.key.pkcs8.pkcs5v15",
+                private_key_passwd="whatever")
+
 def test_ap_wpa2_eap_tls_blob(dev, apdev):
     """WPA2-Enterprise connection using EAP-TLS and config blobs"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     cert = read_pem("auth_serv/ca.pem")
     if "OK" not in dev[0].request("SET blob cacert " + cert.encode("hex")):
         raise Exception("Could not set cacert blob")
@@ -1318,15 +1868,41 @@ def test_ap_wpa2_eap_tls_blob(dev, apdev):
     key = read_pem("auth_serv/user.rsa-key")
     if "OK" not in dev[0].request("SET blob userkey " + key.encode("hex")):
         raise Exception("Could not set cacert blob")
-    eap_connect(dev[0], apdev[0], "TLS", "tls user", ca_cert="blob://cacert",
+    eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="blob://cacert",
                 client_cert="blob://usercert",
                 private_key="blob://userkey")
 
+def test_ap_wpa2_eap_tls_blob_missing(dev, apdev):
+    """EAP-TLS and config blob missing"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0], params)
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                   identity="tls user",
+                   ca_cert="blob://testing-blob-does-not-exist",
+                   client_cert="blob://testing-blob-does-not-exist",
+                   private_key="blob://testing-blob-does-not-exist",
+                   wait_connect=False, scan_freq="2412")
+    ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"], timeout=10)
+    if ev is None:
+        raise Exception("EAP failure not reported")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+def test_ap_wpa2_eap_tls_with_tls_len(dev, apdev):
+    """EAP-TLS and TLS Message Length in unfragmented packets"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
+                phase1="include_tls_length=1",
+                client_cert="auth_serv/user.pem",
+                private_key="auth_serv/user.key")
+
 def test_ap_wpa2_eap_tls_pkcs12(dev, apdev):
     """WPA2-Enterprise connection using EAP-TLS and PKCS#12"""
+    check_pkcs12_support(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TLS", "tls user", ca_cert="auth_serv/ca.pem",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
                 private_key="auth_serv/user.pkcs12",
                 private_key_passwd="whatever")
     dev[0].request("REMOVE_NETWORK all")
@@ -1352,7 +1928,7 @@ def test_ap_wpa2_eap_tls_pkcs12(dev, apdev):
     # client certificate.
     for pkcs12 in "auth_serv/user2.pkcs12", "auth_serv/user3.pkcs12":
         for i in range(2):
-            eap_connect(dev[0], apdev[0], "TLS", "tls user",
+            eap_connect(dev[0], hapd, "TLS", "tls user",
                         ca_cert="auth_serv/ca.pem",
                         private_key=pkcs12,
                         private_key_passwd="whatever")
@@ -1361,15 +1937,16 @@ def test_ap_wpa2_eap_tls_pkcs12(dev, apdev):
 
 def test_ap_wpa2_eap_tls_pkcs12_blob(dev, apdev):
     """WPA2-Enterprise connection using EAP-TLS and PKCS#12 from configuration blob"""
+    check_pkcs12_support(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     cert = read_pem("auth_serv/ca.pem")
     if "OK" not in dev[0].request("SET blob cacert " + cert.encode("hex")):
         raise Exception("Could not set cacert blob")
     with open("auth_serv/user.pkcs12", "rb") as f:
         if "OK" not in dev[0].request("SET blob pkcs12 " + f.read().encode("hex")):
             raise Exception("Could not set pkcs12 blob")
-    eap_connect(dev[0], apdev[0], "TLS", "tls user", ca_cert="blob://cacert",
+    eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="blob://cacert",
                 private_key="blob://pkcs12",
                 private_key_passwd="whatever")
 
@@ -1377,7 +1954,7 @@ def test_ap_wpa2_eap_tls_neg_incorrect_trust_root(dev, apdev):
     """WPA2-Enterprise negative test - incorrect trust root"""
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     cert = read_pem("auth_serv/ca-incorrect.pem")
     if "OK" not in dev[0].request("SET blob cacert " + cert.encode("hex")):
         raise Exception("Could not set cacert blob")
@@ -1393,7 +1970,7 @@ def test_ap_wpa2_eap_tls_neg_incorrect_trust_root(dev, apdev):
                    wait_connect=False, scan_freq="2412")
 
     for dev in (dev[0], dev[1]):
-        ev = dev.wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=10)
+        ev = dev.wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=16)
         if ev is None:
             raise Exception("Association and EAP start timed out")
 
@@ -1436,7 +2013,7 @@ def test_ap_wpa2_eap_tls_neg_incorrect_trust_root(dev, apdev):
 def test_ap_wpa2_eap_tls_diff_ca_trust(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/PAP and different CA trust"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="pap user", anonymous_identity="ttls",
                    password="password", phase2="auth=PAP",
@@ -1464,7 +2041,7 @@ def test_ap_wpa2_eap_tls_diff_ca_trust(dev, apdev):
 def test_ap_wpa2_eap_tls_diff_ca_trust2(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/PAP and different CA trust"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="pap user", anonymous_identity="ttls",
                    password="password", phase2="auth=PAP",
@@ -1491,7 +2068,7 @@ def test_ap_wpa2_eap_tls_diff_ca_trust2(dev, apdev):
 def test_ap_wpa2_eap_tls_diff_ca_trust3(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/PAP and different CA trust"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                         identity="pap user", anonymous_identity="ttls",
                         password="password", phase2="auth=PAP",
@@ -1513,8 +2090,9 @@ def test_ap_wpa2_eap_tls_diff_ca_trust3(dev, apdev):
 
 def test_ap_wpa2_eap_tls_neg_suffix_match(dev, apdev):
     """WPA2-Enterprise negative test - domain suffix mismatch"""
+    check_domain_suffix_match(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="DOMAIN\mschapv2 user", anonymous_identity="ttls",
                    password="password", phase2="auth=MSCHAPV2",
@@ -1522,7 +2100,7 @@ def test_ap_wpa2_eap_tls_neg_suffix_match(dev, apdev):
                    domain_suffix_match="incorrect.example.com",
                    wait_connect=False, scan_freq="2412")
 
-    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=10)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=16)
     if ev is None:
         raise Exception("Association and EAP start timed out")
 
@@ -1566,8 +2144,9 @@ def test_ap_wpa2_eap_tls_neg_suffix_match(dev, apdev):
 
 def test_ap_wpa2_eap_tls_neg_domain_match(dev, apdev):
     """WPA2-Enterprise negative test - domain mismatch"""
+    check_domain_match(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="DOMAIN\mschapv2 user", anonymous_identity="ttls",
                    password="password", phase2="auth=MSCHAPV2",
@@ -1575,7 +2154,7 @@ def test_ap_wpa2_eap_tls_neg_domain_match(dev, apdev):
                    domain_match="w1.fi",
                    wait_connect=False, scan_freq="2412")
 
-    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=10)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=16)
     if ev is None:
         raise Exception("Association and EAP start timed out")
 
@@ -1620,7 +2199,7 @@ def test_ap_wpa2_eap_tls_neg_domain_match(dev, apdev):
 def test_ap_wpa2_eap_tls_neg_subject_match(dev, apdev):
     """WPA2-Enterprise negative test - subject mismatch"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="DOMAIN\mschapv2 user", anonymous_identity="ttls",
                    password="password", phase2="auth=MSCHAPV2",
@@ -1628,7 +2207,7 @@ def test_ap_wpa2_eap_tls_neg_subject_match(dev, apdev):
                    subject_match="/C=FI/O=w1.fi/CN=example.com",
                    wait_connect=False, scan_freq="2412")
 
-    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=10)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=16)
     if ev is None:
         raise Exception("Association and EAP start timed out")
 
@@ -1680,7 +2259,7 @@ def test_ap_wpa2_eap_tls_neg_subject_match(dev, apdev):
 def test_ap_wpa2_eap_tls_neg_altsubject_match(dev, apdev):
     """WPA2-Enterprise negative test - altsubject mismatch"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     tests = [ "incorrect.example.com",
               "DNS:incorrect.example.com",
@@ -1697,7 +2276,7 @@ def _test_ap_wpa2_eap_tls_neg_altsubject_match(dev, apdev, match):
                    altsubject_match=match,
                    wait_connect=False, scan_freq="2412")
 
-    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=10)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=16)
     if ev is None:
         raise Exception("Association and EAP start timed out")
 
@@ -1751,8 +2330,8 @@ def _test_ap_wpa2_eap_tls_neg_altsubject_match(dev, apdev, match):
 def test_ap_wpa2_eap_unauth_tls(dev, apdev):
     """WPA2-Enterprise connection using UNAUTH-TLS"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "UNAUTH-TLS", "unauth-tls",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "UNAUTH-TLS", "unauth-tls",
                 ca_cert="auth_serv/ca.pem")
     eap_reauth(dev[0], "UNAUTH-TLS")
 
@@ -1760,13 +2339,13 @@ def test_ap_wpa2_eap_ttls_server_cert_hash(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS and server certificate hash"""
     check_cert_probe_support(dev[0])
     skip_with_fips(dev[0])
-    srv_cert_hash = "1477c9cd88391609444b83eca45c4f9f324e3051c5c31fc233ac6aede30ce7cd"
+    srv_cert_hash = "bdb9cb55d3df278e52a071abf58e7f0238fbec3ad8fb2c254742f63562628272"
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="probe", ca_cert="probe://",
                    wait_connect=False, scan_freq="2412")
-    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=10)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=16)
     if ev is None:
         raise Exception("Association and EAP start timed out")
     ev = dev[0].wait_event(["CTRL-EVENT-EAP-PEER-CERT depth=0"], timeout=10)
@@ -1787,7 +2366,7 @@ def test_ap_wpa2_eap_ttls_server_cert_hash(dev, apdev):
                    password="password", phase2="auth=MSCHAPV2",
                    ca_cert="hash://server/sha256/5a1bc1296205e6fdbe3979728efe3920798885c1c4590b5f90f43222d239ca6a",
                    wait_connect=False, scan_freq="2412")
-    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=10)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=16)
     if ev is None:
         raise Exception("Association and EAP start timed out")
     ev = dev[0].wait_event(["CTRL-EVENT-EAP-TLS-CERT-ERROR"], timeout=10)
@@ -1798,7 +2377,7 @@ def test_ap_wpa2_eap_ttls_server_cert_hash(dev, apdev):
     dev[0].wait_disconnected(timeout=10)
     dev[0].request("REMOVE_NETWORK all")
 
-    eap_connect(dev[0], apdev[0], "TTLS", "DOMAIN\mschapv2 user",
+    eap_connect(dev[0], hapd, "TTLS", "DOMAIN\mschapv2 user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="hash://server/sha256/" + srv_cert_hash,
                 phase2="auth=MSCHAPV2")
@@ -1806,7 +2385,7 @@ def test_ap_wpa2_eap_ttls_server_cert_hash(dev, apdev):
 def test_ap_wpa2_eap_ttls_server_cert_hash_invalid(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS and server certificate hash (invalid config)"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="DOMAIN\mschapv2 user", anonymous_identity="ttls",
                    password="password", phase2="auth=MSCHAPV2",
@@ -1823,7 +2402,7 @@ def test_ap_wpa2_eap_ttls_server_cert_hash_invalid(dev, apdev):
                    ca_cert="hash://server/sha256/5a1bc1296205e6fdbe3979728efe3920798885c1c4590b5f90f43222d239ca6Q",
                    wait_connect=False, scan_freq="2412")
     for i in range(0, 3):
-        ev = dev[i].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=10)
+        ev = dev[i].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=16)
         if ev is None:
             raise Exception("Association and EAP start timed out")
         ev = dev[i].wait_event(["EAP: Failed to initialize EAP method: vendor 0 method 21 (TTLS)"], timeout=5)
@@ -1834,21 +2413,21 @@ def test_ap_wpa2_eap_pwd(dev, apdev):
     """WPA2-Enterprise connection using EAP-pwd"""
     check_eap_capa(dev[0], "PWD")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "PWD", "pwd user", password="secret password")
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "PWD", "pwd user", password="secret password")
     eap_reauth(dev[0], "PWD")
     dev[0].request("REMOVE_NETWORK all")
 
-    eap_connect(dev[1], apdev[0], "PWD",
+    eap_connect(dev[1], hapd, "PWD",
                 "pwd.user@test123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890.example.com",
                 password="secret password",
                 fragment_size="90")
 
     logger.info("Negative test with incorrect password")
-    eap_connect(dev[2], apdev[0], "PWD", "pwd user", password="secret-password",
+    eap_connect(dev[2], hapd, "PWD", "pwd user", password="secret-password",
                 expect_failure=True, local_error_report=True)
 
-    eap_connect(dev[0], apdev[0], "PWD",
+    eap_connect(dev[0], hapd, "PWD",
                 "pwd.user@test123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890.example.com",
                 password="secret password",
                 fragment_size="31")
@@ -1858,11 +2437,11 @@ def test_ap_wpa2_eap_pwd_nthash(dev, apdev):
     check_eap_capa(dev[0], "PWD")
     skip_with_fips(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "PWD", "pwd-hash", password="secret password")
-    eap_connect(dev[1], apdev[0], "PWD", "pwd-hash",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "PWD", "pwd-hash", password="secret password")
+    eap_connect(dev[1], hapd, "PWD", "pwd-hash",
                 password_hex="hash:e3718ece8ab74792cbbfffd316d2d19a")
-    eap_connect(dev[2], apdev[0], "PWD", "pwd user",
+    eap_connect(dev[2], hapd, "PWD", "pwd user",
                 password_hex="hash:e3718ece8ab74792cbbfffd316d2d19a",
                 expect_failure=True, local_error_report=True)
 
@@ -1873,18 +2452,27 @@ def test_ap_wpa2_eap_pwd_groups(dev, apdev):
     params = { "ssid": "test-wpa2-eap", "wpa": "2", "wpa_key_mgmt": "WPA-EAP",
                "rsn_pairwise": "CCMP", "ieee8021x": "1",
                "eap_server": "1", "eap_user_file": "auth_serv/eap_user.conf" }
-    for i in [ 19, 20, 21, 25, 26 ]:
+    groups = [ 19, 20, 21, 25, 26 ]
+    if tls.startswith("OpenSSL") and "build=OpenSSL 1.0.2" in tls and "run=OpenSSL 1.0.2" in tls:
+        logger.info("Add Brainpool EC groups since OpenSSL is new enough")
+        groups += [ 27, 28, 29, 30 ]
+    for i in groups:
+        logger.info("Group %d" % i)
         params['pwd_group'] = str(i)
-        hostapd.add_ap(apdev[0]['ifname'], params)
-        dev[0].request("REMOVE_NETWORK all")
+        hapd = hostapd.add_ap(apdev[0], params)
         try:
-            eap_connect(dev[0], apdev[0], "PWD", "pwd user",
+            eap_connect(dev[0], hapd, "PWD", "pwd user",
                         password="secret password")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+            dev[0].dump_monitor()
         except:
             if "BoringSSL" in tls and i in [ 25 ]:
                 logger.info("Ignore connection failure with group %d with BoringSSL" % i)
                 dev[0].request("DISCONNECT")
                 time.sleep(0.1)
+                dev[0].request("REMOVE_NETWORK all")
+                dev[0].dump_monitor()
                 continue
             raise
 
@@ -1895,7 +2483,7 @@ def test_ap_wpa2_eap_pwd_invalid_group(dev, apdev):
                "rsn_pairwise": "CCMP", "ieee8021x": "1",
                "eap_server": "1", "eap_user_file": "auth_serv/eap_user.conf" }
     params['pwd_group'] = "0"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="PWD",
                    identity="pwd user", password="secret password",
                    scan_freq="2412", wait_connect=False)
@@ -1911,14 +2499,14 @@ def test_ap_wpa2_eap_pwd_as_frag(dev, apdev):
                "rsn_pairwise": "CCMP", "ieee8021x": "1",
                "eap_server": "1", "eap_user_file": "auth_serv/eap_user.conf",
                "pwd_group": "19", "fragment_size": "40" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "PWD", "pwd user", password="secret password")
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "PWD", "pwd user", password="secret password")
 
 def test_ap_wpa2_eap_gpsk(dev, apdev):
     """WPA2-Enterprise connection using EAP-GPSK"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    id = eap_connect(dev[0], apdev[0], "GPSK", "gpsk user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    id = eap_connect(dev[0], hapd, "GPSK", "gpsk user",
                      password="abcdefghijklmnop0123456789abcdef")
     eap_reauth(dev[0], "GPSK")
 
@@ -1938,29 +2526,29 @@ def test_ap_wpa2_eap_gpsk(dev, apdev):
 
     logger.info("Negative test with incorrect password")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "GPSK", "gpsk user",
+    eap_connect(dev[0], hapd, "GPSK", "gpsk user",
                 password="ffcdefghijklmnop0123456789abcdef",
                 expect_failure=True)
 
 def test_ap_wpa2_eap_sake(dev, apdev):
     """WPA2-Enterprise connection using EAP-SAKE"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "SAKE", "sake user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "SAKE", "sake user",
                 password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
     eap_reauth(dev[0], "SAKE")
 
     logger.info("Negative test with incorrect password")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "SAKE", "sake user",
+    eap_connect(dev[0], hapd, "SAKE", "sake user",
                 password_hex="ff23456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
                 expect_failure=True)
 
 def test_ap_wpa2_eap_eke(dev, apdev):
     """WPA2-Enterprise connection using EAP-EKE"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    id = eap_connect(dev[0], apdev[0], "EKE", "eke user", password="hello")
+    hapd = hostapd.add_ap(apdev[0], params)
+    id = eap_connect(dev[0], hapd, "EKE", "eke user", password="hello")
     eap_reauth(dev[0], "EKE")
 
     logger.info("Test forced algorithm selection")
@@ -1982,20 +2570,54 @@ def test_ap_wpa2_eap_eke(dev, apdev):
 
     logger.info("Negative test with incorrect password")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "EKE", "eke user", password="hello1",
+    eap_connect(dev[0], hapd, "EKE", "eke user", password="hello1",
                 expect_failure=True)
 
+def test_ap_wpa2_eap_eke_many(dev, apdev, params):
+    """WPA2-Enterprise connection using EAP-EKE (many connections) [long]"""
+    if not params['long']:
+        raise HwsimSkip("Skip test case with long duration due to --long not specified")
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0], params)
+    success = 0
+    fail = 0
+    for i in range(100):
+        for j in range(3):
+            dev[j].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="EKE",
+                           identity="eke user", password="hello",
+                           phase1="dhgroup=3 encr=1 prf=1 mac=1",
+                           scan_freq="2412", wait_connect=False)
+        for j in range(3):
+            ev = dev[j].wait_event(["CTRL-EVENT-CONNECTED",
+                                    "CTRL-EVENT-DISCONNECTED"], timeout=15)
+            if ev is None:
+                raise Exception("No connected/disconnected event")
+            if "CTRL-EVENT-DISCONNECTED" in ev:
+                fail += 1
+                # The RADIUS server limits on active sessions can be hit when
+                # going through this test case, so try to give some more time
+                # for the server to remove sessions.
+                logger.info("Failed to connect i=%d j=%d" % (i, j))
+                dev[j].request("REMOVE_NETWORK all")
+                time.sleep(1)
+            else:
+                success += 1
+                dev[j].request("REMOVE_NETWORK all")
+                dev[j].wait_disconnected()
+            dev[j].dump_monitor()
+    logger.info("Total success=%d failure=%d" % (success, fail))
+
 def test_ap_wpa2_eap_eke_serverid_nai(dev, apdev):
     """WPA2-Enterprise connection using EAP-EKE with serverid NAI"""
     params = int_eap_server_params()
     params['server_id'] = 'example.server@w1.fi'
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "EKE", "eke user", password="hello")
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "EKE", "eke user", password="hello")
 
 def test_ap_wpa2_eap_eke_server_oom(dev, apdev):
     """WPA2-Enterprise connection using EAP-EKE with server OOM"""
     params = int_eap_server_params()
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412)
 
     for count,func in [ (1, "eap_eke_build_commit"),
@@ -2011,7 +2633,7 @@ def test_ap_wpa2_eap_eke_server_oom(dev, apdev):
                         (3, "eap_eke_process_identity"),
                         (4, "eap_eke_process_identity") ]:
         with alloc_fail(hapd, count, func):
-            eap_connect(dev[0], apdev[0], "EKE", "eke user", password="hello",
+            eap_connect(dev[0], hapd, "EKE", "eke user", password="hello",
                         expect_failure=True)
             dev[0].request("REMOVE_NETWORK all")
 
@@ -2060,18 +2682,24 @@ def test_ap_wpa2_eap_ikev2(dev, apdev):
     """WPA2-Enterprise connection using EAP-IKEv2"""
     check_eap_capa(dev[0], "IKEV2")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "IKEV2", "ikev2 user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "IKEV2", "ikev2 user",
                 password="ike password")
     eap_reauth(dev[0], "IKEV2")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "IKEV2", "ikev2 user",
+    eap_connect(dev[0], hapd, "IKEV2", "ikev2 user",
                 password="ike password", fragment_size="50")
 
     logger.info("Negative test with incorrect password")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "IKEV2", "ikev2 user",
+    eap_connect(dev[0], hapd, "IKEV2", "ikev2 user",
                 password="ike-password", expect_failure=True)
+    dev[0].request("REMOVE_NETWORK all")
+
+    eap_connect(dev[0], hapd, "IKEV2", "ikev2 user",
+                password="ike password", fragment_size="0")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
 
 def test_ap_wpa2_eap_ikev2_as_frag(dev, apdev):
     """WPA2-Enterprise connection using EAP-IKEv2 with server fragmentation"""
@@ -2081,8 +2709,8 @@ def test_ap_wpa2_eap_ikev2_as_frag(dev, apdev):
                "rsn_pairwise": "CCMP", "ieee8021x": "1",
                "eap_server": "1", "eap_user_file": "auth_serv/eap_user.conf",
                "fragment_size": "50" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "IKEV2", "ikev2 user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "IKEV2", "ikev2 user",
                 password="ike password")
     eap_reauth(dev[0], "IKEV2")
 
@@ -2090,7 +2718,7 @@ def test_ap_wpa2_eap_ikev2_oom(dev, apdev):
     """WPA2-Enterprise connection using EAP-IKEv2 and OOM"""
     check_eap_capa(dev[0], "IKEV2")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     tests = [ (1, "dh_init"),
               (2, "dh_init"),
@@ -2127,14 +2755,14 @@ def test_ap_wpa2_eap_ikev2_oom(dev, apdev):
 def test_ap_wpa2_eap_pax(dev, apdev):
     """WPA2-Enterprise connection using EAP-PAX"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "PAX", "pax.user@example.com",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "PAX", "pax.user@example.com",
                 password_hex="0123456789abcdef0123456789abcdef")
     eap_reauth(dev[0], "PAX")
 
     logger.info("Negative test with incorrect password")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "PAX", "pax.user@example.com",
+    eap_connect(dev[0], hapd, "PAX", "pax.user@example.com",
                 password_hex="ff23456789abcdef0123456789abcdef",
                 expect_failure=True)
 
@@ -2143,8 +2771,8 @@ def test_ap_wpa2_eap_psk(dev, apdev):
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params["wpa_key_mgmt"] = "WPA-EAP-SHA256"
     params["ieee80211w"] = "2"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "PSK", "psk.user@example.com",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "PSK", "psk.user@example.com",
                 password_hex="0123456789abcdef0123456789abcdef", sha256=True)
     eap_reauth(dev[0], "PSK", sha256=True)
     check_mib(dev[0], [ ("dot11RSNAAuthenticationSuiteRequested", "00-0f-ac-5"),
@@ -2158,7 +2786,7 @@ def test_ap_wpa2_eap_psk(dev, apdev):
 
     logger.info("Negative test with incorrect password")
     dev[0].request("REMOVE_NETWORK all")
-    eap_connect(dev[0], apdev[0], "PSK", "psk.user@example.com",
+    eap_connect(dev[0], hapd, "PSK", "psk.user@example.com",
                 password_hex="ff23456789abcdef0123456789abcdef", sha256=True,
                 expect_failure=True)
 
@@ -2166,20 +2794,34 @@ def test_ap_wpa2_eap_psk_oom(dev, apdev):
     """WPA2-Enterprise connection using EAP-PSK and OOM"""
     skip_with_fips(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
+    tests = [ (1, "=aes_128_eax_encrypt"),
+              (1, "=aes_128_eax_decrypt") ]
+    for count, func in tests:
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="PSK",
+                           identity="psk.user@example.com",
+                           password_hex="0123456789abcdef0123456789abcdef",
+                           wait_connect=False, scan_freq="2412")
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
+            if ev is None:
+                raise Exception("EAP method not selected")
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL",
+                              note="Failure not triggered: %d:%s" % (count, func))
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
     tests = [ (1, "aes_128_ctr_encrypt;aes_128_eax_encrypt"),
               (1, "omac1_aes_128;aes_128_eax_encrypt"),
               (2, "omac1_aes_128;aes_128_eax_encrypt"),
               (3, "omac1_aes_128;aes_128_eax_encrypt"),
-              (1, "=aes_128_eax_encrypt"),
               (1, "omac1_aes_vector"),
-              (1, "aes_128_ctr_encrypt;aes_128_eax_decrypt"),
               (1, "omac1_aes_128;aes_128_eax_decrypt"),
               (2, "omac1_aes_128;aes_128_eax_decrypt"),
               (3, "omac1_aes_128;aes_128_eax_decrypt"),
-              (1, "=aes_128_eax_decrypt") ]
+              (1, "aes_128_ctr_encrypt;aes_128_eax_decrypt") ]
     for count, func in tests:
-        with alloc_fail(dev[0], count, func):
+        with fail_test(dev[0], count, func):
             dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="PSK",
                            identity="psk.user@example.com",
                            password_hex="0123456789abcdef0123456789abcdef",
@@ -2187,13 +2829,12 @@ def test_ap_wpa2_eap_psk_oom(dev, apdev):
             ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
             if ev is None:
                 raise Exception("EAP method not selected")
-            for i in range(10):
-                if "0:" in dev[0].request("GET_ALLOC_FAIL"):
-                    break
-                time.sleep(0.02)
+            wait_fail_trigger(dev[0], "GET_FAIL",
+                              note="Failure not triggered: %d:%s" % (count, func))
             dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
 
-    with alloc_fail(dev[0], 1, "aes_128_encrypt_block"):
+    with fail_test(dev[0], 1, "aes_128_encrypt_block"):
             dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="PSK",
                            identity="psk.user@example.com",
                            password_hex="0123456789abcdef0123456789abcdef",
@@ -2202,12 +2843,13 @@ def test_ap_wpa2_eap_psk_oom(dev, apdev):
             if ev is None:
                 raise Exception("EAP method failure not reported")
             dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
 
 def test_ap_wpa_eap_peap_eap_mschapv2(dev, apdev):
     """WPA-Enterprise connection using EAP-PEAP/EAP-MSCHAPv2"""
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hostapd.wpa_eap_params(ssid="test-wpa-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa-eap", key_mgmt="WPA-EAP", eap="PEAP",
                    identity="user", password="password", phase2="auth=MSCHAPV2",
                    ca_cert="auth_serv/ca.pem", wait_connect=False,
@@ -2231,8 +2873,7 @@ def test_ap_wpa2_eap_interactive(dev, apdev):
     """WPA2-Enterprise connection using interactive identity/password entry"""
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
 
     tests = [ ("Connection with dynamic TTLS/MSCHAPv2 password entry",
                "TTLS", "ttls", "DOMAIN\mschapv2 user", "auth=MSCHAPV2",
@@ -2273,8 +2914,7 @@ def test_ap_wpa2_eap_ext_enable_network_while_connected(dev, apdev):
     """WPA2-Enterprise interactive identity entry and ENABLE_NETWORK"""
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
 
     id_other = dev[0].connect("other", key_mgmt="NONE", scan_freq="2412",
                               only_add_network=True)
@@ -2302,18 +2942,36 @@ def test_ap_wpa2_eap_ext_enable_network_while_connected(dev, apdev):
 def test_ap_wpa2_eap_vendor_test(dev, apdev):
     """WPA2-Enterprise connection using EAP vendor test"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "VENDOR-TEST", "vendor-test")
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "VENDOR-TEST", "vendor-test")
     eap_reauth(dev[0], "VENDOR-TEST")
-    eap_connect(dev[1], apdev[0], "VENDOR-TEST", "vendor-test",
+    eap_connect(dev[1], hapd, "VENDOR-TEST", "vendor-test",
                 password="pending")
 
+def test_ap_wpa2_eap_vendor_test_oom(dev, apdev):
+    """WPA2-Enterprise connection using EAP vendor test (OOM)"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0], params)
+
+    tests = [ "eap_vendor_test_init",
+              "eap_msg_alloc;eap_vendor_test_process",
+              "eap_vendor_test_getKey" ]
+    for func in tests:
+        with alloc_fail(dev[0], 1, func):
+            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
+                           scan_freq="2412",
+                           eap="VENDOR-TEST", identity="vendor-test",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
 def test_ap_wpa2_eap_fast_mschapv2_unauth_prov(dev, apdev):
     """WPA2-Enterprise connection using EAP-FAST/MSCHAPv2 and unauthenticated provisioning"""
     check_eap_capa(dev[0], "FAST")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "FAST", "user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "FAST", "user",
                 anonymous_identity="FAST", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                 phase1="fast_provisioning=1", pac_file="blob://fast_pac")
@@ -2328,10 +2986,10 @@ def test_ap_wpa2_eap_fast_pac_file(dev, apdev, params):
     pac_file = os.path.join(params['logdir'], "fast.pac")
     pac_file2 = os.path.join(params['logdir'], "fast-bin.pac")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     try:
-        eap_connect(dev[0], apdev[0], "FAST", "user",
+        eap_connect(dev[0], hapd, "FAST", "user",
                     anonymous_identity="FAST", password="password",
                     ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                     phase1="fast_provisioning=1", pac_file=pac_file)
@@ -2342,18 +3000,18 @@ def test_ap_wpa2_eap_fast_pac_file(dev, apdev, params):
             if "PAC-Key=" not in data:
                 raise Exception("PAC-Key missing from PAC file")
         dev[0].request("REMOVE_NETWORK all")
-        eap_connect(dev[0], apdev[0], "FAST", "user",
+        eap_connect(dev[0], hapd, "FAST", "user",
                     anonymous_identity="FAST", password="password",
                     ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                     pac_file=pac_file)
 
-        eap_connect(dev[1], apdev[0], "FAST", "user",
+        eap_connect(dev[1], hapd, "FAST", "user",
                     anonymous_identity="FAST", password="password",
                     ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                     phase1="fast_provisioning=1 fast_pac_format=binary",
                     pac_file=pac_file2)
         dev[1].request("REMOVE_NETWORK all")
-        eap_connect(dev[1], apdev[0], "FAST", "user",
+        eap_connect(dev[1], hapd, "FAST", "user",
                     anonymous_identity="FAST", password="password",
                     ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                     phase1="fast_pac_format=binary",
@@ -2372,8 +3030,8 @@ def test_ap_wpa2_eap_fast_binary_pac(dev, apdev):
     """WPA2-Enterprise connection using EAP-FAST and binary PAC format"""
     check_eap_capa(dev[0], "FAST")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "FAST", "user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "FAST", "user",
                 anonymous_identity="FAST", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                 phase1="fast_provisioning=1 fast_max_pac_list_len=1 fast_pac_format=binary",
@@ -2382,11 +3040,20 @@ def test_ap_wpa2_eap_fast_binary_pac(dev, apdev):
     if res['tls_session_reused'] != '1':
         raise Exception("EAP-FAST could not use PAC session ticket")
 
+    # Verify fast_max_pac_list_len=0 special case
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+    eap_connect(dev[0], hapd, "FAST", "user",
+                anonymous_identity="FAST", password="password",
+                ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                phase1="fast_provisioning=1 fast_max_pac_list_len=0 fast_pac_format=binary",
+                pac_file="blob://fast_pac_bin")
+
 def test_ap_wpa2_eap_fast_missing_pac_config(dev, apdev):
     """WPA2-Enterprise connection using EAP-FAST and missing PAC config"""
     check_eap_capa(dev[0], "FAST")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="FAST",
                    identity="user", anonymous_identity="FAST",
@@ -2408,12 +3075,297 @@ def test_ap_wpa2_eap_fast_missing_pac_config(dev, apdev):
     if ev is None:
         raise Exception("Timeout on EAP failure report")
 
+def test_ap_wpa2_eap_fast_binary_pac_errors(dev, apdev):
+    """EAP-FAST and binary PAC errors"""
+    check_eap_capa(dev[0], "FAST")
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    tests = [ (1, "=eap_fast_save_pac_bin"),
+              (1, "eap_fast_write_pac"),
+              (2, "eap_fast_write_pac"), ]
+    for count, func in tests:
+        if "OK" not in dev[0].request("SET blob fast_pac_bin_errors "):
+            raise Exception("Could not set blob")
+
+        with alloc_fail(dev[0], count, func):
+            eap_connect(dev[0], hapd, "FAST", "user",
+                        anonymous_identity="FAST", password="password",
+                        ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                        phase1="fast_provisioning=1 fast_pac_format=binary",
+                        pac_file="blob://fast_pac_bin_errors")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ "00", "000000000000", "6ae4920c0001",
+              "6ae4920c000000",
+              "6ae4920c0000" + "0000" + 32*"00" + "ffff" + "0000",
+              "6ae4920c0000" + "0000" + 32*"00" + "0001" + "0000",
+              "6ae4920c0000" + "0000" + 32*"00" + "0000" + "0001",
+              "6ae4920c0000" + "0000" + 32*"00" + "0000" + "0008" + "00040000" + "0007000100"]
+    for t in tests:
+        if "OK" not in dev[0].request("SET blob fast_pac_bin_errors " + t):
+            raise Exception("Could not set blob")
+
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="FAST",
+                       identity="user", anonymous_identity="FAST",
+                       password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                       phase1="fast_provisioning=1 fast_pac_format=binary",
+                       pac_file="blob://fast_pac_bin_errors",
+                       scan_freq="2412", wait_connect=False)
+        ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
+                               timeout=5)
+        if ev is None:
+            raise Exception("Failure not reported")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    pac = "6ae4920c0000" + "0000" + 32*"00" + "0000" + "0000"
+    tests = [ (1, "eap_fast_load_pac_bin"),
+              (2, "eap_fast_load_pac_bin"),
+              (3, "eap_fast_load_pac_bin") ]
+    for count, func in tests:
+        if "OK" not in dev[0].request("SET blob fast_pac_bin_errors " + pac):
+            raise Exception("Could not set blob")
+
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="FAST",
+                           identity="user", anonymous_identity="FAST",
+                           password="password",
+                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                           phase1="fast_provisioning=1 fast_pac_format=binary",
+                           pac_file="blob://fast_pac_bin_errors",
+                           scan_freq="2412", wait_connect=False)
+            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
+                                   timeout=5)
+            if ev is None:
+                raise Exception("Failure not reported")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    pac = "6ae4920c0000" + "0000" + 32*"00" + "0000" + "0005" + "0011223344"
+    if "OK" not in dev[0].request("SET blob fast_pac_bin_errors " + pac):
+        raise Exception("Could not set blob")
+
+    eap_connect(dev[0], hapd, "FAST", "user",
+                anonymous_identity="FAST", password="password",
+                ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                phase1="fast_provisioning=1 fast_pac_format=binary",
+                pac_file="blob://fast_pac_bin_errors")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+    pac = "6ae4920c0000" + "0000" + 32*"00" + "0000" + "0009" + "00040000" + "0007000100"
+    tests = [ (1, "eap_fast_pac_get_a_id"),
+              (2, "eap_fast_pac_get_a_id") ]
+    for count, func in tests:
+        if "OK" not in dev[0].request("SET blob fast_pac_bin_errors " + pac):
+            raise Exception("Could not set blob")
+        with alloc_fail(dev[0], count, func):
+            eap_connect(dev[0], hapd, "FAST", "user",
+                        anonymous_identity="FAST", password="password",
+                        ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                        phase1="fast_provisioning=1 fast_pac_format=binary",
+                        pac_file="blob://fast_pac_bin_errors")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+def test_ap_wpa2_eap_fast_text_pac_errors(dev, apdev):
+    """EAP-FAST and text PAC errors"""
+    check_eap_capa(dev[0], "FAST")
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0], params)
+
+    tests = [ (1, "eap_fast_parse_hex;eap_fast_parse_pac_key"),
+              (1, "eap_fast_parse_hex;eap_fast_parse_pac_opaque"),
+              (1, "eap_fast_parse_hex;eap_fast_parse_a_id"),
+              (1, "eap_fast_parse_start"),
+              (1, "eap_fast_save_pac") ]
+    for count, func in tests:
+        dev[0].request("FLUSH")
+        if "OK" not in dev[0].request("SET blob fast_pac_text_errors "):
+            raise Exception("Could not set blob")
+
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="FAST",
+                           identity="user", anonymous_identity="FAST",
+                           password="password",
+                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                           phase1="fast_provisioning=1",
+                           pac_file="blob://fast_pac_text_errors",
+                           scan_freq="2412", wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    pac = "wpa_supplicant EAP-FAST PAC file - version 1\n"
+    pac += "START\n"
+    pac += "PAC-Type\n"
+    pac += "END\n"
+    if "OK" not in dev[0].request("SET blob fast_pac_text_errors " + pac.encode("hex")):
+        raise Exception("Could not set blob")
+
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="FAST",
+                   identity="user", anonymous_identity="FAST",
+                   password="password",
+                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                   phase1="fast_provisioning=1",
+                   pac_file="blob://fast_pac_text_errors",
+                   scan_freq="2412", wait_connect=False)
+    ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"], timeout=5)
+    if ev is None:
+        raise Exception("Failure not reported")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+    dev[0].request("FLUSH")
+    if "OK" not in dev[0].request("SET blob fast_pac_text_errors "):
+        raise Exception("Could not set blob")
+
+    with alloc_fail(dev[0], 1, "eap_fast_add_pac_data"):
+        for i in range(3):
+            params = int_eap_server_params()
+            params['ssid'] = "test-wpa2-eap-2"
+            params['pac_opaque_encr_key'] = "000102030405060708090a0b0c0dff%02x" % i
+            params['eap_fast_a_id'] = "101112131415161718191a1b1c1dff%02x" % i
+            params['eap_fast_a_id_info'] = "test server %d" % i
+
+            hapd2 = hostapd.add_ap(apdev[1], params)
+
+            dev[0].connect("test-wpa2-eap-2", key_mgmt="WPA-EAP", eap="FAST",
+                           identity="user", anonymous_identity="FAST",
+                           password="password",
+                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                           phase1="fast_provisioning=1",
+                           pac_file="blob://fast_pac_text_errors",
+                           scan_freq="2412", wait_connect=False)
+            dev[0].wait_connected()
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+            hapd2.disable()
+
+def test_ap_wpa2_eap_fast_pac_truncate(dev, apdev):
+    """EAP-FAST and PAC list truncation"""
+    check_eap_capa(dev[0], "FAST")
+    if "OK" not in dev[0].request("SET blob fast_pac_truncate "):
+        raise Exception("Could not set blob")
+    for i in range(5):
+        params = int_eap_server_params()
+        params['pac_opaque_encr_key'] = "000102030405060708090a0b0c0dff%02x" % i
+        params['eap_fast_a_id'] = "101112131415161718191a1b1c1dff%02x" % i
+        params['eap_fast_a_id_info'] = "test server %d" % i
+        hapd = hostapd.add_ap(apdev[0], params)
+
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="FAST",
+                       identity="user", anonymous_identity="FAST",
+                       password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                       phase1="fast_provisioning=1 fast_max_pac_list_len=2",
+                       pac_file="blob://fast_pac_truncate",
+                       scan_freq="2412", wait_connect=False)
+        dev[0].wait_connected()
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+        hapd.disable()
+
+def test_ap_wpa2_eap_fast_pac_refresh(dev, apdev):
+    """EAP-FAST and PAC refresh"""
+    check_eap_capa(dev[0], "FAST")
+    if "OK" not in dev[0].request("SET blob fast_pac_refresh "):
+        raise Exception("Could not set blob")
+    for i in range(2):
+        params = int_eap_server_params()
+        params['pac_opaque_encr_key'] = "000102030405060708090a0b0c0dff%02x" % i
+        params['eap_fast_a_id'] = "101112131415161718191a1b1c1dff%02x" % i
+        params['eap_fast_a_id_info'] = "test server %d" % i
+        params['pac_key_refresh_time'] = "1"
+        params['pac_key_lifetime'] = "10"
+        hapd = hostapd.add_ap(apdev[0], params)
+
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="FAST",
+                       identity="user", anonymous_identity="FAST",
+                       password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                       phase1="fast_provisioning=1",
+                       pac_file="blob://fast_pac_refresh",
+                       scan_freq="2412", wait_connect=False)
+        dev[0].wait_connected()
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+        hapd.disable()
+
+    for i in range(2):
+        params = int_eap_server_params()
+        params['pac_opaque_encr_key'] = "000102030405060708090a0b0c0dff%02x" % i
+        params['eap_fast_a_id'] = "101112131415161718191a1b1c1dff%02x" % i
+        params['eap_fast_a_id_info'] = "test server %d" % i
+        params['pac_key_refresh_time'] = "10"
+        params['pac_key_lifetime'] = "10"
+        hapd = hostapd.add_ap(apdev[0], params)
+
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="FAST",
+                       identity="user", anonymous_identity="FAST",
+                       password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                       phase1="fast_provisioning=1",
+                       pac_file="blob://fast_pac_refresh",
+                       scan_freq="2412", wait_connect=False)
+        dev[0].wait_connected()
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+        hapd.disable()
+
+def test_ap_wpa2_eap_fast_pac_lifetime(dev, apdev):
+    """EAP-FAST and PAC lifetime"""
+    check_eap_capa(dev[0], "FAST")
+    if "OK" not in dev[0].request("SET blob fast_pac_refresh "):
+        raise Exception("Could not set blob")
+
+    i = 0
+    params = int_eap_server_params()
+    params['pac_opaque_encr_key'] = "000102030405060708090a0b0c0dff%02x" % i
+    params['eap_fast_a_id'] = "101112131415161718191a1b1c1dff%02x" % i
+    params['eap_fast_a_id_info'] = "test server %d" % i
+    params['pac_key_refresh_time'] = "0"
+    params['pac_key_lifetime'] = "2"
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="FAST",
+                        identity="user", anonymous_identity="FAST",
+                        password="password",
+                        ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                        phase1="fast_provisioning=2",
+                        pac_file="blob://fast_pac_refresh",
+                        scan_freq="2412", wait_connect=False)
+    dev[0].wait_connected()
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+    time.sleep(3)
+    dev[0].request("PMKSA_FLUSH")
+    dev[0].request("RECONNECT")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=10)
+    if ev is None:
+        raise Exception("No EAP-Failure seen after expired PAC")
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+    dev[0].select_network(id)
+    dev[0].wait_connected()
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
 def test_ap_wpa2_eap_fast_gtc_auth_prov(dev, apdev):
     """WPA2-Enterprise connection using EAP-FAST/GTC and authenticated provisioning"""
     check_eap_capa(dev[0], "FAST")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "FAST", "user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "FAST", "user",
                 anonymous_identity="FAST", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
                 phase1="fast_provisioning=2", pac_file="blob://fast_pac_auth")
@@ -2426,8 +3378,8 @@ def test_ap_wpa2_eap_fast_gtc_identity_change(dev, apdev):
     """WPA2-Enterprise connection using EAP-FAST/GTC and identity changing"""
     check_eap_capa(dev[0], "FAST")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    id = eap_connect(dev[0], apdev[0], "FAST", "user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    id = eap_connect(dev[0], hapd, "FAST", "user",
                      anonymous_identity="FAST", password="password",
                      ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
                      phase1="fast_provisioning=2",
@@ -2445,9 +3397,18 @@ def test_ap_wpa2_eap_fast_gtc_identity_change(dev, apdev):
 def test_ap_wpa2_eap_fast_prf_oom(dev, apdev):
     """WPA2-Enterprise connection using EAP-FAST and OOM in PRF"""
     check_eap_capa(dev[0], "FAST")
+    tls = dev[0].request("GET tls_library")
+    if tls.startswith("OpenSSL"):
+        func = "tls_connection_get_eap_fast_key"
+        count = 2
+    elif tls.startswith("internal"):
+        func = "tls_connection_prf"
+        count = 1
+    else:
+        raise HwsimSkip("Unsupported TLS library")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    with alloc_fail(dev[0], 2, "openssl_tls_prf"):
+    hapd = hostapd.add_ap(apdev[0], params)
+    with alloc_fail(dev[0], count, func):
         dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="FAST",
                        identity="user", anonymous_identity="FAST",
                        password="password", ca_cert="auth_serv/ca.pem",
@@ -2469,10 +3430,10 @@ def test_ap_wpa2_eap_fast_server_oom(dev, apdev):
     params['pac_opaque_encr_key'] = '000102030405060708090a0b0c0d0e0f'
     params['eap_fast_a_id'] = '1011'
     params['eap_fast_a_id_info'] = 'another test server'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     with alloc_fail(hapd, 1, "tls_session_ticket_ext_cb"):
-        id = eap_connect(dev[0], apdev[0], "FAST", "user",
+        id = eap_connect(dev[0], hapd, "FAST", "user",
                          anonymous_identity="FAST", password="password",
                          ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                          phase1="fast_provisioning=1",
@@ -2486,12 +3447,75 @@ def test_ap_wpa2_eap_fast_server_oom(dev, apdev):
 
     dev[0].select_network(id, freq="2412")
 
+def test_ap_wpa2_eap_fast_cipher_suites(dev, apdev):
+    """EAP-FAST and different TLS cipher suites"""
+    check_eap_capa(dev[0], "FAST")
+    tls = dev[0].request("GET tls_library")
+    if not tls.startswith("OpenSSL"):
+        raise HwsimSkip("TLS library is not OpenSSL: " + tls)
+
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].request("SET blob fast_pac_ciphers ")
+    eap_connect(dev[0], hapd, "FAST", "user",
+                anonymous_identity="FAST", password="password",
+                ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
+                phase1="fast_provisioning=2",
+                pac_file="blob://fast_pac_ciphers")
+    res = dev[0].get_status_field('EAP TLS cipher')
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+    if res != "DHE-RSA-AES256-SHA":
+        raise Exception("Unexpected cipher suite for provisioning: " + res)
+
+    tests = [ "DHE-RSA-AES128-SHA",
+              "RC4-SHA",
+              "AES128-SHA",
+              "AES256-SHA",
+              "DHE-RSA-AES256-SHA" ]
+    for cipher in tests:
+        dev[0].dump_monitor()
+        logger.info("Testing " + cipher)
+        try:
+            eap_connect(dev[0], hapd, "FAST", "user",
+                        openssl_ciphers=cipher,
+                        anonymous_identity="FAST", password="password",
+                        ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
+                        pac_file="blob://fast_pac_ciphers")
+        except Exception, e:
+            if "Could not select EAP method" in str(e) and cipher == "RC4-SHA":
+                tls = dev[0].request("GET tls_library")
+                if "run=OpenSSL 1.1" in tls:
+                    logger.info("Allow failure due to missing TLS library support")
+                    dev[0].request("REMOVE_NETWORK all")
+                    dev[0].wait_disconnected()
+                    continue
+            raise
+        res = dev[0].get_status_field('EAP TLS cipher')
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+        if res != cipher:
+            raise Exception("Unexpected TLS cipher info (configured %s): %s" % (cipher, res))
+
 def test_ap_wpa2_eap_tls_ocsp(dev, apdev):
     """WPA2-Enterprise connection using EAP-TLS and verifying OCSP"""
     check_ocsp_support(dev[0])
+    check_pkcs12_support(dev[0])
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
+                private_key="auth_serv/user.pkcs12",
+                private_key_passwd="whatever", ocsp=2)
+
+def test_ap_wpa2_eap_tls_ocsp_multi(dev, apdev):
+    """WPA2-Enterprise connection using EAP-TLS and verifying OCSP-multi"""
+    check_ocsp_multi_support(dev[0])
+    check_pkcs12_support(dev[0])
+
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TLS", "tls user", ca_cert="auth_serv/ca.pem",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
                 private_key="auth_serv/user.pkcs12",
                 private_key_passwd="whatever", ocsp=2)
 
@@ -2501,15 +3525,135 @@ def int_eap_server_params():
                "eap_server": "1", "eap_user_file": "auth_serv/eap_user.conf",
                "ca_cert": "auth_serv/ca.pem",
                "server_cert": "auth_serv/server.pem",
-               "private_key": "auth_serv/server.key" }
+               "private_key": "auth_serv/server.key",
+               "dh_file": "auth_serv/dh.conf" }
     return params
 
+def test_ap_wpa2_eap_tls_ocsp_key_id(dev, apdev, params):
+    """EAP-TLS and OCSP certificate signed OCSP response using key ID"""
+    check_ocsp_support(dev[0])
+    ocsp = os.path.join(params['logdir'], "ocsp-server-cache-key-id.der")
+    if not os.path.exists(ocsp):
+        raise HwsimSkip("No OCSP response available")
+    params = int_eap_server_params()
+    params["ocsp_stapling_response"] = ocsp
+    hostapd.add_ap(apdev[0], params)
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                   identity="tls user", ca_cert="auth_serv/ca.pem",
+                   private_key="auth_serv/user.pkcs12",
+                   private_key_passwd="whatever", ocsp=2,
+                   scan_freq="2412")
+
+def test_ap_wpa2_eap_tls_ocsp_ca_signed_good(dev, apdev, params):
+    """EAP-TLS and CA signed OCSP response (good)"""
+    check_ocsp_support(dev[0])
+    ocsp = os.path.join(params['logdir'], "ocsp-resp-ca-signed.der")
+    if not os.path.exists(ocsp):
+        raise HwsimSkip("No OCSP response available")
+    params = int_eap_server_params()
+    params["ocsp_stapling_response"] = ocsp
+    hostapd.add_ap(apdev[0], params)
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                   identity="tls user", ca_cert="auth_serv/ca.pem",
+                   private_key="auth_serv/user.pkcs12",
+                   private_key_passwd="whatever", ocsp=2,
+                   scan_freq="2412")
+
+def test_ap_wpa2_eap_tls_ocsp_ca_signed_revoked(dev, apdev, params):
+    """EAP-TLS and CA signed OCSP response (revoked)"""
+    check_ocsp_support(dev[0])
+    ocsp = os.path.join(params['logdir'], "ocsp-resp-ca-signed-revoked.der")
+    if not os.path.exists(ocsp):
+        raise HwsimSkip("No OCSP response available")
+    params = int_eap_server_params()
+    params["ocsp_stapling_response"] = ocsp
+    hostapd.add_ap(apdev[0], params)
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                   identity="tls user", ca_cert="auth_serv/ca.pem",
+                   private_key="auth_serv/user.pkcs12",
+                   private_key_passwd="whatever", ocsp=2,
+                   wait_connect=False, scan_freq="2412")
+    count = 0
+    while True:
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STATUS"])
+        if ev is None:
+            raise Exception("Timeout on EAP status")
+        if 'bad certificate status response' in ev:
+            break
+        if 'certificate revoked' in ev:
+            break
+        count = count + 1
+        if count > 10:
+            raise Exception("Unexpected number of EAP status messages")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"])
+    if ev is None:
+        raise Exception("Timeout on EAP failure report")
+
+def test_ap_wpa2_eap_tls_ocsp_ca_signed_unknown(dev, apdev, params):
+    """EAP-TLS and CA signed OCSP response (unknown)"""
+    check_ocsp_support(dev[0])
+    ocsp = os.path.join(params['logdir'], "ocsp-resp-ca-signed-unknown.der")
+    if not os.path.exists(ocsp):
+        raise HwsimSkip("No OCSP response available")
+    params = int_eap_server_params()
+    params["ocsp_stapling_response"] = ocsp
+    hostapd.add_ap(apdev[0], params)
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                   identity="tls user", ca_cert="auth_serv/ca.pem",
+                   private_key="auth_serv/user.pkcs12",
+                   private_key_passwd="whatever", ocsp=2,
+                   wait_connect=False, scan_freq="2412")
+    count = 0
+    while True:
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STATUS"])
+        if ev is None:
+            raise Exception("Timeout on EAP status")
+        if 'bad certificate status response' in ev:
+            break
+        count = count + 1
+        if count > 10:
+            raise Exception("Unexpected number of EAP status messages")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"])
+    if ev is None:
+        raise Exception("Timeout on EAP failure report")
+
+def test_ap_wpa2_eap_tls_ocsp_server_signed(dev, apdev, params):
+    """EAP-TLS and server signed OCSP response"""
+    check_ocsp_support(dev[0])
+    ocsp = os.path.join(params['logdir'], "ocsp-resp-server-signed.der")
+    if not os.path.exists(ocsp):
+        raise HwsimSkip("No OCSP response available")
+    params = int_eap_server_params()
+    params["ocsp_stapling_response"] = ocsp
+    hostapd.add_ap(apdev[0], params)
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                   identity="tls user", ca_cert="auth_serv/ca.pem",
+                   private_key="auth_serv/user.pkcs12",
+                   private_key_passwd="whatever", ocsp=2,
+                   wait_connect=False, scan_freq="2412")
+    count = 0
+    while True:
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STATUS"])
+        if ev is None:
+            raise Exception("Timeout on EAP status")
+        if 'bad certificate status response' in ev:
+            break
+        count = count + 1
+        if count > 10:
+            raise Exception("Unexpected number of EAP status messages")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"])
+    if ev is None:
+        raise Exception("Timeout on EAP failure report")
+
 def test_ap_wpa2_eap_tls_ocsp_invalid_data(dev, apdev):
     """WPA2-Enterprise connection using EAP-TLS and invalid OCSP data"""
     check_ocsp_support(dev[0])
     params = int_eap_server_params()
     params["ocsp_stapling_response"] = "auth_serv/ocsp-req.der"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
                    identity="tls user", ca_cert="auth_serv/ca.pem",
                    private_key="auth_serv/user.pkcs12",
@@ -2535,7 +3679,7 @@ def test_ap_wpa2_eap_tls_ocsp_invalid(dev, apdev):
     check_ocsp_support(dev[0])
     params = int_eap_server_params()
     params["ocsp_stapling_response"] = "auth_serv/ocsp-server-cache.der-invalid"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
                    identity="tls user", ca_cert="auth_serv/ca.pem",
                    private_key="auth_serv/user.pkcs12",
@@ -2561,7 +3705,7 @@ def test_ap_wpa2_eap_tls_ocsp_unknown_sign(dev, apdev):
     check_ocsp_support(dev[0])
     params = int_eap_server_params()
     params["ocsp_stapling_response"] = "auth_serv/ocsp-server-cache.der-unknown-sign"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
                    identity="tls user", ca_cert="auth_serv/ca.pem",
                    private_key="auth_serv/user.pkcs12",
@@ -2590,7 +3734,7 @@ def test_ap_wpa2_eap_ttls_ocsp_revoked(dev, apdev, params):
         raise HwsimSkip("No OCSP response available")
     params = int_eap_server_params()
     params["ocsp_stapling_response"] = ocsp
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="pap user", ca_cert="auth_serv/ca.pem",
                    anonymous_identity="ttls", password="password",
@@ -2621,7 +3765,7 @@ def test_ap_wpa2_eap_ttls_ocsp_unknown(dev, apdev, params):
         raise HwsimSkip("No OCSP response available")
     params = int_eap_server_params()
     params["ocsp_stapling_response"] = ocsp
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="pap user", ca_cert="auth_serv/ca.pem",
                    anonymous_identity="ttls", password="password",
@@ -2642,25 +3786,309 @@ def test_ap_wpa2_eap_ttls_ocsp_unknown(dev, apdev, params):
     if ev is None:
         raise Exception("Timeout on EAP failure report")
 
-def test_ap_wpa2_eap_ttls_optional_ocsp_unknown(dev, apdev, params):
-    """WPA2-Enterprise connection using EAP-TTLS and OCSP status revoked"""
-    ocsp = os.path.join(params['logdir'], "ocsp-server-cache-unknown.der")
-    if not os.path.exists(ocsp):
-        raise HwsimSkip("No OCSP response available")
+def test_ap_wpa2_eap_ttls_optional_ocsp_unknown(dev, apdev, params):
+    """WPA2-Enterprise connection using EAP-TTLS and OCSP status revoked"""
+    ocsp = os.path.join(params['logdir'], "ocsp-server-cache-unknown.der")
+    if not os.path.exists(ocsp):
+        raise HwsimSkip("No OCSP response available")
+    params = int_eap_server_params()
+    params["ocsp_stapling_response"] = ocsp
+    hostapd.add_ap(apdev[0], params)
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                   identity="pap user", ca_cert="auth_serv/ca.pem",
+                   anonymous_identity="ttls", password="password",
+                   phase2="auth=PAP", ocsp=1, scan_freq="2412")
+
+def test_ap_wpa2_eap_tls_intermediate_ca(dev, apdev, params):
+    """EAP-TLS with intermediate server/user CA"""
+    params = int_eap_server_params()
+    params["ca_cert"] = "auth_serv/iCA-server/ca-and-root.pem"
+    params["server_cert"] = "auth_serv/iCA-server/server.pem"
+    params["private_key"] = "auth_serv/iCA-server/server.key"
+    hostapd.add_ap(apdev[0], params)
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                   identity="tls user",
+                   ca_cert="auth_serv/iCA-user/ca-and-root.pem",
+                   client_cert="auth_serv/iCA-user/user.pem",
+                   private_key="auth_serv/iCA-user/user.key",
+                   scan_freq="2412")
+
+def root_ocsp(cert):
+    ca = "auth_serv/ca.pem"
+
+    fd2, fn2 = tempfile.mkstemp()
+    os.close(fd2)
+
+    arg = [ "openssl", "ocsp", "-reqout", fn2, "-issuer", ca, "-cert", cert,
+            "-no_nonce", "-sha256", "-text" ]
+    cmd = subprocess.Popen(arg, stdout=subprocess.PIPE,
+                           stderr=subprocess.PIPE)
+    res = cmd.stdout.read() + "\n" + cmd.stderr.read()
+    cmd.stdout.close()
+    cmd.stderr.close()
+    logger.info("OCSP request:\n" + res)
+
+    fd, fn = tempfile.mkstemp()
+    os.close(fd)
+    arg = [ "openssl", "ocsp", "-index", "auth_serv/rootCA/index.txt",
+            "-rsigner", ca, "-rkey", "auth_serv/ca-key.pem",
+            "-CA", ca, "-issuer", ca, "-verify_other", ca, "-trust_other",
+            "-ndays", "7", "-reqin", fn2, "-resp_no_certs", "-respout", fn,
+            "-text" ]
+    cmd = subprocess.Popen(arg, stdout=subprocess.PIPE,
+                           stderr=subprocess.PIPE)
+    res = cmd.stdout.read() + "\n" + cmd.stderr.read()
+    cmd.stdout.close()
+    cmd.stderr.close()
+    logger.info("OCSP response:\n" + res)
+    os.unlink(fn2)
+    return fn
+
+def ica_ocsp(cert):
+    prefix = "auth_serv/iCA-server/"
+    ca = prefix + "cacert.pem"
+    cert = prefix + cert
+
+    fd2, fn2 = tempfile.mkstemp()
+    os.close(fd2)
+
+    arg = [ "openssl", "ocsp", "-reqout", fn2, "-issuer", ca, "-cert", cert,
+            "-no_nonce", "-sha256", "-text" ]
+    cmd = subprocess.Popen(arg, stdout=subprocess.PIPE,
+                           stderr=subprocess.PIPE)
+    res = cmd.stdout.read() + "\n" + cmd.stderr.read()
+    cmd.stdout.close()
+    cmd.stderr.close()
+    logger.info("OCSP request:\n" + res)
+
+    fd, fn = tempfile.mkstemp()
+    os.close(fd)
+    arg = [ "openssl", "ocsp", "-index", prefix + "index.txt",
+            "-rsigner", ca, "-rkey", prefix + "private/cakey.pem",
+            "-CA", ca, "-issuer", ca, "-verify_other", ca, "-trust_other",
+            "-ndays", "7", "-reqin", fn2, "-resp_no_certs", "-respout", fn,
+            "-text" ]
+    cmd = subprocess.Popen(arg, stdout=subprocess.PIPE,
+                           stderr=subprocess.PIPE)
+    res = cmd.stdout.read() + "\n" + cmd.stderr.read()
+    cmd.stdout.close()
+    cmd.stderr.close()
+    logger.info("OCSP response:\n" + res)
+    os.unlink(fn2)
+    return fn
+
+def test_ap_wpa2_eap_tls_intermediate_ca_ocsp(dev, apdev, params):
+    """EAP-TLS with intermediate server/user CA and OCSP on server certificate"""
+    params = int_eap_server_params()
+    params["ca_cert"] = "auth_serv/iCA-server/ca-and-root.pem"
+    params["server_cert"] = "auth_serv/iCA-server/server.pem"
+    params["private_key"] = "auth_serv/iCA-server/server.key"
+    fn = ica_ocsp("server.pem")
+    params["ocsp_stapling_response"] = fn
+    try:
+        hostapd.add_ap(apdev[0], params)
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                       identity="tls user",
+                       ca_cert="auth_serv/iCA-user/ca-and-root.pem",
+                       client_cert="auth_serv/iCA-user/user.pem",
+                       private_key="auth_serv/iCA-user/user.key",
+                       scan_freq="2412", ocsp=2)
+    finally:
+        os.unlink(fn)
+
+def test_ap_wpa2_eap_tls_intermediate_ca_ocsp_revoked(dev, apdev, params):
+    """EAP-TLS with intermediate server/user CA and OCSP on revoked server certificate"""
+    params = int_eap_server_params()
+    params["ca_cert"] = "auth_serv/iCA-server/ca-and-root.pem"
+    params["server_cert"] = "auth_serv/iCA-server/server-revoked.pem"
+    params["private_key"] = "auth_serv/iCA-server/server-revoked.key"
+    fn = ica_ocsp("server-revoked.pem")
+    params["ocsp_stapling_response"] = fn
+    try:
+        hostapd.add_ap(apdev[0], params)
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                       identity="tls user",
+                       ca_cert="auth_serv/iCA-user/ca-and-root.pem",
+                       client_cert="auth_serv/iCA-user/user.pem",
+                       private_key="auth_serv/iCA-user/user.key",
+                       scan_freq="2412", ocsp=1, wait_connect=False)
+        count = 0
+        while True:
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STATUS",
+                                    "CTRL-EVENT-EAP-SUCCESS"])
+            if ev is None:
+                raise Exception("Timeout on EAP status")
+            if "CTRL-EVENT-EAP-SUCCESS" in ev:
+                raise Exception("Unexpected EAP-Success")
+            if 'bad certificate status response' in ev:
+                break
+            if 'certificate revoked' in ev:
+                break
+            count = count + 1
+            if count > 10:
+                raise Exception("Unexpected number of EAP status messages")
+
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"])
+        if ev is None:
+            raise Exception("Timeout on EAP failure report")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+    finally:
+        os.unlink(fn)
+
+def test_ap_wpa2_eap_tls_intermediate_ca_ocsp_multi_missing_resp(dev, apdev, params):
+    """EAP-TLS with intermediate server/user CA and OCSP multi missing response"""
+    check_ocsp_support(dev[0])
+    check_ocsp_multi_support(dev[0])
+
+    params = int_eap_server_params()
+    params["ca_cert"] = "auth_serv/iCA-server/ca-and-root.pem"
+    params["server_cert"] = "auth_serv/iCA-server/server.pem"
+    params["private_key"] = "auth_serv/iCA-server/server.key"
+    fn = ica_ocsp("server.pem")
+    params["ocsp_stapling_response"] = fn
+    try:
+        hostapd.add_ap(apdev[0], params)
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                       identity="tls user",
+                       ca_cert="auth_serv/iCA-user/ca-and-root.pem",
+                       client_cert="auth_serv/iCA-user/user.pem",
+                       private_key="auth_serv/iCA-user/user.key",
+                       scan_freq="2412", ocsp=3, wait_connect=False)
+        count = 0
+        while True:
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STATUS",
+                                    "CTRL-EVENT-EAP-SUCCESS"])
+            if ev is None:
+                raise Exception("Timeout on EAP status")
+            if "CTRL-EVENT-EAP-SUCCESS" in ev:
+                raise Exception("Unexpected EAP-Success")
+            if 'bad certificate status response' in ev:
+                break
+            if 'certificate revoked' in ev:
+                break
+            count = count + 1
+            if count > 10:
+                raise Exception("Unexpected number of EAP status messages")
+
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"])
+        if ev is None:
+            raise Exception("Timeout on EAP failure report")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+    finally:
+        os.unlink(fn)
+
+def test_ap_wpa2_eap_tls_intermediate_ca_ocsp_multi(dev, apdev, params):
+    """EAP-TLS with intermediate server/user CA and OCSP multi OK"""
+    check_ocsp_support(dev[0])
+    check_ocsp_multi_support(dev[0])
+
     params = int_eap_server_params()
-    params["ocsp_stapling_response"] = ocsp
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
-                   identity="pap user", ca_cert="auth_serv/ca.pem",
-                   anonymous_identity="ttls", password="password",
-                   phase2="auth=PAP", ocsp=1, scan_freq="2412")
+    params["ca_cert"] = "auth_serv/iCA-server/ca-and-root.pem"
+    params["server_cert"] = "auth_serv/iCA-server/server.pem"
+    params["private_key"] = "auth_serv/iCA-server/server.key"
+    fn = ica_ocsp("server.pem")
+    fn2 = root_ocsp("auth_serv/iCA-server/cacert.pem")
+    params["ocsp_stapling_response"] = fn
+
+    with open(fn, "r") as f:
+        resp_server = f.read()
+    with open(fn2, "r") as f:
+        resp_ica = f.read()
+
+    fd3, fn3 = tempfile.mkstemp()
+    try:
+        f = os.fdopen(fd3, 'w')
+        f.write(struct.pack(">L", len(resp_server))[1:4])
+        f.write(resp_server)
+        f.write(struct.pack(">L", len(resp_ica))[1:4])
+        f.write(resp_ica)
+        f.close()
+
+        params["ocsp_stapling_response_multi"] = fn3
+
+        hostapd.add_ap(apdev[0], params)
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                       identity="tls user",
+                       ca_cert="auth_serv/iCA-user/ca-and-root.pem",
+                       client_cert="auth_serv/iCA-user/user.pem",
+                       private_key="auth_serv/iCA-user/user.key",
+                       scan_freq="2412", ocsp=3)
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+    finally:
+        os.unlink(fn)
+        os.unlink(fn2)
+        os.unlink(fn3)
+
+def test_ap_wpa2_eap_tls_ocsp_multi_revoked(dev, apdev, params):
+    """EAP-TLS and CA signed OCSP multi response (revoked)"""
+    check_ocsp_support(dev[0])
+    check_ocsp_multi_support(dev[0])
+
+    ocsp_revoked = os.path.join(params['logdir'],
+                                "ocsp-resp-ca-signed-revoked.der")
+    if not os.path.exists(ocsp_revoked):
+        raise HwsimSkip("No OCSP response (revoked) available")
+    ocsp_unknown = os.path.join(params['logdir'],
+                                "ocsp-resp-ca-signed-unknown.der")
+    if not os.path.exists(ocsp_unknown):
+        raise HwsimSkip("No OCSP response(unknown) available")
+
+    with open(ocsp_revoked, "r") as f:
+        resp_revoked = f.read()
+    with open(ocsp_unknown, "r") as f:
+        resp_unknown = f.read()
+
+    fd, fn = tempfile.mkstemp()
+    try:
+        # This is not really a valid order of the OCSPResponse items in the
+        # list, but this works for now to verify parsing and processing of
+        # multiple responses.
+        f = os.fdopen(fd, 'w')
+        f.write(struct.pack(">L", len(resp_unknown))[1:4])
+        f.write(resp_unknown)
+        f.write(struct.pack(">L", len(resp_revoked))[1:4])
+        f.write(resp_revoked)
+        f.write(struct.pack(">L", 0)[1:4])
+        f.write(struct.pack(">L", len(resp_unknown))[1:4])
+        f.write(resp_unknown)
+        f.close()
+
+        params = int_eap_server_params()
+        params["ocsp_stapling_response_multi"] = fn
+        hostapd.add_ap(apdev[0], params)
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                       identity="tls user", ca_cert="auth_serv/ca.pem",
+                       private_key="auth_serv/user.pkcs12",
+                       private_key_passwd="whatever", ocsp=1,
+                       wait_connect=False, scan_freq="2412")
+        count = 0
+        while True:
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STATUS",
+                                    "CTRL-EVENT-EAP-SUCCESS"])
+            if ev is None:
+                raise Exception("Timeout on EAP status")
+            if "CTRL-EVENT-EAP-SUCCESS" in ev:
+                raise Exception("Unexpected EAP-Success")
+            if 'bad certificate status response' in ev:
+                break
+            if 'certificate revoked' in ev:
+                break
+            count = count + 1
+            if count > 10:
+                raise Exception("Unexpected number of EAP status messages")
+    finally:
+        os.unlink(fn)
 
 def test_ap_wpa2_eap_tls_domain_suffix_match_cn_full(dev, apdev):
     """WPA2-Enterprise using EAP-TLS and domain suffix match (CN)"""
+    check_domain_match_full(dev[0])
     params = int_eap_server_params()
     params["server_cert"] = "auth_serv/server-no-dnsname.pem"
     params["private_key"] = "auth_serv/server-no-dnsname.key"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
                    identity="tls user", ca_cert="auth_serv/ca.pem",
                    private_key="auth_serv/user.pkcs12",
@@ -2670,10 +4098,11 @@ def test_ap_wpa2_eap_tls_domain_suffix_match_cn_full(dev, apdev):
 
 def test_ap_wpa2_eap_tls_domain_match_cn(dev, apdev):
     """WPA2-Enterprise using EAP-TLS and domainmatch (CN)"""
+    check_domain_match(dev[0])
     params = int_eap_server_params()
     params["server_cert"] = "auth_serv/server-no-dnsname.pem"
     params["private_key"] = "auth_serv/server-no-dnsname.key"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
                    identity="tls user", ca_cert="auth_serv/ca.pem",
                    private_key="auth_serv/user.pkcs12",
@@ -2687,7 +4116,7 @@ def test_ap_wpa2_eap_tls_domain_suffix_match_cn(dev, apdev):
     params = int_eap_server_params()
     params["server_cert"] = "auth_serv/server-no-dnsname.pem"
     params["private_key"] = "auth_serv/server-no-dnsname.key"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[1].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
                    identity="tls user", ca_cert="auth_serv/ca.pem",
                    private_key="auth_serv/user.pkcs12",
@@ -2697,10 +4126,11 @@ def test_ap_wpa2_eap_tls_domain_suffix_match_cn(dev, apdev):
 
 def test_ap_wpa2_eap_tls_domain_suffix_mismatch_cn(dev, apdev):
     """WPA2-Enterprise using EAP-TLS and domain suffix mismatch (CN)"""
+    check_domain_suffix_match(dev[0])
     params = int_eap_server_params()
     params["server_cert"] = "auth_serv/server-no-dnsname.pem"
     params["private_key"] = "auth_serv/server-no-dnsname.key"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
                    identity="tls user", ca_cert="auth_serv/ca.pem",
                    private_key="auth_serv/user.pkcs12",
@@ -2724,10 +4154,11 @@ def test_ap_wpa2_eap_tls_domain_suffix_mismatch_cn(dev, apdev):
 
 def test_ap_wpa2_eap_tls_domain_mismatch_cn(dev, apdev):
     """WPA2-Enterprise using EAP-TLS and domain mismatch (CN)"""
+    check_domain_match(dev[0])
     params = int_eap_server_params()
     params["server_cert"] = "auth_serv/server-no-dnsname.pem"
     params["private_key"] = "auth_serv/server-no-dnsname.key"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
                    identity="tls user", ca_cert="auth_serv/ca.pem",
                    private_key="auth_serv/user.pkcs12",
@@ -2755,7 +4186,7 @@ def test_ap_wpa2_eap_ttls_expired_cert(dev, apdev):
     params = int_eap_server_params()
     params["server_cert"] = "auth_serv/server-expired.pem"
     params["private_key"] = "auth_serv/server-expired.key"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="mschap user", password="password",
                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
@@ -2776,7 +4207,7 @@ def test_ap_wpa2_eap_ttls_ignore_expired_cert(dev, apdev):
     params = int_eap_server_params()
     params["server_cert"] = "auth_serv/server-expired.pem"
     params["private_key"] = "auth_serv/server-expired.key"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="mschap user", password="password",
                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
@@ -2789,7 +4220,7 @@ def test_ap_wpa2_eap_ttls_long_duration(dev, apdev):
     params = int_eap_server_params()
     params["server_cert"] = "auth_serv/server-long-duration.pem"
     params["private_key"] = "auth_serv/server-long-duration.key"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="mschap user", password="password",
                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
@@ -2801,7 +4232,7 @@ def test_ap_wpa2_eap_ttls_server_cert_eku_client(dev, apdev):
     params = int_eap_server_params()
     params["server_cert"] = "auth_serv/server-eku-client.pem"
     params["private_key"] = "auth_serv/server-eku-client.key"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="mschap user", password="password",
                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
@@ -2817,7 +4248,7 @@ def test_ap_wpa2_eap_ttls_server_cert_eku_client_server(dev, apdev):
     params = int_eap_server_params()
     params["server_cert"] = "auth_serv/server-eku-client-server.pem"
     params["private_key"] = "auth_serv/server-eku-client-server.key"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="mschap user", password="password",
                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
@@ -2829,7 +4260,20 @@ def test_ap_wpa2_eap_ttls_server_pkcs12(dev, apdev):
     params = int_eap_server_params()
     del params["server_cert"]
     params["private_key"] = "auth_serv/server.pkcs12"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                   identity="mschap user", password="password",
+                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
+                   scan_freq="2412")
+
+def test_ap_wpa2_eap_ttls_server_pkcs12_extra(dev, apdev):
+    """EAP-TTLS and server PKCS#12 file with extra certs"""
+    skip_with_fips(dev[0])
+    params = int_eap_server_params()
+    del params["server_cert"]
+    params["private_key"] = "auth_serv/server-extra.pkcs12"
+    params["private_key_passwd"] = "whatever"
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="mschap user", password="password",
                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
@@ -2838,17 +4282,18 @@ def test_ap_wpa2_eap_ttls_server_pkcs12(dev, apdev):
 def test_ap_wpa2_eap_ttls_dh_params(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/CHAP and setting DH params"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.der", phase2="auth=PAP",
                 dh_file="auth_serv/dh.conf")
 
 def test_ap_wpa2_eap_ttls_dh_params_dsa(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS and setting DH params (DSA)"""
+    check_dh_dsa_support(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.der", phase2="auth=PAP",
                 dh_file="auth_serv/dsaparam.pem")
@@ -2857,7 +4302,7 @@ def test_ap_wpa2_eap_ttls_dh_params_not_found(dev, apdev):
     """EAP-TTLS and DH params file not found"""
     skip_with_fips(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="mschap user", password="password",
                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
@@ -2873,7 +4318,7 @@ def test_ap_wpa2_eap_ttls_dh_params_invalid(dev, apdev):
     """EAP-TTLS and invalid DH params file"""
     skip_with_fips(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="mschap user", password="password",
                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
@@ -2888,11 +4333,11 @@ def test_ap_wpa2_eap_ttls_dh_params_invalid(dev, apdev):
 def test_ap_wpa2_eap_ttls_dh_params_blob(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS/CHAP and setting DH params from blob"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dh = read_pem("auth_serv/dh2.conf")
     if "OK" not in dev[0].request("SET blob dhparams " + dh.encode("hex")):
         raise Exception("Could not set dhparams blob")
-    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+    eap_connect(dev[0], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.der", phase2="auth=PAP",
                 dh_file="blob://dhparams")
@@ -2901,8 +4346,8 @@ def test_ap_wpa2_eap_ttls_dh_params_server(dev, apdev):
     """WPA2-Enterprise using EAP-TTLS and alternative server dhparams"""
     params = int_eap_server_params()
     params["dh_file"] = "auth_serv/dh2.conf"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.der", phase2="auth=PAP")
 
@@ -2910,8 +4355,8 @@ def test_ap_wpa2_eap_ttls_dh_params_dsa_server(dev, apdev):
     """WPA2-Enterprise using EAP-TTLS and alternative server dhparams (DSA)"""
     params = int_eap_server_params()
     params["dh_file"] = "auth_serv/dsaparam.pem"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.der", phase2="auth=PAP")
 
@@ -2919,7 +4364,7 @@ def test_ap_wpa2_eap_ttls_dh_params_not_found(dev, apdev):
     """EAP-TLS server and dhparams file not found"""
     params = int_eap_server_params()
     params["dh_file"] = "auth_serv/dh-no-such-file.conf"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, no_enable=True)
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
     if "FAIL" not in hapd.request("ENABLE"):
         raise Exception("Invalid configuration accepted")
 
@@ -2927,7 +4372,7 @@ def test_ap_wpa2_eap_ttls_dh_params_invalid(dev, apdev):
     """EAP-TLS server and invalid dhparams file"""
     params = int_eap_server_params()
     params["dh_file"] = "auth_serv/ca.pem"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, no_enable=True)
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
     if "FAIL" not in hapd.request("ENABLE"):
         raise Exception("Invalid configuration accepted")
 
@@ -2935,8 +4380,8 @@ def test_ap_wpa2_eap_reauth(dev, apdev):
     """WPA2-Enterprise and Authenticator forcing reauthentication"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params['eap_reauth_period'] = '2'
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "PAX", "pax.user@example.com",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "PAX", "pax.user@example.com",
                 password_hex="0123456789abcdef0123456789abcdef")
     logger.info("Wait for reauthentication")
     ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=10)
@@ -2957,8 +4402,8 @@ def test_ap_wpa2_eap_request_identity_message(dev, apdev):
     """Optional displayable message in EAP Request-Identity"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params['eap_message'] = 'hello\\0networkid=netw,nasid=foo,portid=0,NAIRealms=example.com'
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "PAX", "pax.user@example.com",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "PAX", "pax.user@example.com",
                 password_hex="0123456789abcdef0123456789abcdef")
 
 def test_ap_wpa2_eap_sim_aka_result_ind(dev, apdev):
@@ -2967,54 +4412,55 @@ def test_ap_wpa2_eap_sim_aka_result_ind(dev, apdev):
     params = int_eap_server_params()
     params['eap_sim_db'] = "unix:/tmp/hlr_auc_gw.sock"
     params['eap_sim_aka_result_ind'] = "1"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
-    eap_connect(dev[0], apdev[0], "SIM", "1232010000000000",
+    eap_connect(dev[0], hapd, "SIM", "1232010000000000",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
                 phase1="result_ind=1")
     eap_reauth(dev[0], "SIM")
-    eap_connect(dev[1], apdev[0], "SIM", "1232010000000000",
+    eap_connect(dev[1], hapd, "SIM", "1232010000000000",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
 
     dev[0].request("REMOVE_NETWORK all")
     dev[1].request("REMOVE_NETWORK all")
 
-    eap_connect(dev[0], apdev[0], "AKA", "0232010000000000",
+    eap_connect(dev[0], hapd, "AKA", "0232010000000000",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
                 phase1="result_ind=1")
     eap_reauth(dev[0], "AKA")
-    eap_connect(dev[1], apdev[0], "AKA", "0232010000000000",
+    eap_connect(dev[1], hapd, "AKA", "0232010000000000",
                 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123")
 
     dev[0].request("REMOVE_NETWORK all")
     dev[1].request("REMOVE_NETWORK all")
 
-    eap_connect(dev[0], apdev[0], "AKA'", "6555444333222111",
+    eap_connect(dev[0], hapd, "AKA'", "6555444333222111",
                 password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
                 phase1="result_ind=1")
     eap_reauth(dev[0], "AKA'")
-    eap_connect(dev[1], apdev[0], "AKA'", "6555444333222111",
+    eap_connect(dev[1], hapd, "AKA'", "6555444333222111",
                 password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123")
 
 def test_ap_wpa2_eap_too_many_roundtrips(dev, apdev):
     """WPA2-Enterprise connection resulting in too many EAP roundtrips"""
     skip_with_fips(dev[0])
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP WPA-EAP-SHA256",
                    eap="TTLS", identity="mschap user",
                    wait_connect=False, scan_freq="2412", ieee80211w="1",
                    anonymous_identity="ttls", password="password",
                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
-                   fragment_size="10")
-    ev = dev[0].wait_event(["EAP: more than"], timeout=20)
-    if ev is None:
+                   fragment_size="8")
+    ev = dev[0].wait_event(["EAP: more than",
+                            "CTRL-EVENT-EAP-SUCCESS"], timeout=20)
+    if ev is None or "EAP: more than" not in ev:
         raise Exception("EAP roundtrip limit not reached")
 
 def test_ap_wpa2_eap_expanded_nak(dev, apdev):
     """WPA2-Enterprise connection with EAP resulting in expanded NAK"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP WPA-EAP-SHA256",
                    eap="PSK", identity="vendor-test",
                    password_hex="ff23456789abcdef0123456789abcdef",
@@ -3022,7 +4468,7 @@ def test_ap_wpa2_eap_expanded_nak(dev, apdev):
 
     found = False
     for i in range(0, 5):
-        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STATUS"], timeout=10)
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STATUS"], timeout=16)
         if ev is None:
             raise Exception("Association and EAP start timed out")
         if "refuse proposed method" in ev:
@@ -3062,19 +4508,19 @@ def test_ap_wpa2_eap_sql(dev, apdev, params):
     try:
         params = int_eap_server_params()
         params["eap_user_file"] = "sqlite:" + dbfile
-        hostapd.add_ap(apdev[0]['ifname'], params)
-        eap_connect(dev[0], apdev[0], "TTLS", "user-mschapv2",
+        hapd = hostapd.add_ap(apdev[0], params)
+        eap_connect(dev[0], hapd, "TTLS", "user-mschapv2",
                     anonymous_identity="ttls", password="password",
                     ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2")
         dev[0].request("REMOVE_NETWORK all")
-        eap_connect(dev[1], apdev[0], "TTLS", "user-mschap",
+        eap_connect(dev[1], hapd, "TTLS", "user-mschap",
                     anonymous_identity="ttls", password="password",
                     ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP")
         dev[1].request("REMOVE_NETWORK all")
-        eap_connect(dev[0], apdev[0], "TTLS", "user-chap",
+        eap_connect(dev[0], hapd, "TTLS", "user-chap",
                     anonymous_identity="ttls", password="password",
                     ca_cert="auth_serv/ca.pem", phase2="auth=CHAP")
-        eap_connect(dev[1], apdev[0], "TTLS", "user-pap",
+        eap_connect(dev[1], hapd, "TTLS", "user-pap",
                     anonymous_identity="ttls", password="password",
                     ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
     finally:
@@ -3083,13 +4529,13 @@ def test_ap_wpa2_eap_sql(dev, apdev, params):
 def test_ap_wpa2_eap_non_ascii_identity(dev, apdev):
     """WPA2-Enterprise connection attempt using non-ASCII identity"""
     params = int_eap_server_params()
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="\x80", password="password", wait_connect=False)
     dev[1].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="a\x80", password="password", wait_connect=False)
     for i in range(0, 2):
-        ev = dev[i].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=10)
+        ev = dev[i].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=16)
         if ev is None:
             raise Exception("Association and EAP start timed out")
         ev = dev[i].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=10)
@@ -3099,13 +4545,13 @@ def test_ap_wpa2_eap_non_ascii_identity(dev, apdev):
 def test_ap_wpa2_eap_non_ascii_identity2(dev, apdev):
     """WPA2-Enterprise connection attempt using non-ASCII identity"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="\x80", password="password", wait_connect=False)
     dev[1].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="a\x80", password="password", wait_connect=False)
     for i in range(0, 2):
-        ev = dev[i].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=10)
+        ev = dev[i].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=16)
         if ev is None:
             raise Exception("Association and EAP start timed out")
         ev = dev[i].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=10)
@@ -3118,12 +4564,12 @@ def test_openssl_cipher_suite_config_wpas(dev, apdev):
     if not tls.startswith("OpenSSL"):
         raise HwsimSkip("TLS library is not OpenSSL: " + tls)
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 openssl_ciphers="AES128",
                 ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
-    eap_connect(dev[1], apdev[0], "TTLS", "pap user",
+    eap_connect(dev[1], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 openssl_ciphers="EXPORT",
                 ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
@@ -3146,38 +4592,42 @@ def test_openssl_cipher_suite_config_hapd(dev, apdev):
         raise HwsimSkip("wpa_supplicant TLS library is not OpenSSL: " + tls)
     params = int_eap_server_params()
     params['openssl_ciphers'] = "AES256"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     tls = hapd.request("GET tls_library")
     if not tls.startswith("OpenSSL"):
         raise HwsimSkip("hostapd TLS library is not OpenSSL: " + tls)
-    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+    eap_connect(dev[0], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
-    eap_connect(dev[1], apdev[0], "TTLS", "pap user",
+    eap_connect(dev[1], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 openssl_ciphers="AES128",
                 ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
                 expect_failure=True)
-    eap_connect(dev[2], apdev[0], "TTLS", "pap user",
+    eap_connect(dev[2], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 openssl_ciphers="HIGH:!ADH",
                 ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
 
     params['openssl_ciphers'] = "FOO"
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params, no_enable=True)
+    hapd2 = hostapd.add_ap(apdev[1], params, no_enable=True)
     if "FAIL" not in hapd2.request("ENABLE"):
         raise Exception("Invalid openssl_ciphers value accepted")
 
 def test_wpa2_eap_ttls_pap_key_lifetime_in_memory(dev, apdev, params):
     """Key lifetime in memory with WPA2-Enterprise using EAP-TTLS/PAP"""
     p = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], p)
+    hapd = hostapd.add_ap(apdev[0], p)
     password = "63d2d21ac3c09ed567ee004a34490f1d16e7fa5835edf17ddba70a63f1a90a25"
     pid = find_wpas_process(dev[0])
-    id = eap_connect(dev[0], apdev[0], "TTLS", "pap-secret",
+    id = eap_connect(dev[0], hapd, "TTLS", "pap-secret",
                      anonymous_identity="ttls", password=password,
                      ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
+    # The decrypted copy of GTK is freed only after the CTRL-EVENT-CONNECTED
+    # event has been delivered, so verify that wpa_supplicant has returned to
+    # eloop before reading process memory.
     time.sleep(1)
+    dev[0].ping()
     buf = read_process_memory(pid, password)
 
     dev[0].request("DISCONNECT")
@@ -3234,6 +4684,7 @@ def test_wpa2_eap_ttls_pap_key_lifetime_in_memory(dev, apdev, params):
     if tk in buf:
         raise Exception("TK found from memory")
     if gtk in buf:
+        get_key_locations(buf, gtk, "GTK")
         raise Exception("GTK found from memory")
 
     logger.info("Checking keys in memory after disassociation")
@@ -3282,9 +4733,9 @@ def test_wpa2_eap_ttls_pap_key_lifetime_in_memory(dev, apdev, params):
 def test_ap_wpa2_eap_unexpected_wep_eapol_key(dev, apdev):
     """WPA2-Enterprise connection and unexpected WEP EAPOL-Key"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
-    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+    eap_connect(dev[0], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
 
@@ -3307,7 +4758,7 @@ def test_ap_wpa2_eap_in_bridge(dev, apdev):
 
 def _test_ap_wpa2_eap_in_bridge(dev, apdev):
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     br_ifname='sta-br0'
     ifname='wlan5'
@@ -3318,25 +4769,31 @@ def _test_ap_wpa2_eap_in_bridge(dev, apdev):
     subprocess.call(['iw', ifname, 'set', '4addr', 'on'])
     subprocess.check_call(['brctl', 'addif', br_ifname, ifname])
     wpas.interface_add(ifname, br_ifname=br_ifname)
+    wpas.dump_monitor()
 
-    id = eap_connect(wpas, apdev[0], "PAX", "pax.user@example.com",
+    id = eap_connect(wpas, hapd, "PAX", "pax.user@example.com",
                      password_hex="0123456789abcdef0123456789abcdef")
+    wpas.dump_monitor()
     eap_reauth(wpas, "PAX")
+    wpas.dump_monitor()
     # Try again as a regression test for packet socket workaround
     eap_reauth(wpas, "PAX")
+    wpas.dump_monitor()
     wpas.request("DISCONNECT")
     wpas.wait_disconnected()
+    wpas.dump_monitor()
     wpas.request("RECONNECT")
     wpas.wait_connected()
+    wpas.dump_monitor()
 
 def test_ap_wpa2_eap_session_ticket(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS and TLS session ticket enabled"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     key_mgmt = hapd.get_config()['key_mgmt']
     if key_mgmt.split(' ')[0] != "WPA-EAP":
         raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
-    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+    eap_connect(dev[0], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem",
                 phase1="tls_disable_session_ticket=0", phase2="auth=PAP")
@@ -3345,11 +4802,11 @@ def test_ap_wpa2_eap_session_ticket(dev, apdev):
 def test_ap_wpa2_eap_no_workaround(dev, apdev):
     """WPA2-Enterprise connection using EAP-TTLS and eap_workaround=0"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     key_mgmt = hapd.get_config()['key_mgmt']
     if key_mgmt.split(' ')[0] != "WPA-EAP":
         raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
-    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+    eap_connect(dev[0], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", eap_workaround='0',
                 phase2="auth=PAP")
@@ -3359,10 +4816,10 @@ def test_ap_wpa2_eap_tls_check_crl(dev, apdev):
     """EAP-TLS and server checking CRL"""
     params = int_eap_server_params()
     params['check_crl'] = '1'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     # check_crl=1 and no CRL available --> reject connection
-    eap_connect(dev[0], apdev[0], "TLS", "tls user", ca_cert="auth_serv/ca.pem",
+    eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
                 client_cert="auth_serv/user.pem",
                 private_key="auth_serv/user.key", expect_failure=True)
     dev[0].request("REMOVE_NETWORK all")
@@ -3372,7 +4829,7 @@ def test_ap_wpa2_eap_tls_check_crl(dev, apdev):
     hapd.enable()
 
     # check_crl=1 and valid CRL --> accept
-    eap_connect(dev[0], apdev[0], "TLS", "tls user", ca_cert="auth_serv/ca.pem",
+    eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
                 client_cert="auth_serv/user.pem",
                 private_key="auth_serv/user.key")
     dev[0].request("REMOVE_NETWORK all")
@@ -3382,7 +4839,7 @@ def test_ap_wpa2_eap_tls_check_crl(dev, apdev):
     hapd.enable()
 
     # check_crl=2 and valid CRL --> accept
-    eap_connect(dev[0], apdev[0], "TLS", "tls user", ca_cert="auth_serv/ca.pem",
+    eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
                 client_cert="auth_serv/user.pem",
                 private_key="auth_serv/user.key")
     dev[0].request("REMOVE_NETWORK all")
@@ -3391,10 +4848,11 @@ def test_ap_wpa2_eap_tls_oom(dev, apdev):
     """EAP-TLS and OOM"""
     check_subject_match_support(dev[0])
     check_altsubject_match_support(dev[0])
+    check_domain_match(dev[0])
     check_domain_match_full(dev[0])
 
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     tests = [ (1, "tls_connection_set_subject_match"),
               (2, "tls_connection_set_subject_match"),
@@ -3422,15 +4880,15 @@ def test_ap_wpa2_eap_tls_macacl(dev, apdev):
     """WPA2-Enterprise connection using MAC ACL"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params["macaddr_acl"] = "2"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[1], apdev[0], "TLS", "tls user", ca_cert="auth_serv/ca.pem",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[1], hapd, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
                 client_cert="auth_serv/user.pem",
                 private_key="auth_serv/user.key")
 
 def test_ap_wpa2_eap_oom(dev, apdev):
     """EAP server and OOM"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412)
 
     with alloc_fail(hapd, 1, "eapol_auth_alloc"):
@@ -3442,8 +4900,8 @@ def test_ap_wpa2_eap_oom(dev, apdev):
                        private_key="auth_serv/user.key",
                        scan_freq="2412")
 
-def check_tls_ver(dev, ap, phase1, expected):
-    eap_connect(dev, ap, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
+def check_tls_ver(dev, hapd, phase1, expected):
+    eap_connect(dev, hapd, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
                 client_cert="auth_serv/user.pem",
                 private_key="auth_serv/user.key",
                 phase1=phase1)
@@ -3454,17 +4912,20 @@ def check_tls_ver(dev, ap, phase1, expected):
 def test_ap_wpa2_eap_tls_versions(dev, apdev):
     """EAP-TLS and TLS version configuration"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     tls = dev[0].request("GET tls_library")
     if tls.startswith("OpenSSL"):
         if "build=OpenSSL 1.0.2" in tls and "run=OpenSSL 1.0.2" in tls:
-            check_tls_ver(dev[0], apdev[0],
+            check_tls_ver(dev[0], hapd,
                           "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1",
                           "TLSv1.2")
-    check_tls_ver(dev[1], apdev[0],
+    elif tls.startswith("internal"):
+        check_tls_ver(dev[0], hapd,
+                      "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1", "TLSv1.2")
+    check_tls_ver(dev[1], hapd,
                   "tls_disable_tlsv1_0=1 tls_disable_tlsv1_2=1", "TLSv1.1")
-    check_tls_ver(dev[2], apdev[0],
+    check_tls_ver(dev[2], hapd,
                   "tls_disable_tlsv1_1=1 tls_disable_tlsv1_2=1", "TLSv1")
 
 def test_rsn_ie_proto_eap_sta(dev, apdev):
@@ -3473,7 +4934,7 @@ def test_rsn_ie_proto_eap_sta(dev, apdev):
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     # This is the RSN element used normally by hostapd
     params['own_ie_override'] = '30140100000fac040100000fac040100000fac010c00'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="GPSK",
                         identity="gpsk user",
                         password="abcdefghijklmnop0123456789abcdef",
@@ -3499,6 +4960,10 @@ def test_rsn_ie_proto_eap_sta(dev, apdev):
         dev[0].select_network(id, freq=2412)
         dev[0].wait_connected()
 
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+    dev[0].flush_scan_cache()
+
 def check_tls_session_resumption_capa(dev, hapd):
     tls = hapd.request("GET tls_library")
     if not tls.startswith("OpenSSL"):
@@ -3512,9 +4977,9 @@ def test_eap_ttls_pap_session_resumption(dev, apdev):
     """EAP-TTLS/PAP session resumption"""
     params = int_eap_server_params()
     params['tls_session_lifetime'] = '60'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     check_tls_session_resumption_capa(dev[0], hapd)
-    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+    eap_connect(dev[0], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", eap_workaround='0',
                 phase2="auth=PAP")
@@ -3535,9 +5000,9 @@ def test_eap_ttls_chap_session_resumption(dev, apdev):
     """EAP-TTLS/CHAP session resumption"""
     params = int_eap_server_params()
     params['tls_session_lifetime'] = '60'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     check_tls_session_resumption_capa(dev[0], hapd)
-    eap_connect(dev[0], apdev[0], "TTLS", "chap user",
+    eap_connect(dev[0], hapd, "TTLS", "chap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.der", phase2="auth=CHAP")
     if dev[0].get_status_field("tls_session_reused") != '0':
@@ -3555,11 +5020,12 @@ def test_eap_ttls_chap_session_resumption(dev, apdev):
 
 def test_eap_ttls_mschap_session_resumption(dev, apdev):
     """EAP-TTLS/MSCHAP session resumption"""
+    check_domain_suffix_match(dev[0])
     params = int_eap_server_params()
     params['tls_session_lifetime'] = '60'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     check_tls_session_resumption_capa(dev[0], hapd)
-    eap_connect(dev[0], apdev[0], "TTLS", "mschap user",
+    eap_connect(dev[0], hapd, "TTLS", "mschap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
                 domain_suffix_match="server.w1.fi")
@@ -3578,12 +5044,13 @@ def test_eap_ttls_mschap_session_resumption(dev, apdev):
 
 def test_eap_ttls_mschapv2_session_resumption(dev, apdev):
     """EAP-TTLS/MSCHAPv2 session resumption"""
+    check_domain_suffix_match(dev[0])
     check_eap_capa(dev[0], "MSCHAPV2")
     params = int_eap_server_params()
     params['tls_session_lifetime'] = '60'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     check_tls_session_resumption_capa(dev[0], hapd)
-    eap_connect(dev[0], apdev[0], "TTLS", "DOMAIN\mschapv2 user",
+    eap_connect(dev[0], hapd, "TTLS", "DOMAIN\mschapv2 user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
                 domain_suffix_match="server.w1.fi")
@@ -3604,9 +5071,9 @@ def test_eap_ttls_eap_gtc_session_resumption(dev, apdev):
     """EAP-TTLS/EAP-GTC session resumption"""
     params = int_eap_server_params()
     params['tls_session_lifetime'] = '60'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     check_tls_session_resumption_capa(dev[0], hapd)
-    eap_connect(dev[0], apdev[0], "TTLS", "user",
+    eap_connect(dev[0], hapd, "TTLS", "user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="autheap=GTC")
     if dev[0].get_status_field("tls_session_reused") != '0':
@@ -3626,8 +5093,8 @@ def test_eap_ttls_no_session_resumption(dev, apdev):
     """EAP-TTLS session resumption disabled on server"""
     params = int_eap_server_params()
     params['tls_session_lifetime'] = '0'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TTLS", "pap user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TTLS", "pap user",
                 anonymous_identity="ttls", password="password",
                 ca_cert="auth_serv/ca.pem", eap_workaround='0',
                 phase2="auth=PAP")
@@ -3648,10 +5115,33 @@ def test_eap_peap_session_resumption(dev, apdev):
     """EAP-PEAP session resumption"""
     params = int_eap_server_params()
     params['tls_session_lifetime'] = '60'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
+    check_tls_session_resumption_capa(dev[0], hapd)
+    eap_connect(dev[0], hapd, "PEAP", "user",
+                anonymous_identity="peap", password="password",
+                ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2")
+    if dev[0].get_status_field("tls_session_reused") != '0':
+        raise Exception("Unexpected session resumption on the first connection")
+
+    dev[0].request("REAUTHENTICATE")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=10)
+    if ev is None:
+        raise Exception("EAP success timed out")
+    ev = dev[0].wait_event(["WPA: Key negotiation completed"], timeout=10)
+    if ev is None:
+        raise Exception("Key handshake with the AP timed out")
+    if dev[0].get_status_field("tls_session_reused") != '1':
+        raise Exception("Session resumption not used on the second connection")
+
+def test_eap_peap_session_resumption_crypto_binding(dev, apdev):
+    """EAP-PEAP session resumption with crypto binding"""
+    params = int_eap_server_params()
+    params['tls_session_lifetime'] = '60'
+    hapd = hostapd.add_ap(apdev[0], params)
     check_tls_session_resumption_capa(dev[0], hapd)
-    eap_connect(dev[0], apdev[0], "PEAP", "user",
+    eap_connect(dev[0], hapd, "PEAP", "user",
                 anonymous_identity="peap", password="password",
+                phase1="peapver=0 crypto_binding=2",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2")
     if dev[0].get_status_field("tls_session_reused") != '0':
         raise Exception("Unexpected session resumption on the first connection")
@@ -3669,8 +5159,8 @@ def test_eap_peap_session_resumption(dev, apdev):
 def test_eap_peap_no_session_resumption(dev, apdev):
     """EAP-PEAP session resumption disabled on server"""
     params = int_eap_server_params()
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "PEAP", "user",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "PEAP", "user",
                 anonymous_identity="peap", password="password",
                 ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2")
     if dev[0].get_status_field("tls_session_reused") != '0':
@@ -3690,9 +5180,9 @@ def test_eap_tls_session_resumption(dev, apdev):
     """EAP-TLS session resumption"""
     params = int_eap_server_params()
     params['tls_session_lifetime'] = '60'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     check_tls_session_resumption_capa(dev[0], hapd)
-    eap_connect(dev[0], apdev[0], "TLS", "tls user", ca_cert="auth_serv/ca.pem",
+    eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
                 client_cert="auth_serv/user.pem",
                 private_key="auth_serv/user.key")
     if dev[0].get_status_field("tls_session_reused") != '0':
@@ -3722,9 +5212,9 @@ def test_eap_tls_session_resumption_expiration(dev, apdev):
     """EAP-TLS session resumption"""
     params = int_eap_server_params()
     params['tls_session_lifetime'] = '1'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     check_tls_session_resumption_capa(dev[0], hapd)
-    eap_connect(dev[0], apdev[0], "TLS", "tls user", ca_cert="auth_serv/ca.pem",
+    eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
                 client_cert="auth_serv/user.pem",
                 private_key="auth_serv/user.key")
     if dev[0].get_status_field("tls_session_reused") != '0':
@@ -3750,8 +5240,8 @@ def test_eap_tls_session_resumption_expiration(dev, apdev):
 def test_eap_tls_no_session_resumption(dev, apdev):
     """EAP-TLS session resumption disabled on server"""
     params = int_eap_server_params()
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TLS", "tls user", ca_cert="auth_serv/ca.pem",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
                 client_cert="auth_serv/user.pem",
                 private_key="auth_serv/user.key")
     if dev[0].get_status_field("tls_session_reused") != '0':
@@ -3778,13 +5268,13 @@ def test_eap_tls_session_resumption_radius(dev, apdev):
                "server_cert": "auth_serv/server.pem",
                "private_key": "auth_serv/server.key",
                "tls_session_lifetime": "60" }
-    authsrv = hostapd.add_ap(apdev[1]['ifname'], params)
+    authsrv = hostapd.add_ap(apdev[1], params)
     check_tls_session_resumption_capa(dev[0], authsrv)
 
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params['auth_server_port'] = "18128"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TLS", "tls user", ca_cert="auth_serv/ca.pem",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
                 client_cert="auth_serv/user.pem",
                 private_key="auth_serv/user.key")
     if dev[0].get_status_field("tls_session_reused") != '0':
@@ -3811,12 +5301,12 @@ def test_eap_tls_no_session_resumption_radius(dev, apdev):
                "server_cert": "auth_serv/server.pem",
                "private_key": "auth_serv/server.key",
                "tls_session_lifetime": "0" }
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params['auth_server_port'] = "18128"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "TLS", "tls user", ca_cert="auth_serv/ca.pem",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="auth_serv/ca.pem",
                 client_cert="auth_serv/user.pem",
                 private_key="auth_serv/user.key")
     if dev[0].get_status_field("tls_session_reused") != '0':
@@ -3831,3 +5321,635 @@ def test_eap_tls_no_session_resumption_radius(dev, apdev):
         raise Exception("Key handshake with the AP timed out")
     if dev[0].get_status_field("tls_session_reused") != '0':
         raise Exception("Unexpected session resumption on the second connection")
+
+def test_eap_mschapv2_errors(dev, apdev):
+    """EAP-MSCHAPv2 error cases"""
+    check_eap_capa(dev[0], "MSCHAPV2")
+    check_eap_capa(dev[0], "FAST")
+
+    params = hostapd.wpa2_eap_params(ssid="test-wpa-eap")
+    hapd = hostapd.add_ap(apdev[0], params)
+    dev[0].connect("test-wpa-eap", key_mgmt="WPA-EAP", eap="MSCHAPV2",
+                   identity="phase1-user", password="password",
+                   scan_freq="2412")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+    tests = [ (1, "hash_nt_password_hash;mschapv2_derive_response"),
+              (1, "nt_password_hash;mschapv2_derive_response"),
+              (1, "nt_password_hash;=mschapv2_derive_response"),
+              (1, "generate_nt_response;mschapv2_derive_response"),
+              (1, "generate_authenticator_response;mschapv2_derive_response"),
+              (1, "nt_password_hash;=mschapv2_derive_response"),
+              (1, "get_master_key;mschapv2_derive_response"),
+              (1, "os_get_random;eap_mschapv2_challenge_reply") ]
+    for count, func in tests:
+        with fail_test(dev[0], count, func):
+            dev[0].connect("test-wpa-eap", key_mgmt="WPA-EAP", eap="MSCHAPV2",
+                           identity="phase1-user", password="password",
+                           wait_connect=False, scan_freq="2412")
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "hash_nt_password_hash;mschapv2_derive_response"),
+              (1, "hash_nt_password_hash;=mschapv2_derive_response"),
+              (1, "generate_nt_response_pwhash;mschapv2_derive_response"),
+              (1, "generate_authenticator_response_pwhash;mschapv2_derive_response") ]
+    for count, func in tests:
+        with fail_test(dev[0], count, func):
+            dev[0].connect("test-wpa-eap", key_mgmt="WPA-EAP", eap="MSCHAPV2",
+                           identity="phase1-user",
+                           password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
+                           wait_connect=False, scan_freq="2412")
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "eap_mschapv2_init"),
+              (1, "eap_msg_alloc;eap_mschapv2_challenge_reply"),
+              (1, "eap_msg_alloc;eap_mschapv2_success"),
+              (1, "eap_mschapv2_getKey") ]
+    for count, func in tests:
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("test-wpa-eap", key_mgmt="WPA-EAP", eap="MSCHAPV2",
+                           identity="phase1-user", password="password",
+                           wait_connect=False, scan_freq="2412")
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "eap_msg_alloc;eap_mschapv2_failure") ]
+    for count, func in tests:
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("test-wpa-eap", key_mgmt="WPA-EAP", eap="MSCHAPV2",
+                           identity="phase1-user", password="wrong password",
+                           wait_connect=False, scan_freq="2412")
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (2, "eap_mschapv2_init"),
+              (3, "eap_mschapv2_init") ]
+    for count, func in tests:
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("test-wpa-eap", key_mgmt="WPA-EAP", eap="FAST",
+                           anonymous_identity="FAST", identity="user",
+                           password="password",
+                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                           phase1="fast_provisioning=1",
+                           pac_file="blob://fast_pac",
+                           wait_connect=False, scan_freq="2412")
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+def test_eap_gpsk_errors(dev, apdev):
+    """EAP-GPSK error cases"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa-eap")
+    hapd = hostapd.add_ap(apdev[0], params)
+    dev[0].connect("test-wpa-eap", key_mgmt="WPA-EAP", eap="GPSK",
+                   identity="gpsk user",
+                   password="abcdefghijklmnop0123456789abcdef",
+                   scan_freq="2412")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+    tests = [ (1, "os_get_random;eap_gpsk_send_gpsk_2", None),
+              (1, "eap_gpsk_derive_session_id;eap_gpsk_send_gpsk_2",
+               "cipher=1"),
+              (1, "eap_gpsk_derive_session_id;eap_gpsk_send_gpsk_2",
+               "cipher=2"),
+              (1, "eap_gpsk_derive_keys_helper", None),
+              (2, "eap_gpsk_derive_keys_helper", None),
+              (1, "eap_gpsk_compute_mic_aes;eap_gpsk_compute_mic;eap_gpsk_send_gpsk_2",
+               "cipher=1"),
+              (1, "hmac_sha256;eap_gpsk_compute_mic;eap_gpsk_send_gpsk_2",
+               "cipher=2"),
+              (1, "eap_gpsk_compute_mic;eap_gpsk_validate_gpsk_3_mic", None),
+              (1, "eap_gpsk_compute_mic;eap_gpsk_send_gpsk_4", None),
+              (1, "eap_gpsk_derive_mid_helper", None) ]
+    for count, func, phase1 in tests:
+        with fail_test(dev[0], count, func):
+            dev[0].connect("test-wpa-eap", key_mgmt="WPA-EAP", eap="GPSK",
+                           identity="gpsk user",
+                           password="abcdefghijklmnop0123456789abcdef",
+                           phase1=phase1,
+                           wait_connect=False, scan_freq="2412")
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "eap_gpsk_init"),
+              (2, "eap_gpsk_init"),
+              (3, "eap_gpsk_init"),
+              (1, "eap_gpsk_process_id_server"),
+              (1, "eap_msg_alloc;eap_gpsk_send_gpsk_2"),
+              (1, "eap_gpsk_derive_session_id;eap_gpsk_send_gpsk_2"),
+              (1, "eap_gpsk_derive_mid_helper;eap_gpsk_derive_session_id;eap_gpsk_send_gpsk_2"),
+              (1, "eap_gpsk_derive_keys"),
+              (1, "eap_gpsk_derive_keys_helper"),
+              (1, "eap_msg_alloc;eap_gpsk_send_gpsk_4"),
+              (1, "eap_gpsk_getKey"),
+              (1, "eap_gpsk_get_emsk"),
+              (1, "eap_gpsk_get_session_id") ]
+    for count, func in tests:
+        with alloc_fail(dev[0], count, func):
+            dev[0].request("ERP_FLUSH")
+            dev[0].connect("test-wpa-eap", key_mgmt="WPA-EAP", eap="GPSK",
+                           identity="gpsk user", erp="1",
+                           password="abcdefghijklmnop0123456789abcdef",
+                           wait_connect=False, scan_freq="2412")
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+def test_ap_wpa2_eap_sim_db(dev, apdev, params):
+    """EAP-SIM DB error cases"""
+    sockpath = '/tmp/hlr_auc_gw.sock-test'
+    try:
+        os.remove(sockpath)
+    except:
+        pass
+    hparams = int_eap_server_params()
+    hparams['eap_sim_db'] = 'unix:' + sockpath
+    hapd = hostapd.add_ap(apdev[0], hparams)
+
+    # Initial test with hlr_auc_gw socket not available
+    id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP WPA-EAP-SHA256",
+                        eap="SIM", identity="1232010000000000",
+                        password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
+                        scan_freq="2412", wait_connect=False)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=10)
+    if ev is None:
+        raise Exception("EAP-Failure not reported")
+    dev[0].wait_disconnected()
+    dev[0].request("DISCONNECT")
+
+    # Test with invalid responses and response timeout
+
+    class test_handler(SocketServer.DatagramRequestHandler):
+        def handle(self):
+            data = self.request[0].strip()
+            socket = self.request[1]
+            logger.debug("Received hlr_auc_gw request: " + data)
+            # EAP-SIM DB: Failed to parse response string
+            socket.sendto("FOO", self.client_address)
+            # EAP-SIM DB: Failed to parse response string
+            socket.sendto("FOO 1", self.client_address)
+            # EAP-SIM DB: Unknown external response
+            socket.sendto("FOO 1 2", self.client_address)
+            logger.info("No proper response - wait for pending eap_sim_db request timeout")
+
+    server = SocketServer.UnixDatagramServer(sockpath, test_handler)
+    server.timeout = 1
+
+    dev[0].select_network(id)
+    server.handle_request()
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=10)
+    if ev is None:
+        raise Exception("EAP-Failure not reported")
+    dev[0].wait_disconnected()
+    dev[0].request("DISCONNECT")
+
+    # Test with a valid response
+
+    class test_handler2(SocketServer.DatagramRequestHandler):
+        def handle(self):
+            data = self.request[0].strip()
+            socket = self.request[1]
+            logger.debug("Received hlr_auc_gw request: " + data)
+            fname = os.path.join(params['logdir'],
+                                 'hlr_auc_gw.milenage_db')
+            cmd = subprocess.Popen(['../../hostapd/hlr_auc_gw',
+                                    '-m', fname, data],
+                                   stdout=subprocess.PIPE)
+            res = cmd.stdout.read().strip()
+            cmd.stdout.close()
+            logger.debug("hlr_auc_gw response: " + res)
+            socket.sendto(res, self.client_address)
+
+    server.RequestHandlerClass = test_handler2
+
+    dev[0].select_network(id)
+    server.handle_request()
+    dev[0].wait_connected()
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+def test_eap_tls_sha512(dev, apdev, params):
+    """EAP-TLS with SHA512 signature"""
+    params = int_eap_server_params()
+    params["ca_cert"] = "auth_serv/sha512-ca.pem"
+    params["server_cert"] = "auth_serv/sha512-server.pem"
+    params["private_key"] = "auth_serv/sha512-server.key"
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                   identity="tls user sha512",
+                   ca_cert="auth_serv/sha512-ca.pem",
+                   client_cert="auth_serv/sha512-user.pem",
+                   private_key="auth_serv/sha512-user.key",
+                   scan_freq="2412")
+    dev[1].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                   identity="tls user sha512",
+                   ca_cert="auth_serv/sha512-ca.pem",
+                   client_cert="auth_serv/sha384-user.pem",
+                   private_key="auth_serv/sha384-user.key",
+                   scan_freq="2412")
+
+def test_eap_tls_sha384(dev, apdev, params):
+    """EAP-TLS with SHA384 signature"""
+    params = int_eap_server_params()
+    params["ca_cert"] = "auth_serv/sha512-ca.pem"
+    params["server_cert"] = "auth_serv/sha384-server.pem"
+    params["private_key"] = "auth_serv/sha384-server.key"
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                   identity="tls user sha512",
+                   ca_cert="auth_serv/sha512-ca.pem",
+                   client_cert="auth_serv/sha512-user.pem",
+                   private_key="auth_serv/sha512-user.key",
+                   scan_freq="2412")
+    dev[1].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                   identity="tls user sha512",
+                   ca_cert="auth_serv/sha512-ca.pem",
+                   client_cert="auth_serv/sha384-user.pem",
+                   private_key="auth_serv/sha384-user.key",
+                   scan_freq="2412")
+
+def test_ap_wpa2_eap_assoc_rsn(dev, apdev):
+    """WPA2-Enterprise AP and association request RSN IE differences"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0], params)
+
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap-11w")
+    params["ieee80211w"] = "2"
+    hostapd.add_ap(apdev[1], params)
+
+    # Success cases with optional RSN IE fields removed one by one
+    tests = [ ("Normal wpa_supplicant assoc req RSN IE",
+               "30140100000fac040100000fac040100000fac010000"),
+              ("Extra PMKIDCount field in RSN IE",
+               "30160100000fac040100000fac040100000fac0100000000"),
+              ("Extra Group Management Cipher Suite in RSN IE",
+               "301a0100000fac040100000fac040100000fac0100000000000fac06"),
+              ("Extra undefined extension field in RSN IE",
+               "301c0100000fac040100000fac040100000fac0100000000000fac061122"),
+              ("RSN IE without RSN Capabilities",
+               "30120100000fac040100000fac040100000fac01"),
+              ("RSN IE without AKM", "300c0100000fac040100000fac04"),
+              ("RSN IE without pairwise", "30060100000fac04"),
+              ("RSN IE without group", "30020100") ]
+    for title, ie in tests:
+        logger.info(title)
+        set_test_assoc_ie(dev[0], ie)
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="GPSK",
+                       identity="gpsk user",
+                       password="abcdefghijklmnop0123456789abcdef",
+                       scan_freq="2412")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    tests = [ ("Normal wpa_supplicant assoc req RSN IE",
+               "30140100000fac040100000fac040100000fac01cc00"),
+              ("Group management cipher included in assoc req RSN IE",
+               "301a0100000fac040100000fac040100000fac01cc000000000fac06") ]
+    for title, ie in tests:
+        logger.info(title)
+        set_test_assoc_ie(dev[0], ie)
+        dev[0].connect("test-wpa2-eap-11w", key_mgmt="WPA-EAP", ieee80211w="1",
+                       eap="GPSK", identity="gpsk user",
+                       password="abcdefghijklmnop0123456789abcdef",
+                       scan_freq="2412")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    tests = [ ("Invalid group cipher", "30060100000fac02", 41),
+              ("Invalid pairwise cipher", "300c0100000fac040100000fac02", 42) ]
+    for title, ie, status in tests:
+        logger.info(title)
+        set_test_assoc_ie(dev[0], ie)
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="GPSK",
+                       identity="gpsk user",
+                       password="abcdefghijklmnop0123456789abcdef",
+                       scan_freq="2412", wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-EVENT-ASSOC-REJECT"])
+        if ev is None:
+            raise Exception("Association rejection not reported")
+        if "status_code=" + str(status) not in ev:
+            raise Exception("Unexpected status code: " + ev)
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].dump_monitor()
+
+    tests = [ ("Management frame protection not enabled",
+               "30140100000fac040100000fac040100000fac010000", 31),
+              ("Unsupported management group cipher",
+               "301a0100000fac040100000fac040100000fac01cc000000000fac0b", 31) ]
+    for title, ie, status in tests:
+        logger.info(title)
+        set_test_assoc_ie(dev[0], ie)
+        dev[0].connect("test-wpa2-eap-11w", key_mgmt="WPA-EAP", ieee80211w="1",
+                       eap="GPSK", identity="gpsk user",
+                       password="abcdefghijklmnop0123456789abcdef",
+                       scan_freq="2412", wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-EVENT-ASSOC-REJECT"])
+        if ev is None:
+            raise Exception("Association rejection not reported")
+        if "status_code=" + str(status) not in ev:
+            raise Exception("Unexpected status code: " + ev)
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].dump_monitor()
+
+def test_eap_tls_ext_cert_check(dev, apdev):
+    """EAP-TLS and external server certification validation"""
+    # With internal server certificate chain validation
+    id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                        identity="tls user",
+                        ca_cert="auth_serv/ca.pem",
+                        client_cert="auth_serv/user.pem",
+                        private_key="auth_serv/user.key",
+                        phase1="tls_ext_cert_check=1", scan_freq="2412",
+                        only_add_network=True)
+    run_ext_cert_check(dev, apdev, id)
+
+def test_eap_ttls_ext_cert_check(dev, apdev):
+    """EAP-TTLS and external server certification validation"""
+    # Without internal server certificate chain validation
+    id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                        identity="pap user", anonymous_identity="ttls",
+                        password="password", phase2="auth=PAP",
+                        phase1="tls_ext_cert_check=1", scan_freq="2412",
+                        only_add_network=True)
+    run_ext_cert_check(dev, apdev, id)
+
+def test_eap_peap_ext_cert_check(dev, apdev):
+    """EAP-PEAP and external server certification validation"""
+    # With internal server certificate chain validation
+    id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="PEAP",
+                        identity="user", anonymous_identity="peap",
+                        ca_cert="auth_serv/ca.pem",
+                        password="password", phase2="auth=MSCHAPV2",
+                        phase1="tls_ext_cert_check=1", scan_freq="2412",
+                        only_add_network=True)
+    run_ext_cert_check(dev, apdev, id)
+
+def test_eap_fast_ext_cert_check(dev, apdev):
+    """EAP-FAST and external server certification validation"""
+    check_eap_capa(dev[0], "FAST")
+    # With internal server certificate chain validation
+    dev[0].request("SET blob fast_pac_auth_ext ")
+    id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="FAST",
+                        identity="user", anonymous_identity="FAST",
+                        ca_cert="auth_serv/ca.pem",
+                        password="password", phase2="auth=GTC",
+                        phase1="tls_ext_cert_check=1 fast_provisioning=2",
+                        pac_file="blob://fast_pac_auth_ext",
+                        scan_freq="2412",
+                        only_add_network=True)
+    run_ext_cert_check(dev, apdev, id)
+
+def run_ext_cert_check(dev, apdev, net_id):
+    check_ext_cert_check_support(dev[0])
+    if not openssl_imported:
+        raise HwsimSkip("OpenSSL python method not available")
+
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].select_network(net_id)
+    certs = {}
+    while True:
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PEER-CERT",
+                                "CTRL-REQ-EXT_CERT_CHECK",
+                                "CTRL-EVENT-EAP-SUCCESS"], timeout=10)
+        if ev is None:
+            raise Exception("No peer server certificate event seen")
+        if "CTRL-EVENT-EAP-PEER-CERT" in ev:
+            depth = None
+            cert = None
+            vals = ev.split(' ')
+            for v in vals:
+                if v.startswith("depth="):
+                    depth = int(v.split('=')[1])
+                elif v.startswith("cert="):
+                    cert = v.split('=')[1]
+            if depth is not None and cert:
+                certs[depth] = binascii.unhexlify(cert)
+        elif "CTRL-EVENT-EAP-SUCCESS" in ev:
+            raise Exception("Unexpected EAP-Success")
+        elif "CTRL-REQ-EXT_CERT_CHECK" in ev:
+            id = ev.split(':')[0].split('-')[-1]
+            break
+    if 0 not in certs:
+        raise Exception("Server certificate not received")
+    if 1 not in certs:
+        raise Exception("Server certificate issuer not received")
+
+    cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_ASN1,
+                                           certs[0])
+    cn = cert.get_subject().commonName
+    logger.info("Server certificate CN=" + cn)
+
+    issuer = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_ASN1,
+                                             certs[1])
+    icn = issuer.get_subject().commonName
+    logger.info("Issuer certificate CN=" + icn)
+
+    if cn != "server.w1.fi":
+        raise Exception("Unexpected server certificate CN: " + cn)
+    if icn != "Root CA":
+        raise Exception("Unexpected server certificate issuer CN: " + icn)
+
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=0.1)
+    if ev:
+        raise Exception("Unexpected EAP-Success before external check result indication")
+
+    dev[0].request("CTRL-RSP-EXT_CERT_CHECK-" + id + ":good")
+    dev[0].wait_connected()
+
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+    if "FAIL" in dev[0].request("PMKSA_FLUSH"):
+        raise Exception("PMKSA_FLUSH failed")
+    dev[0].request("SET blob fast_pac_auth_ext ")
+    dev[0].request("RECONNECT")
+
+    ev = dev[0].wait_event(["CTRL-REQ-EXT_CERT_CHECK"], timeout=10)
+    if ev is None:
+        raise Exception("No peer server certificate event seen (2)")
+    id = ev.split(':')[0].split('-')[-1]
+    dev[0].request("CTRL-RSP-EXT_CERT_CHECK-" + id + ":bad")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+    if ev is None:
+        raise Exception("EAP-Failure not reported")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+def test_eap_tls_errors(dev, apdev):
+    """EAP-TLS error cases"""
+    params = int_eap_server_params()
+    params['fragment_size'] = '100'
+    hostapd.add_ap(apdev[0], params)
+    with alloc_fail(dev[0], 1,
+                    "eap_peer_tls_reassemble_fragment"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                       identity="tls user", ca_cert="auth_serv/ca.pem",
+                       client_cert="auth_serv/user.pem",
+                       private_key="auth_serv/user.key",
+                       wait_connect=False, scan_freq="2412")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    with alloc_fail(dev[0], 1, "eap_tls_init"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                       identity="tls user", ca_cert="auth_serv/ca.pem",
+                       client_cert="auth_serv/user.pem",
+                       private_key="auth_serv/user.key",
+                       wait_connect=False, scan_freq="2412")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    with alloc_fail(dev[0], 1, "eap_peer_tls_ssl_init"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                       identity="tls user", ca_cert="auth_serv/ca.pem",
+                       client_cert="auth_serv/user.pem",
+                       private_key="auth_serv/user.key",
+                       engine="1",
+                       wait_connect=False, scan_freq="2412")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        ev = dev[0].wait_event(["CTRL-REQ-PIN"], timeout=5)
+        if ev is None:
+            raise Exception("No CTRL-REQ-PIN seen")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    tests = [ "eap_peer_tls_derive_key;eap_tls_success",
+              "eap_peer_tls_derive_session_id;eap_tls_success",
+              "eap_tls_getKey",
+              "eap_tls_get_emsk",
+              "eap_tls_get_session_id" ]
+    for func in tests:
+        with alloc_fail(dev[0], 1, func):
+            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS",
+                           identity="tls user", ca_cert="auth_serv/ca.pem",
+                           client_cert="auth_serv/user.pem",
+                           private_key="auth_serv/user.key",
+                           erp="1",
+                           wait_connect=False, scan_freq="2412")
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    with alloc_fail(dev[0], 1, "eap_unauth_tls_init"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="UNAUTH-TLS",
+                       identity="unauth-tls", ca_cert="auth_serv/ca.pem",
+                       wait_connect=False, scan_freq="2412")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    with alloc_fail(dev[0], 1, "eap_peer_tls_ssl_init;eap_unauth_tls_init"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="UNAUTH-TLS",
+                       identity="unauth-tls", ca_cert="auth_serv/ca.pem",
+                       wait_connect=False, scan_freq="2412")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    with alloc_fail(dev[0], 1, "eap_wfa_unauth_tls_init"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
+                       eap="WFA-UNAUTH-TLS",
+                       identity="osen@example.com", ca_cert="auth_serv/ca.pem",
+                       wait_connect=False, scan_freq="2412")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    with alloc_fail(dev[0], 1, "eap_peer_tls_ssl_init;eap_wfa_unauth_tls_init"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
+                       eap="WFA-UNAUTH-TLS",
+                       identity="osen@example.com", ca_cert="auth_serv/ca.pem",
+                       wait_connect=False, scan_freq="2412")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+def test_ap_wpa2_eap_status(dev, apdev):
+    """EAP state machine status information"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hostapd.add_ap(apdev[0], params)
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="PEAP",
+                   identity="cert user",
+                   ca_cert="auth_serv/ca.pem", phase2="auth=TLS",
+                   ca_cert2="auth_serv/ca.pem",
+                   client_cert2="auth_serv/user.pem",
+                   private_key2="auth_serv/user.key",
+                   scan_freq="2412", wait_connect=False)
+    success = False
+    states = []
+    method_states = []
+    decisions = []
+    req_methods = []
+    selected_methods = []
+    for i in range(100000):
+        s = dev[0].get_status(extra="VERBOSE")
+        if 'EAP state' in s:
+            state = s['EAP state']
+            if state:
+                if state not in states:
+                    states.append(state)
+                if state == "SUCCESS":
+                    success = True
+                    break
+        if 'methodState' in s:
+            val = s['methodState']
+            if val not in method_states:
+                method_states.append(val)
+        if 'decision' in s:
+            val = s['decision']
+            if val not in decisions:
+                decisions.append(val)
+        if 'reqMethod' in s:
+            val = s['reqMethod']
+            if val not in req_methods:
+                req_methods.append(val)
+        if 'selectedMethod' in s:
+            val = s['selectedMethod']
+            if val not in selected_methods:
+                selected_methods.append(val)
+    logger.info("Iterations: %d" % i)
+    logger.info("EAP states: " + str(states))
+    logger.info("methodStates: " + str(method_states))
+    logger.info("decisions: " + str(decisions))
+    logger.info("reqMethods: " + str(req_methods))
+    logger.info("selectedMethods: " + str(selected_methods))
+    if not success:
+        raise Exception("EAP did not succeed")
+    dev[0].wait_connected()
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+def test_ap_wpa2_eap_gpsk_ptk_rekey_ap(dev, apdev):
+    """WPA2-Enterprise with EAP-GPSK and PTK rekey enforced by AP"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    params['wpa_ptk_rekey'] = '2'
+    hapd = hostapd.add_ap(apdev[0], params)
+    id = eap_connect(dev[0], hapd, "GPSK", "gpsk user",
+                     password="abcdefghijklmnop0123456789abcdef")
+    ev = dev[0].wait_event(["WPA: Key negotiation completed"])
+    if ev is None:
+        raise Exception("PTK rekey timed out")
+    hwsim_utils.test_connectivity(dev[0], hapd)
+
+def test_ap_wpa2_eap_wildcard_ssid(dev, apdev):
+    """WPA2-Enterprise connection using EAP-GPSK and wildcard SSID"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0], params)
+    dev[0].connect(bssid=apdev[0]['bssid'], key_mgmt="WPA-EAP", eap="GPSK",
+                   identity="gpsk user",
+                   password="abcdefghijklmnop0123456789abcdef",
+                   scan_freq="2412")
index f95966c..bd9b1ab 100644 (file)
@@ -4,10 +4,10 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import binascii
 import os
 import time
-import subprocess
 import logging
 logger = logging.getLogger()
 
@@ -93,14 +93,15 @@ def ft_params2_r0kh_mismatch(rsn=True, ssid=None, passphrase=None):
 
 def run_roams(dev, apdev, hapd0, hapd1, ssid, passphrase, over_ds=False,
               sae=False, eap=False, fail_test=False, roams=1,
-              pairwise_cipher="CCMP", group_cipher="TKIP CCMP"):
+              pairwise_cipher="CCMP", group_cipher="TKIP CCMP", ptk_rekey="0"):
     logger.info("Connect to first AP")
     if eap:
         dev.connect(ssid, key_mgmt="FT-EAP", proto="WPA2", ieee80211w="1",
                     eap="GPSK", identity="gpsk user",
                     password="abcdefghijklmnop0123456789abcdef",
                     scan_freq="2412",
-                    pairwise=pairwise_cipher, group=group_cipher)
+                    pairwise=pairwise_cipher, group=group_cipher,
+                    wpa_ptk_rekey=ptk_rekey)
     else:
         if sae:
             key_mgmt="FT-SAE"
@@ -108,7 +109,8 @@ def run_roams(dev, apdev, hapd0, hapd1, ssid, passphrase, over_ds=False,
             key_mgmt="FT-PSK"
         dev.connect(ssid, psk=passphrase, key_mgmt=key_mgmt, proto="WPA2",
                     ieee80211w="1", scan_freq="2412",
-                    pairwise=pairwise_cipher, group=group_cipher)
+                    pairwise=pairwise_cipher, group=group_cipher,
+                    wpa_ptk_rekey=ptk_rekey)
     if dev.get_status_field('bssid') == apdev[0]['bssid']:
         ap1 = apdev[0]
         ap2 = apdev[1]
@@ -152,9 +154,9 @@ def test_ap_ft(dev, apdev):
     passphrase="12345678"
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
     params = ft_params2(ssid=ssid, passphrase=passphrase)
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase)
     if "[WPA2-FT/PSK-CCMP]" not in dev[0].request("SCAN_RESULTS"):
@@ -166,9 +168,9 @@ def test_ap_ft_many(dev, apdev):
     passphrase="12345678"
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
     params = ft_params2(ssid=ssid, passphrase=passphrase)
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, roams=50)
 
@@ -178,13 +180,13 @@ def test_ap_ft_mixed(dev, apdev):
     passphrase="12345678"
 
     params = ft_params1(rsn=False, ssid=ssid, passphrase=passphrase)
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     key_mgmt = hapd.get_config()['key_mgmt']
     vals = key_mgmt.split(' ')
     if vals[0] != "WPA-PSK" or vals[1] != "FT-PSK":
         raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
     params = ft_params2(rsn=False, ssid=ssid, passphrase=passphrase)
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     run_roams(dev[0], apdev, hapd, hapd1, ssid, passphrase)
 
@@ -194,11 +196,11 @@ def test_ap_ft_pmf(dev, apdev):
     passphrase="12345678"
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
-    params["ieee80211w"] = "2";
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    params["ieee80211w"] = "2"
+    hapd0 = hostapd.add_ap(apdev[0], params)
     params = ft_params2(ssid=ssid, passphrase=passphrase)
-    params["ieee80211w"] = "2";
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    params["ieee80211w"] = "2"
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase)
 
@@ -208,9 +210,9 @@ def test_ap_ft_over_ds(dev, apdev):
     passphrase="12345678"
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
     params = ft_params2(ssid=ssid, passphrase=passphrase)
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, over_ds=True)
     check_mib(dev[0], [ ("dot11RSNAAuthenticationSuiteRequested", "00-0f-ac-4"),
@@ -222,34 +224,36 @@ def test_ap_ft_over_ds_many(dev, apdev):
     passphrase="12345678"
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
     params = ft_params2(ssid=ssid, passphrase=passphrase)
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, over_ds=True,
               roams=50)
 
+@remote_compatible
 def test_ap_ft_over_ds_unknown_target(dev, apdev):
     """WPA2-PSK-FT AP"""
     ssid = "test-ft"
     passphrase="12345678"
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect(ssid, psk=passphrase, key_mgmt="FT-PSK", proto="WPA2",
                    scan_freq="2412")
     dev[0].roam_over_ds("02:11:22:33:44:55", fail_test=True)
 
+@remote_compatible
 def test_ap_ft_over_ds_unexpected(dev, apdev):
     """WPA2-PSK-FT AP over DS and unexpected response"""
     ssid = "test-ft"
     passphrase="12345678"
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
     params = ft_params2(ssid=ssid, passphrase=passphrase)
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     dev[0].connect(ssid, psk=passphrase, key_mgmt="FT-PSK", proto="WPA2",
                    scan_freq="2412")
@@ -347,11 +351,11 @@ def test_ap_ft_pmf_over_ds(dev, apdev):
     passphrase="12345678"
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
-    params["ieee80211w"] = "2";
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    params["ieee80211w"] = "2"
+    hapd0 = hostapd.add_ap(apdev[0], params)
     params = ft_params2(ssid=ssid, passphrase=passphrase)
-    params["ieee80211w"] = "2";
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    params["ieee80211w"] = "2"
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, over_ds=True)
 
@@ -362,10 +366,10 @@ def test_ap_ft_over_ds_pull(dev, apdev):
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
     params["pmk_r1_push"] = "0"
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
     params = ft_params2(ssid=ssid, passphrase=passphrase)
     params["pmk_r1_push"] = "0"
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, over_ds=True)
 
@@ -378,10 +382,10 @@ def test_ap_ft_sae(dev, apdev):
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
     params['wpa_key_mgmt'] = "FT-SAE"
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
     params = ft_params2(ssid=ssid, passphrase=passphrase)
     params['wpa_key_mgmt'] = "FT-SAE"
-    hapd = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[1], params)
     key_mgmt = hapd.get_config()['key_mgmt']
     if key_mgmt.split(' ')[0] != "FT-SAE":
         raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
@@ -398,10 +402,10 @@ def test_ap_ft_sae_over_ds(dev, apdev):
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
     params['wpa_key_mgmt'] = "FT-SAE"
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
     params = ft_params2(ssid=ssid, passphrase=passphrase)
     params['wpa_key_mgmt'] = "FT-SAE"
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     dev[0].request("SET sae_groups ")
     run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, sae=True,
@@ -417,7 +421,7 @@ def test_ap_ft_eap(dev, apdev):
     params['wpa_key_mgmt'] = "FT-EAP"
     params["ieee8021x"] = "1"
     params = dict(radius.items() + params.items())
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     key_mgmt = hapd.get_config()['key_mgmt']
     if key_mgmt.split(' ')[0] != "FT-EAP":
         raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
@@ -425,7 +429,7 @@ def test_ap_ft_eap(dev, apdev):
     params['wpa_key_mgmt'] = "FT-EAP"
     params["ieee8021x"] = "1"
     params = dict(radius.items() + params.items())
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     run_roams(dev[0], apdev, hapd, hapd1, ssid, passphrase, eap=True)
     if "[WPA2-FT/EAP-CCMP]" not in dev[0].request("SCAN_RESULTS"):
@@ -433,6 +437,21 @@ def test_ap_ft_eap(dev, apdev):
     check_mib(dev[0], [ ("dot11RSNAAuthenticationSuiteRequested", "00-0f-ac-3"),
                         ("dot11RSNAAuthenticationSuiteSelected", "00-0f-ac-3") ])
 
+    # Verify EAPOL reauthentication after FT protocol
+    if dev[0].get_status_field('bssid') == apdev[0]['bssid']:
+        ap = hapd
+    else:
+        ap = hapd1
+    ap.request("EAPOL_REAUTH " + dev[0].own_addr())
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
+    if ev is None:
+        raise Exception("EAP authentication did not start")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=5)
+    if ev is None:
+        raise Exception("EAP authentication did not succeed")
+    time.sleep(0.1)
+    hwsim_utils.test_connectivity(dev[0], ap)
+
 def test_ap_ft_eap_pull(dev, apdev):
     """WPA2-EAP-FT AP (pull PMK)"""
     ssid = "test-ft"
@@ -444,7 +463,7 @@ def test_ap_ft_eap_pull(dev, apdev):
     params["ieee8021x"] = "1"
     params["pmk_r1_push"] = "0"
     params = dict(radius.items() + params.items())
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     key_mgmt = hapd.get_config()['key_mgmt']
     if key_mgmt.split(' ')[0] != "FT-EAP":
         raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
@@ -453,25 +472,27 @@ def test_ap_ft_eap_pull(dev, apdev):
     params["ieee8021x"] = "1"
     params["pmk_r1_push"] = "0"
     params = dict(radius.items() + params.items())
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     run_roams(dev[0], apdev, hapd, hapd1, ssid, passphrase, eap=True)
 
+@remote_compatible
 def test_ap_ft_mismatching_rrb_key_push(dev, apdev):
     """WPA2-PSK-FT AP over DS with mismatching RRB key (push)"""
     ssid = "test-ft"
     passphrase="12345678"
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
-    params["ieee80211w"] = "2";
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    params["ieee80211w"] = "2"
+    hapd0 = hostapd.add_ap(apdev[0], params)
     params = ft_params2_incorrect_rrb_key(ssid=ssid, passphrase=passphrase)
-    params["ieee80211w"] = "2";
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    params["ieee80211w"] = "2"
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, over_ds=True,
               fail_test=True)
 
+@remote_compatible
 def test_ap_ft_mismatching_rrb_key_pull(dev, apdev):
     """WPA2-PSK-FT AP over DS with mismatching RRB key (pull)"""
     ssid = "test-ft"
@@ -479,14 +500,15 @@ def test_ap_ft_mismatching_rrb_key_pull(dev, apdev):
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
     params["pmk_r1_push"] = "0"
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
     params = ft_params2_incorrect_rrb_key(ssid=ssid, passphrase=passphrase)
     params["pmk_r1_push"] = "0"
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, over_ds=True,
               fail_test=True)
 
+@remote_compatible
 def test_ap_ft_mismatching_r0kh_id_pull(dev, apdev):
     """WPA2-PSK-FT AP over DS with mismatching R0KH-ID (pull)"""
     ssid = "test-ft"
@@ -495,32 +517,34 @@ def test_ap_ft_mismatching_r0kh_id_pull(dev, apdev):
     params = ft_params1(ssid=ssid, passphrase=passphrase)
     params["pmk_r1_push"] = "0"
     params["nas_identifier"] = "nas0.w1.fi"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, key_mgmt="FT-PSK", proto="WPA2",
                    scan_freq="2412")
 
     params = ft_params2(ssid=ssid, passphrase=passphrase)
     params["pmk_r1_push"] = "0"
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     dev[0].scan_for_bss(apdev[1]['bssid'], freq="2412")
     dev[0].roam_over_ds(apdev[1]['bssid'], fail_test=True)
 
+@remote_compatible
 def test_ap_ft_mismatching_rrb_r0kh_push(dev, apdev):
     """WPA2-PSK-FT AP over DS with mismatching R0KH key (push)"""
     ssid = "test-ft"
     passphrase="12345678"
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
-    params["ieee80211w"] = "2";
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    params["ieee80211w"] = "2"
+    hapd0 = hostapd.add_ap(apdev[0], params)
     params = ft_params2_r0kh_mismatch(ssid=ssid, passphrase=passphrase)
-    params["ieee80211w"] = "2";
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    params["ieee80211w"] = "2"
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, over_ds=True,
               fail_test=True)
 
+@remote_compatible
 def test_ap_ft_mismatching_rrb_r0kh_pull(dev, apdev):
     """WPA2-PSK-FT AP over DS with mismatching R0KH key (pull)"""
     ssid = "test-ft"
@@ -528,10 +552,10 @@ def test_ap_ft_mismatching_rrb_r0kh_pull(dev, apdev):
 
     params = ft_params1_r0kh_mismatch(ssid=ssid, passphrase=passphrase)
     params["pmk_r1_push"] = "0"
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
     params = ft_params2(ssid=ssid, passphrase=passphrase)
     params["pmk_r1_push"] = "0"
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, over_ds=True,
               fail_test=True)
@@ -543,7 +567,7 @@ def test_ap_ft_gtk_rekey(dev, apdev):
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
     params['wpa_group_rekey'] = '1'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect(ssid, psk=passphrase, key_mgmt="FT-PSK", proto="WPA2",
                    ieee80211w="1", scan_freq="2412")
@@ -555,7 +579,7 @@ def test_ap_ft_gtk_rekey(dev, apdev):
 
     params = ft_params2(ssid=ssid, passphrase=passphrase)
     params['wpa_group_rekey'] = '1'
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     dev[0].scan_for_bss(apdev[1]['bssid'], freq="2412")
     dev[0].roam(apdev[1]['bssid'])
@@ -575,15 +599,19 @@ def test_ft_psk_key_lifetime_in_memory(dev, apdev, params):
     psk = '93c90846ff67af9037ed83fb72b63dbeddaa81d47f926c20909b5886f1d9358d'
     pmk = binascii.unhexlify(psk)
     p = ft_params1(ssid=ssid, passphrase=passphrase)
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], p)
+    hapd0 = hostapd.add_ap(apdev[0], p)
     p = ft_params2(ssid=ssid, passphrase=passphrase)
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], p)
+    hapd1 = hostapd.add_ap(apdev[1], p)
 
     pid = find_wpas_process(dev[0])
 
     dev[0].connect(ssid, psk=passphrase, key_mgmt="FT-PSK", proto="WPA2",
                    scan_freq="2412")
+    # The decrypted copy of GTK is freed only after the CTRL-EVENT-CONNECTED
+    # event has been delivered, so verify that wpa_supplicant has returned to
+    # eloop before reading process memory.
     time.sleep(1)
+    dev[0].ping()
 
     buf = read_process_memory(pid, pmk)
 
@@ -637,6 +665,7 @@ def test_ft_psk_key_lifetime_in_memory(dev, apdev, params):
     if tk in buf:
         raise Exception("TK found from memory")
     if gtk in buf:
+        get_key_locations(buf, gtk, "GTK")
         raise Exception("GTK found from memory")
 
     logger.info("Checking keys in memory after disassociation")
@@ -672,18 +701,19 @@ def test_ft_psk_key_lifetime_in_memory(dev, apdev, params):
     verify_not_present(buf, tk, fname, "TK")
     verify_not_present(buf, gtk, fname, "GTK")
 
+@remote_compatible
 def test_ap_ft_invalid_resp(dev, apdev):
     """WPA2-PSK-FT AP and invalid response IEs"""
     ssid = "test-ft"
     passphrase="12345678"
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, key_mgmt="FT-PSK", proto="WPA2",
                    scan_freq="2412")
 
     params = ft_params2(ssid=ssid, passphrase=passphrase)
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     tests = [
         # Various IEs for test coverage. The last one is FTIE with invalid
@@ -738,10 +768,10 @@ def test_ap_ft_gcmp_256(dev, apdev):
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
     params['rsn_pairwise'] = "GCMP-256"
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
     params = ft_params2(ssid=ssid, passphrase=passphrase)
     params['rsn_pairwise'] = "GCMP-256"
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase,
               pairwise_cipher="GCMP-256", group_cipher="GCMP-256")
@@ -753,9 +783,9 @@ def test_ap_ft_oom(dev, apdev):
     passphrase="12345678"
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
     params = ft_params2(ssid=ssid, passphrase=passphrase)
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     dev[0].connect(ssid, psk=passphrase, key_mgmt="FT-PSK", proto="WPA2",
                    scan_freq="2412")
@@ -767,18 +797,23 @@ def test_ap_ft_oom(dev, apdev):
     dev[0].scan_for_bss(dst, freq="2412")
     with alloc_fail(dev[0], 1, "wpa_ft_gen_req_ies"):
         dev[0].roam(dst)
-    with alloc_fail(dev[0], 1, "wpa_ft_mic"):
+    with fail_test(dev[0], 1, "wpa_ft_mic"):
         dev[0].roam(dst, fail_test=True)
     with fail_test(dev[0], 1, "os_get_random;wpa_ft_prepare_auth_request"):
         dev[0].roam(dst, fail_test=True)
 
+    dev[0].request("REMOVE_NETWORK all")
+    with alloc_fail(dev[0], 1, "=sme_update_ft_ies"):
+        dev[0].connect(ssid, psk=passphrase, key_mgmt="FT-PSK", proto="WPA2",
+                       scan_freq="2412")
+
 def test_ap_ft_over_ds_proto(dev, apdev):
     """WPA2-PSK-FT AP over DS protocol testing"""
     ssid = "test-ft"
     passphrase="12345678"
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, key_mgmt="FT-PSK", proto="WPA2",
                    scan_freq="2412")
 
@@ -792,7 +827,7 @@ def test_ap_ft_over_ds_proto(dev, apdev):
     hapd0.mgmt_tx(msg)
 
     params = ft_params2(ssid=ssid, passphrase=passphrase)
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
     dev[0].scan_for_bss(apdev[1]['bssid'], freq="2412")
     hapd0.set("ext_mgmt_frame_handling", "1")
     hapd0.dump_monitor()
@@ -823,13 +858,14 @@ def test_ap_ft_over_ds_proto(dev, apdev):
     msg['payload'] = binascii.unhexlify("0602020000000000" + "020000000400" + "0000" + "3603a1b201" + "3766000000000000000000000000000000000000c4e67ac1999bebd00ff4ae4d5dcaf87896bb060b469f7c78d49623fb395c3455ffffff6b693fe6f8d8c5dfac0a22344750775bd09437f98b238c9f87b97f790c0106000102030406030a6e6173312e77312e6669")
     hapd0.mgmt_tx(msg)
 
+@remote_compatible
 def test_ap_ft_rrb(dev, apdev):
     """WPA2-PSK-FT RRB protocol testing"""
     ssid = "test-ft"
     passphrase="12345678"
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect(ssid, psk=passphrase, key_mgmt="FT-PSK", proto="WPA2",
                    scan_freq="2412")
@@ -914,6 +950,7 @@ def test_ap_ft_rrb(dev, apdev):
     if "OK" not in dev[0].request("DATA_TEST_FRAME " + binascii.hexlify(pkt)):
         raise Exception("DATA_TEST_FRAME failed")
 
+@remote_compatible
 def test_rsn_ie_proto_ft_psk_sta(dev, apdev):
     """RSN element protocol testing for FT-PSK + PMF cases on STA side"""
     bssid = apdev[0]['bssid']
@@ -921,10 +958,10 @@ def test_rsn_ie_proto_ft_psk_sta(dev, apdev):
     passphrase="12345678"
 
     params = ft_params1(ssid=ssid, passphrase=passphrase)
-    params["ieee80211w"] = "1";
+    params["ieee80211w"] = "1"
     # This is the RSN element used normally by hostapd
     params['own_ie_override'] = '30140100000fac040100000fac040100000fac048c00' + '3603a1b201'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     id = dev[0].connect(ssid, psk=passphrase, key_mgmt="FT-PSK", proto="WPA2",
                         ieee80211w="1", scan_freq="2412",
                         pairwise="CCMP", group="CCMP")
@@ -981,3 +1018,82 @@ def test_rsn_ie_proto_ft_psk_sta(dev, apdev):
     if ev is not None:
         raise Exception("Unexpected connection")
     dev[0].request("DISCONNECT")
+
+def test_ap_ft_ptk_rekey(dev, apdev):
+    """WPA2-PSK-FT PTK rekeying triggered by station after roam"""
+    ssid = "test-ft"
+    passphrase="12345678"
+
+    params = ft_params1(ssid=ssid, passphrase=passphrase)
+    hapd0 = hostapd.add_ap(apdev[0], params)
+    params = ft_params2(ssid=ssid, passphrase=passphrase)
+    hapd1 = hostapd.add_ap(apdev[1], params)
+
+    run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, ptk_rekey="1")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED",
+                            "WPA: Key negotiation completed"], timeout=5)
+    if ev is None:
+        raise Exception("No event received after roam")
+    if "CTRL-EVENT-DISCONNECTED" in ev:
+        raise Exception("Unexpected disconnection after roam")
+
+    if dev[0].get_status_field('bssid') == apdev[0]['bssid']:
+        hapd = hapd0
+    else:
+        hapd = hapd1
+    hwsim_utils.test_connectivity(dev[0], hapd)
+
+def test_ap_ft_ptk_rekey_ap(dev, apdev):
+    """WPA2-PSK-FT PTK rekeying triggered by AP after roam"""
+    ssid = "test-ft"
+    passphrase="12345678"
+
+    params = ft_params1(ssid=ssid, passphrase=passphrase)
+    params['wpa_ptk_rekey'] = '2'
+    hapd0 = hostapd.add_ap(apdev[0], params)
+    params = ft_params2(ssid=ssid, passphrase=passphrase)
+    params['wpa_ptk_rekey'] = '2'
+    hapd1 = hostapd.add_ap(apdev[1], params)
+
+    run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase)
+
+    ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED",
+                            "WPA: Key negotiation completed"], timeout=5)
+    if ev is None:
+        raise Exception("No event received after roam")
+    if "CTRL-EVENT-DISCONNECTED" in ev:
+        raise Exception("Unexpected disconnection after roam")
+
+    if dev[0].get_status_field('bssid') == apdev[0]['bssid']:
+        hapd = hapd0
+    else:
+        hapd = hapd1
+    hwsim_utils.test_connectivity(dev[0], hapd)
+
+def test_ap_ft_internal_rrb_check(dev, apdev):
+    """RRB internal delivery only to WPA enabled BSS"""
+    ssid = "test-ft"
+    passphrase="12345678"
+
+    radius = hostapd.radius_params()
+    params = ft_params1(ssid=ssid, passphrase=passphrase)
+    params['wpa_key_mgmt'] = "FT-EAP"
+    params["ieee8021x"] = "1"
+    params = dict(radius.items() + params.items())
+    hapd = hostapd.add_ap(apdev[0], params)
+    key_mgmt = hapd.get_config()['key_mgmt']
+    if key_mgmt.split(' ')[0] != "FT-EAP":
+        raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
+
+    hapd1 = hostapd.add_ap(apdev[1], { "ssid" : ssid })
+
+    # Connect to WPA enabled AP
+    dev[0].connect(ssid, key_mgmt="FT-EAP", proto="WPA2", ieee80211w="1",
+                   eap="GPSK", identity="gpsk user",
+                   password="abcdefghijklmnop0123456789abcdef",
+                   scan_freq="2412")
+
+    # Try over_ds roaming to non-WPA-enabled AP.
+    # If hostapd does not check hapd->wpa_auth internally, it will crash now.
+    dev[0].roam_over_ds(apdev[1]['bssid'], fail_test=True)
index 27f9e87..6a7e52a 100644 (file)
@@ -4,10 +4,11 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
+import base64
 import binascii
 import struct
 import time
-import subprocess
 import logging
 logger = logging.getLogger()
 import os
@@ -16,12 +17,13 @@ import socket
 import subprocess
 
 import hostapd
-from utils import HwsimSkip, skip_with_fips
+from utils import HwsimSkip, skip_with_fips, alloc_fail, wait_fail_trigger
 import hwsim_utils
 from tshark import run_tshark
 from wlantest import Wlantest
 from wpasupplicant import WpaSupplicant
 from test_ap_eap import check_eap_capa, check_domain_match_full
+from test_gas import gas_rx, parse_gas, action_response, anqp_initial_resp, send_gas_resp, ACTION_CATEG_PUBLIC, GAS_INITIAL_RESPONSE
 
 def hs20_ap_params(ssid="test-hs20"):
     params = hostapd.wpa2_params(ssid=ssid)
@@ -60,6 +62,7 @@ def check_auto_select(dev, bssid):
         raise Exception("Connected to incorrect network")
     dev.request("REMOVE_NETWORK all")
     dev.wait_disconnected()
+    dev.dump_monitor()
 
 def interworking_select(dev, bssid, type=None, no_match=False, freq=None):
     dev.dump_monitor()
@@ -70,7 +73,7 @@ def interworking_select(dev, bssid, type=None, no_match=False, freq=None):
     ev = dev.wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH"],
                         timeout=15)
     if ev is None:
-        raise Exception("Network selection timed out");
+        raise Exception("Network selection timed out")
     if no_match:
         if "INTERWORKING-NO-MATCH" not in ev:
             raise Exception("Unexpected network match")
@@ -82,7 +85,7 @@ def interworking_select(dev, bssid, type=None, no_match=False, freq=None):
         ev = dev.wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH"],
                             timeout=15)
         if ev is None:
-            raise Exception("Network selection timed out");
+            raise Exception("Network selection timed out")
         if "INTERWORKING-NO-MATCH" in ev:
             raise Exception("Matching network not found")
     if bssid and bssid not in ev:
@@ -166,13 +169,13 @@ def test_ap_anqp_sharing(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     bssid2 = apdev[1]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
     params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]" ]
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com", 'username': "test",
@@ -210,6 +213,91 @@ def test_ap_anqp_sharing(dev, apdev):
     if res1['anqp_nai_realm'] == res2['anqp_nai_realm']:
         raise Exception("ANQP results were not unshared")
 
+def test_ap_anqp_no_sharing_diff_ess(dev, apdev):
+    """ANQP no sharing between ESSs"""
+    check_eap_capa(dev[0], "MSCHAPV2")
+    dev[0].flush_scan_cache()
+
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    hostapd.add_ap(apdev[0], params)
+
+    bssid2 = apdev[1]['bssid']
+    params = hs20_ap_params(ssid="test-hs20-another")
+    params['hessid'] = bssid
+    params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]" ]
+    hostapd.add_ap(apdev[1], params)
+
+    dev[0].hs20_enable()
+    id = dev[0].add_cred_values({ 'realm': "example.com", 'username': "test",
+                                  'password': "secret",
+                                  'domain': "example.com" })
+    logger.info("Normal network selection with shared ANQP results")
+    dev[0].scan_for_bss(bssid, freq="2412")
+    dev[0].scan_for_bss(bssid2, freq="2412")
+    interworking_select(dev[0], None, "home", freq="2412")
+
+def test_ap_anqp_no_sharing_missing_info(dev, apdev):
+    """ANQP no sharing due to missing information"""
+    check_eap_capa(dev[0], "MSCHAPV2")
+    dev[0].flush_scan_cache()
+
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    del params['roaming_consortium']
+    del params['domain_name']
+    del params['anqp_3gpp_cell_net']
+    del params['nai_realm']
+    hostapd.add_ap(apdev[0], params)
+
+    bssid2 = apdev[1]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]" ]
+    hostapd.add_ap(apdev[1], params)
+
+    dev[0].hs20_enable()
+    id = dev[0].add_cred_values({ 'realm': "example.com", 'username': "test",
+                                  'password': "secret",
+                                  'domain': "example.com" })
+    logger.info("Normal network selection with shared ANQP results")
+    dev[0].scan_for_bss(bssid, freq="2412")
+    dev[0].scan_for_bss(bssid2, freq="2412")
+    interworking_select(dev[0], None, "home", freq="2412")
+
+def test_ap_anqp_sharing_oom(dev, apdev):
+    """ANQP sharing within ESS and explicit unshare OOM"""
+    check_eap_capa(dev[0], "MSCHAPV2")
+    dev[0].flush_scan_cache()
+
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    hostapd.add_ap(apdev[0], params)
+
+    bssid2 = apdev[1]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]" ]
+    hostapd.add_ap(apdev[1], params)
+
+    dev[0].hs20_enable()
+    id = dev[0].add_cred_values({ 'realm': "example.com", 'username': "test",
+                                  'password': "secret",
+                                  'domain': "example.com" })
+    dev[0].scan_for_bss(bssid, freq="2412")
+    dev[0].scan_for_bss(bssid2, freq="2412")
+    interworking_select(dev[0], None, "home", freq="2412")
+    dev[0].dump_monitor()
+
+    with alloc_fail(dev[0], 1, "wpa_bss_anqp_clone"):
+        dev[0].request("ANQP_GET " + bssid + " 263")
+        ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
+        if ev is None:
+            raise Exception("ANQP operation timed out")
+
 def test_ap_nai_home_realm_query(dev, apdev):
     """NAI Home Realm Query"""
     check_eap_capa(dev[0], "MSCHAPV2")
@@ -217,7 +305,7 @@ def test_ap_nai_home_realm_query(dev, apdev):
     params = hs20_ap_params()
     params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]",
                             "0,another.example.org" ]
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].scan(freq="2412")
     dev[0].request("HS20_GET_NAI_HOME_REALM_LIST " + bssid + " realm=example.com")
@@ -282,6 +370,7 @@ def test_ap_nai_home_realm_query(dev, apdev):
     if "NAI Realm list" not in ev:
         raise Exception("Missing NAI Realm list: " + ev)
 
+@remote_compatible
 def test_ap_interworking_scan_filtering(dev, apdev):
     """Interworking scan filtering with HESSID and access network type"""
     try:
@@ -296,7 +385,7 @@ def _test_ap_interworking_scan_filtering(dev, apdev):
     ssid = "test-hs20-ap1"
     params['ssid'] = ssid
     params['hessid'] = bssid
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
 
     bssid2 = apdev[1]['bssid']
     params = hs20_ap_params()
@@ -306,10 +395,11 @@ def _test_ap_interworking_scan_filtering(dev, apdev):
     params['access_network_type'] = "1"
     del params['venue_group']
     del params['venue_type']
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     dev[0].hs20_enable()
 
+    Wlantest.setup(hapd0)
     wt = Wlantest()
     wt.flush()
 
@@ -371,7 +461,7 @@ def test_ap_hs20_select(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com", 'username': "test",
@@ -385,7 +475,7 @@ def test_ap_hs20_select(dev, apdev):
                                   'domain': "no.match.example.com" })
     interworking_select(dev[0], bssid, "roaming", freq="2412")
 
-    dev[0].set_cred_quoted(id, "realm", "no.match.example.com");
+    dev[0].set_cred_quoted(id, "realm", "no.match.example.com")
     interworking_select(dev[0], bssid, no_match=True, freq="2412")
 
     res = dev[0].request("SCAN_RESULTS")
@@ -397,7 +487,7 @@ def test_ap_hs20_select(dev, apdev):
     params['nai_realm'] = [ "0,example.org,21" ]
     params['hessid'] = bssid2
     params['domain_name'] = "example.org"
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
     dev[0].remove_cred(id)
     id = dev[0].add_cred_values({ 'realm': "example.org", 'username': "test",
                                   'password': "secret",
@@ -410,12 +500,12 @@ def hs20_simulated_sim(dev, ap, method):
     params['hessid'] = bssid
     params['anqp_3gpp_cell_net'] = "555,444"
     params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
-    hostapd.add_ap(ap['ifname'], params)
+    hostapd.add_ap(ap, params)
 
     dev.hs20_enable()
     dev.add_cred_values({ 'imsi': "555444-333222111", 'eap': method,
                           'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"})
-    interworking_select(dev, "home", freq="2412")
+    interworking_select(dev, bssid, "home", freq="2412")
     interworking_connect(dev, bssid, method)
     check_sp_type(dev, "home")
 
@@ -428,6 +518,46 @@ def test_ap_hs20_sim(dev, apdev):
     if ev is None:
         raise Exception("Timeout on already-connected event")
 
+def test_ap_hs20_sim_invalid(dev, apdev):
+    """Hotspot 2.0 with simulated SIM and EAP-SIM - invalid IMSI"""
+    hlr_auc_gw_available()
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    params['anqp_3gpp_cell_net'] = "555,444"
+    params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    dev[0].add_cred_values({ 'imsi': "555444-3332221110", 'eap': "SIM",
+                          'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"})
+    # This hits "No valid IMSI available" in build_root_nai()
+    interworking_select(dev[0], bssid, freq="2412")
+
+def test_ap_hs20_sim_oom(dev, apdev):
+    """Hotspot 2.0 with simulated SIM and EAP-SIM - OOM"""
+    hlr_auc_gw_available()
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    params['anqp_3gpp_cell_net'] = "555,444"
+    params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    dev[0].add_cred_values({ 'imsi': "555444-333222111", 'eap': "SIM",
+                          'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"})
+    dev[0].scan_for_bss(bssid, freq=2412)
+    interworking_select(dev[0], bssid, freq="2412")
+
+    with alloc_fail(dev[0], 1, "wpa_config_add_network;interworking_connect_3gpp"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+    with alloc_fail(dev[0], 1, "=interworking_connect_3gpp"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
 def test_ap_hs20_aka(dev, apdev):
     """Hotspot 2.0 with simulated USIM and EAP-AKA"""
     hlr_auc_gw_available()
@@ -446,13 +576,13 @@ def test_ap_hs20_ext_sim(dev, apdev):
     params['hessid'] = bssid
     params['anqp_3gpp_cell_net'] = "232,01"
     params['domain_name'] = "wlan.mnc001.mcc232.3gppnetwork.org"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     try:
         dev[0].request("SET external_sim 1")
         dev[0].add_cred_values({ 'imsi': "23201-0000000000", 'eap': "SIM" })
-        interworking_select(dev[0], "home", freq="2412")
+        interworking_select(dev[0], bssid, "home", freq="2412")
         interworking_ext_sim_connect(dev[0], bssid, "SIM")
         check_sp_type(dev[0], "home")
     finally:
@@ -466,13 +596,13 @@ def test_ap_hs20_ext_sim_roaming(dev, apdev):
     params['hessid'] = bssid
     params['anqp_3gpp_cell_net'] = "244,91;310,026;232,01;234,56"
     params['domain_name'] = "wlan.mnc091.mcc244.3gppnetwork.org"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     try:
         dev[0].request("SET external_sim 1")
         dev[0].add_cred_values({ 'imsi': "23201-0000000000", 'eap': "SIM" })
-        interworking_select(dev[0], "roaming", freq="2412")
+        interworking_select(dev[0], bssid, "roaming", freq="2412")
         interworking_ext_sim_connect(dev[0], bssid, "SIM")
         check_sp_type(dev[0], "roaming")
     finally:
@@ -485,7 +615,7 @@ def test_ap_hs20_username(dev, apdev):
     params = hs20_ap_params()
     params['hessid'] = bssid
     params['disable_dgaf'] = '1'
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com",
@@ -515,7 +645,7 @@ def test_ap_hs20_connect_api(dev, apdev):
     params = hs20_ap_params()
     params['hessid'] = bssid
     params['disable_dgaf'] = '1'
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
@@ -543,7 +673,7 @@ def test_ap_hs20_auto_interworking(dev, apdev):
     params = hs20_ap_params()
     params['hessid'] = bssid
     params['disable_dgaf'] = '1'
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable(auto_interworking=True)
     id = dev[0].add_cred_values({ 'realm': "example.com",
@@ -561,9 +691,10 @@ def test_ap_hs20_auto_interworking(dev, apdev):
     if status['hs20'] != "2":
         raise Exception("Unexpected HS 2.0 support indication")
 
+@remote_compatible
 def test_ap_hs20_auto_interworking_no_match(dev, apdev):
     """Hotspot 2.0 connection with auto_interworking=1 and no matching network"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "mismatch" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "mismatch" })
 
     dev[0].hs20_enable(auto_interworking=True)
     id = dev[0].connect("mismatch", psk="12345678", scan_freq="2412",
@@ -600,11 +731,12 @@ def test_ap_hs20_auto_interworking_no_match(dev, apdev):
         dev[0].dump_monitor()
     dev[0].request("DISCONNECT")
 
+@remote_compatible
 def test_ap_hs20_auto_interworking_no_cred_match(dev, apdev):
     """Hotspot 2.0 connection with auto_interworking=1 but no cred match"""
     bssid = apdev[0]['bssid']
     params = { "ssid": "test" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable(auto_interworking=True)
     dev[0].add_cred_values({ 'realm': "example.com",
@@ -626,7 +758,7 @@ def eap_test(dev, ap, eap_params, method, user):
     bssid = ap['bssid']
     params = hs20_ap_params()
     params['nai_realm'] = [ "0,example.com," + eap_params ]
-    hostapd.add_ap(ap['ifname'], params)
+    hostapd.add_ap(ap, params)
 
     dev.hs20_enable()
     dev.add_cred_values({ 'realm': "example.com",
@@ -636,12 +768,13 @@ def eap_test(dev, ap, eap_params, method, user):
     interworking_select(dev, bssid, freq="2412")
     interworking_connect(dev, bssid, method)
 
+@remote_compatible
 def test_ap_hs20_eap_unknown(dev, apdev):
     """Hotspot 2.0 connection with unknown EAP method"""
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['nai_realm'] = "0,example.com,99"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].add_cred_values(default_cred())
@@ -661,12 +794,13 @@ def test_ap_hs20_eap_peap_gtc(dev, apdev):
     """Hotspot 2.0 connection with PEAP/GTC"""
     eap_test(dev[0], apdev[0], "25[3:6]", "PEAP", "user")
 
+@remote_compatible
 def test_ap_hs20_eap_peap_unknown(dev, apdev):
     """Hotspot 2.0 connection with PEAP/unknown"""
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['nai_realm'] = "0,example.com,25[3:99]"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].add_cred_values(default_cred())
@@ -682,39 +816,47 @@ def test_ap_hs20_eap_ttls_mschap(dev, apdev):
     skip_with_fips(dev[0])
     eap_test(dev[0], apdev[0], "21[2:3]", "TTLS", "mschap user")
 
+def test_ap_hs20_eap_ttls_default(dev, apdev):
+    """Hotspot 2.0 connection with TTLS/default"""
+    skip_with_fips(dev[0])
+    eap_test(dev[0], apdev[0], "21", "TTLS", "hs20-test")
+
 def test_ap_hs20_eap_ttls_eap_mschapv2(dev, apdev):
     """Hotspot 2.0 connection with TTLS/EAP-MSCHAPv2"""
     check_eap_capa(dev[0], "MSCHAPV2")
     eap_test(dev[0], apdev[0], "21[3:26][6:7][99:99]", "TTLS", "user")
 
+@remote_compatible
 def test_ap_hs20_eap_ttls_eap_unknown(dev, apdev):
     """Hotspot 2.0 connection with TTLS/EAP-unknown"""
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['nai_realm'] = "0,example.com,21[3:99]"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].add_cred_values(default_cred())
     interworking_select(dev[0], None, no_match=True, freq="2412")
 
+@remote_compatible
 def test_ap_hs20_eap_ttls_eap_unsupported(dev, apdev):
     """Hotspot 2.0 connection with TTLS/EAP-OTP(unsupported)"""
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['nai_realm'] = "0,example.com,21[3:5]"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].add_cred_values(default_cred())
     interworking_select(dev[0], None, no_match=True, freq="2412")
 
+@remote_compatible
 def test_ap_hs20_eap_ttls_unknown(dev, apdev):
     """Hotspot 2.0 connection with TTLS/unknown"""
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['nai_realm'] = "0,example.com,21[2:5]"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].add_cred_values(default_cred())
@@ -735,7 +877,7 @@ def test_ap_hs20_eap_tls(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['nai_realm'] = [ "0,example.com,13[5:6]" ]
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].add_cred_values({ 'realm': "example.com",
@@ -746,12 +888,13 @@ def test_ap_hs20_eap_tls(dev, apdev):
     interworking_select(dev[0], bssid, freq="2412")
     interworking_connect(dev[0], bssid, "TLS")
 
+@remote_compatible
 def test_ap_hs20_eap_cert_unknown(dev, apdev):
     """Hotspot 2.0 connection with certificate, but unknown EAP method"""
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['nai_realm'] = [ "0,example.com,99[5:6]" ]
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].add_cred_values({ 'realm': "example.com",
@@ -761,12 +904,13 @@ def test_ap_hs20_eap_cert_unknown(dev, apdev):
                              'private_key': "auth_serv/user.key"})
     interworking_select(dev[0], None, no_match=True, freq="2412")
 
+@remote_compatible
 def test_ap_hs20_eap_cert_unsupported(dev, apdev):
     """Hotspot 2.0 connection with certificate, but unsupported TTLS"""
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['nai_realm'] = [ "0,example.com,21[5:6]" ]
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].add_cred_values({ 'realm': "example.com",
@@ -776,11 +920,12 @@ def test_ap_hs20_eap_cert_unsupported(dev, apdev):
                              'private_key': "auth_serv/user.key"})
     interworking_select(dev[0], None, no_match=True, freq="2412")
 
+@remote_compatible
 def test_ap_hs20_eap_invalid_cred(dev, apdev):
     """Hotspot 2.0 connection with invalid cred configuration"""
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].add_cred_values({ 'realm': "example.com",
@@ -794,7 +939,7 @@ def test_ap_hs20_nai_realms(dev, apdev):
     params = hs20_ap_params()
     params['hessid'] = bssid
     params['nai_realm'] = [ "0,no.match.here;example.com;no.match.here.either,21[2:1][5:7]" ]
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com",
@@ -811,7 +956,7 @@ def test_ap_hs20_roaming_consortium(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     for consortium in [ "112233", "1020304050", "010203040506", "fedcba" ]:
@@ -830,6 +975,252 @@ def test_ap_hs20_roaming_consortium(dev, apdev):
             raise Exception("Timeout on already-connected event")
         dev[0].remove_cred(id)
 
+def test_ap_hs20_roaming_consortium_invalid(dev, apdev):
+    """Hotspot 2.0 connection and invalid roaming consortium ANQP-element"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    # Override Roaming Consortium ANQP-element with an incorrectly encoded
+    # value.
+    params['anqp_elem'] = "261:04fedcba"
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    id = dev[0].add_cred_values({ 'username': "user",
+                                  'password': "password",
+                                  'domain': "example.com",
+                                  'ca_cert': "auth_serv/ca.pem",
+                                  'roaming_consortium': "fedcba",
+                                  'eap': "PEAP" })
+    interworking_select(dev[0], bssid, "home", freq="2412", no_match=True)
+
+def test_ap_hs20_roaming_consortium_element(dev, apdev):
+    """Hotspot 2.0 connection and invalid roaming consortium element"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    del params['roaming_consortium']
+    params['vendor_elements'] = '6f00'
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    dev[0].scan_for_bss(bssid, freq="2412")
+    id = dev[0].add_cred_values({ 'username': "user",
+                                  'password': "password",
+                                  'domain': "example.com",
+                                  'ca_cert': "auth_serv/ca.pem",
+                                  'roaming_consortium': "112233",
+                                  'eap': "PEAP" })
+    interworking_select(dev[0], bssid, freq="2412", no_match=True)
+
+    hapd.set('vendor_elements', '6f020001')
+    if "OK" not in hapd.request("UPDATE_BEACON"):
+        raise Exception("UPDATE_BEACON failed")
+    dev[0].request("BSS_FLUSH 0")
+    dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
+    interworking_select(dev[0], bssid, freq="2412", no_match=True)
+
+def test_ap_hs20_roaming_consortium_constraints(dev, apdev):
+    """Hotspot 2.0 connection and roaming consortium constraints"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    params['bss_load_test'] = "12:200:20000"
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+
+    vals = { 'username': "user",
+             'password': "password",
+             'domain': "example.com",
+             'ca_cert': "auth_serv/ca.pem",
+             'roaming_consortium': "fedcba",
+             'eap': "TTLS" }
+    vals2 = vals.copy()
+    vals2['required_roaming_consortium'] = "223344"
+    id = dev[0].add_cred_values(vals2)
+    interworking_select(dev[0], bssid, "home", freq="2412", no_match=True)
+    dev[0].remove_cred(id)
+
+    vals2 = vals.copy()
+    vals2['min_dl_bandwidth_home'] = "65500"
+    id = dev[0].add_cred_values(vals2)
+    dev[0].request("INTERWORKING_SELECT freq=2412")
+    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
+    if ev is None:
+        raise Exception("No AP found")
+    if "below_min_backhaul=1" not in ev:
+        raise Exception("below_min_backhaul not reported")
+    dev[0].remove_cred(id)
+
+    vals2 = vals.copy()
+    vals2['max_bss_load'] = "100"
+    id = dev[0].add_cred_values(vals2)
+    dev[0].request("INTERWORKING_SELECT freq=2412")
+    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
+    if ev is None:
+        raise Exception("No AP found")
+    if "over_max_bss_load=1" not in ev:
+        raise Exception("over_max_bss_load not reported")
+    dev[0].remove_cred(id)
+
+    vals2 = vals.copy()
+    vals2['req_conn_capab'] = "6:1234"
+    vals2['domain'] = 'example.org'
+    id = dev[0].add_cred_values(vals2)
+
+    dev[0].request("INTERWORKING_SELECT freq=2412")
+    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
+    if ev is None:
+        raise Exception("No AP found")
+    if "conn_capab_missing=1" not in ev:
+        raise Exception("conn_capab_missing not reported")
+    dev[0].remove_cred(id)
+
+    values = default_cred()
+    values['roaming_consortium'] = "fedcba"
+    id3 = dev[0].add_cred_values(values)
+
+    vals2 = vals.copy()
+    vals2['roaming_consortium'] = "fedcba"
+    vals2['priority'] = "2"
+    id = dev[0].add_cred_values(vals2)
+
+    values = default_cred()
+    values['roaming_consortium'] = "fedcba"
+    id2 = dev[0].add_cred_values(values)
+
+    dev[0].request("INTERWORKING_SELECT freq=2412")
+    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
+    if ev is None:
+        raise Exception("No AP found")
+    dev[0].remove_cred(id)
+    dev[0].remove_cred(id2)
+    dev[0].remove_cred(id3)
+
+def test_ap_hs20_3gpp_constraints(dev, apdev):
+    """Hotspot 2.0 connection and 3GPP credential constraints"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    params['anqp_3gpp_cell_net'] = "555,444"
+    params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
+    params['bss_load_test'] = "12:200:20000"
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+
+    vals = { 'imsi': "555444-333222111",
+             'eap': "SIM",
+             'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123" }
+    vals2 = vals.copy()
+    vals2['required_roaming_consortium'] = "223344"
+    id = dev[0].add_cred_values(vals2)
+    interworking_select(dev[0], bssid, "home", freq="2412", no_match=True)
+    dev[0].remove_cred(id)
+
+    vals2 = vals.copy()
+    vals2['min_dl_bandwidth_home'] = "65500"
+    id = dev[0].add_cred_values(vals2)
+    dev[0].request("INTERWORKING_SELECT freq=2412")
+    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
+    if ev is None:
+        raise Exception("No AP found")
+    if "below_min_backhaul=1" not in ev:
+        raise Exception("below_min_backhaul not reported")
+    dev[0].remove_cred(id)
+
+    vals2 = vals.copy()
+    vals2['max_bss_load'] = "100"
+    id = dev[0].add_cred_values(vals2)
+    dev[0].request("INTERWORKING_SELECT freq=2412")
+    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
+    if ev is None:
+        raise Exception("No AP found")
+    if "over_max_bss_load=1" not in ev:
+        raise Exception("over_max_bss_load not reported")
+    dev[0].remove_cred(id)
+
+    values = default_cred()
+    values['roaming_consortium'] = "fedcba"
+    id3 = dev[0].add_cred_values(values)
+
+    vals2 = vals.copy()
+    vals2['roaming_consortium'] = "fedcba"
+    vals2['priority'] = "2"
+    id = dev[0].add_cred_values(vals2)
+
+    values = default_cred()
+    values['roaming_consortium'] = "fedcba"
+    id2 = dev[0].add_cred_values(values)
+
+    dev[0].request("INTERWORKING_SELECT freq=2412")
+    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
+    if ev is None:
+        raise Exception("No AP found")
+    dev[0].remove_cred(id)
+    dev[0].remove_cred(id2)
+    dev[0].remove_cred(id3)
+
+    hapd.disable()
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    params['anqp_3gpp_cell_net'] = "555,444"
+    params['bss_load_test'] = "12:200:20000"
+    hapd = hostapd.add_ap(apdev[0], params)
+    vals2 = vals.copy()
+    vals2['req_conn_capab'] = "6:1234"
+    id = dev[0].add_cred_values(vals2)
+    dev[0].request("INTERWORKING_SELECT freq=2412")
+    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
+    if ev is None:
+        raise Exception("No AP found")
+    if "conn_capab_missing=1" not in ev:
+        raise Exception("conn_capab_missing not reported")
+    dev[0].remove_cred(id)
+
+def test_ap_hs20_connect_no_full_match(dev, apdev):
+    """Hotspot 2.0 connection and no full match"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    params['anqp_3gpp_cell_net'] = "555,444"
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+
+    vals = { 'username': "user",
+             'password': "password",
+             'domain': "example.com",
+             'ca_cert': "auth_serv/ca.pem",
+             'roaming_consortium': "fedcba",
+             'eap': "TTLS",
+             'min_dl_bandwidth_home': "65500" }
+    id = dev[0].add_cred_values(vals)
+    dev[0].request("INTERWORKING_SELECT freq=2412")
+    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
+    if ev is None:
+        raise Exception("No AP found")
+    if "below_min_backhaul=1" not in ev:
+        raise Exception("below_min_backhaul not reported")
+    interworking_connect(dev[0], bssid, "TTLS")
+    dev[0].remove_cred(id)
+    dev[0].wait_disconnected()
+
+    vals = { 'imsi': "555444-333222111", 'eap': "SIM",
+             'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
+             'min_dl_bandwidth_roaming': "65500" }
+    id = dev[0].add_cred_values(vals)
+    dev[0].request("INTERWORKING_SELECT freq=2412")
+    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
+    if ev is None:
+        raise Exception("No AP found")
+    if "below_min_backhaul=1" not in ev:
+        raise Exception("below_min_backhaul not reported")
+    interworking_connect(dev[0], bssid, "SIM")
+    dev[0].remove_cred(id)
+    dev[0].wait_disconnected()
+
 def test_ap_hs20_username_roaming(dev, apdev):
     """Hotspot 2.0 connection in username/password credential (roaming)"""
     check_eap_capa(dev[0], "MSCHAPV2")
@@ -840,7 +1231,7 @@ def test_ap_hs20_username_roaming(dev, apdev):
                             "0,another.example.com" ]
     params['domain_name'] = "another.example.com"
     params['hessid'] = bssid
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "roaming.example.com",
@@ -858,7 +1249,7 @@ def test_ap_hs20_username_unknown(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com",
@@ -876,7 +1267,7 @@ def test_ap_hs20_username_unknown2(dev, apdev):
     params = hs20_ap_params()
     params['hessid'] = bssid
     del params['domain_name']
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com",
@@ -894,7 +1285,7 @@ def test_ap_hs20_gas_while_associated(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com",
@@ -912,6 +1303,44 @@ def test_ap_hs20_gas_while_associated(dev, apdev):
         if ev is None:
             raise Exception("Operation timed out")
 
+def test_ap_hs20_gas_with_another_ap_while_associated(dev, apdev):
+    """GAS query with another AP while associated"""
+    check_eap_capa(dev[0], "MSCHAPV2")
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    hostapd.add_ap(apdev[0], params)
+
+    bssid2 = apdev[1]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid2
+    params['nai_realm'] = [ "0,no-match.example.org,13[5:6],21[2:4][5:7]" ]
+    hostapd.add_ap(apdev[1], params)
+
+    dev[0].hs20_enable()
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'ca_cert': "auth_serv/ca.pem",
+                                  'username': "hs20-test",
+                                  'password': "password",
+                                  'domain': "example.com" })
+    interworking_select(dev[0], bssid, "home", freq="2412")
+    interworking_connect(dev[0], bssid, "TTLS")
+    dev[0].dump_monitor()
+
+    logger.info("Verifying GAS query with same AP while associated")
+    dev[0].request("ANQP_GET " + bssid + " 263")
+    ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
+    if ev is None:
+        raise Exception("ANQP operation timed out")
+    dev[0].dump_monitor()
+
+    logger.info("Verifying GAS query with another AP while associated")
+    dev[0].scan_for_bss(bssid2, 2412)
+    dev[0].request("ANQP_GET " + bssid2 + " 263")
+    ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
+    if ev is None:
+        raise Exception("ANQP operation timed out")
+
 def test_ap_hs20_gas_while_associated_with_pmf(dev, apdev):
     """Hotspot 2.0 connection with GAS query while associated and using PMF"""
     check_eap_capa(dev[0], "MSCHAPV2")
@@ -924,13 +1353,13 @@ def _test_ap_hs20_gas_while_associated_with_pmf(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     bssid2 = apdev[1]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid2
     params['nai_realm'] = [ "0,no-match.example.org,13[5:6],21[2:4][5:7]" ]
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     dev[0].hs20_enable()
     dev[0].request("SET pmf 2")
@@ -949,15 +1378,59 @@ def _test_ap_hs20_gas_while_associated_with_pmf(dev, apdev):
         if ev is None:
             raise Exception("Operation timed out")
 
-def test_ap_hs20_gas_frag_while_associated(dev, apdev):
-    """Hotspot 2.0 connection with fragmented GAS query while associated"""
+def test_ap_hs20_gas_with_another_ap_while_using_pmf(dev, apdev):
+    """GAS query with another AP while associated and using PMF"""
     check_eap_capa(dev[0], "MSCHAPV2")
+    try:
+        _test_ap_hs20_gas_with_another_ap_while_using_pmf(dev, apdev)
+    finally:
+        dev[0].request("SET pmf 0")
+
+def _test_ap_hs20_gas_with_another_ap_while_using_pmf(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
-    hapd.set("gas_frag_limit", "50")
+    hostapd.add_ap(apdev[0], params)
+
+    bssid2 = apdev[1]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid2
+    params['nai_realm'] = [ "0,no-match.example.org,13[5:6],21[2:4][5:7]" ]
+    hostapd.add_ap(apdev[1], params)
+
+    dev[0].hs20_enable()
+    dev[0].request("SET pmf 2")
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'ca_cert': "auth_serv/ca.pem",
+                                  'username': "hs20-test",
+                                  'password': "password",
+                                  'domain': "example.com" })
+    interworking_select(dev[0], bssid, "home", freq="2412")
+    interworking_connect(dev[0], bssid, "TTLS")
+    dev[0].dump_monitor()
+
+    logger.info("Verifying GAS query with same AP while associated")
+    dev[0].request("ANQP_GET " + bssid + " 263")
+    ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
+    if ev is None:
+        raise Exception("ANQP operation timed out")
+    dev[0].dump_monitor()
+
+    logger.info("Verifying GAS query with another AP while associated")
+    dev[0].scan_for_bss(bssid2, 2412)
+    dev[0].request("ANQP_GET " + bssid2 + " 263")
+    ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
+    if ev is None:
+        raise Exception("ANQP operation timed out")
+
+def test_ap_hs20_gas_frag_while_associated(dev, apdev):
+    """Hotspot 2.0 connection with fragmented GAS query while associated"""
+    check_eap_capa(dev[0], "MSCHAPV2")
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    hapd = hostapd.add_ap(apdev[0], params)
+    hapd.set("gas_frag_limit", "50")
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com",
@@ -981,7 +1454,7 @@ def test_ap_hs20_multiple_connects(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     values = { 'realm': "example.com",
@@ -1021,7 +1494,7 @@ def test_ap_hs20_disallow_aps(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     values = { 'realm': "example.com",
@@ -1118,12 +1591,12 @@ def test_ap_hs20_prefer_home(dev, apdev):
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hs20_ap_params()
     params['domain_name'] = "example.org"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     params = hs20_ap_params()
     params['ssid'] = "test-hs20-other"
     params['domain_name'] = "example.com"
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     values = default_cred()
     values['domain'] = "example.com"
@@ -1135,12 +1608,12 @@ def test_ap_hs20_req_roaming_consortium(dev, apdev):
     """Hotspot 2.0 required roaming consortium"""
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hs20_ap_params()
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     params = hs20_ap_params()
     params['ssid'] = "test-hs20-other"
     params['roaming_consortium'] = [ "223344" ]
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     values = default_cred()
     values['required_roaming_consortium'] = "223344"
@@ -1156,19 +1629,40 @@ def test_ap_hs20_req_roaming_consortium(dev, apdev):
         if "FAIL" not in dev[0].request('SET_CRED {} required_roaming_consortium {}'.format(id, val)):
             raise Exception("Invalid roaming consortium value accepted: " + val)
 
+def test_ap_hs20_req_roaming_consortium_no_match(dev, apdev):
+    """Hotspot 2.0 required roaming consortium and no match"""
+    check_eap_capa(dev[0], "MSCHAPV2")
+    params = hs20_ap_params()
+    del params['roaming_consortium']
+    hostapd.add_ap(apdev[0], params)
+
+    params = hs20_ap_params()
+    params['ssid'] = "test-hs20-other"
+    params['roaming_consortium'] = [ "223345" ]
+    hostapd.add_ap(apdev[1], params)
+
+    values = default_cred()
+    values['required_roaming_consortium'] = "223344"
+    dev[0].hs20_enable()
+    id = dev[0].add_cred_values(values)
+    dev[0].request("INTERWORKING_SELECT auto freq=2412")
+    ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=10)
+    if ev is None:
+        raise Exception("INTERWORKING-NO-MATCH not reported")
+
 def test_ap_hs20_excluded_ssid(dev, apdev):
     """Hotspot 2.0 exclusion based on SSID"""
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hs20_ap_params()
     params['roaming_consortium'] = [ "223344" ]
     params['anqp_3gpp_cell_net'] = "555,444"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     params = hs20_ap_params()
     params['ssid'] = "test-hs20-other"
     params['roaming_consortium'] = [ "223344" ]
     params['anqp_3gpp_cell_net'] = "555,444"
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     values = default_cred()
     values['excluded_ssid'] = "test-hs20"
@@ -1206,7 +1700,7 @@ def test_ap_hs20_roam_to_higher_prio(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params(ssid="test-hs20-visited")
     params['domain_name'] = "visited.example.org"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com",
@@ -1223,7 +1717,7 @@ def test_ap_hs20_roam_to_higher_prio(dev, apdev):
     bssid2 = apdev[1]['bssid']
     params = hs20_ap_params(ssid="test-hs20-home")
     params['domain_name'] = "example.com"
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     dev[0].scan_for_bss(bssid2, freq="2412", force_scan=True)
     dev[0].request("INTERWORKING_SELECT auto freq=2412")
@@ -1241,10 +1735,11 @@ def test_ap_hs20_roam_to_higher_prio(dev, apdev):
 
 def test_ap_hs20_domain_suffix_match_full(dev, apdev):
     """Hotspot 2.0 and domain_suffix_match"""
+    check_domain_match_full(dev[0])
     check_eap_capa(dev[0], "MSCHAPV2")
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com",
@@ -1275,7 +1770,7 @@ def test_ap_hs20_domain_suffix_match(dev, apdev):
     check_domain_match_full(dev[0])
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com",
@@ -1293,12 +1788,12 @@ def test_ap_hs20_roaming_partner_preference(dev, apdev):
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hs20_ap_params()
     params['domain_name'] = "roaming.example.org"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     params = hs20_ap_params()
     params['ssid'] = "test-hs20-other"
     params['domain_name'] = "roaming.example.net"
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     logger.info("Verify default vs. specified preference")
     values = default_cred()
@@ -1318,12 +1813,12 @@ def test_ap_hs20_max_bss_load(dev, apdev):
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hs20_ap_params()
     params['bss_load_test'] = "12:200:20000"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     params = hs20_ap_params()
     params['ssid'] = "test-hs20-other"
     params['bss_load_test'] = "5:20:10000"
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     logger.info("Verify maximum BSS load constraint")
     values = default_cred()
@@ -1354,11 +1849,11 @@ def test_ap_hs20_max_bss_load2(dev, apdev):
     check_eap_capa(dev[0], "MSCHAPV2")
     params = hs20_ap_params()
     params['bss_load_test'] = "12:200:20000"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     params = hs20_ap_params()
     params['ssid'] = "test-hs20-other"
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     logger.info("Verify maximum BSS load constraint with AP advertisement")
     values = default_cred()
@@ -1373,6 +1868,23 @@ def test_ap_hs20_max_bss_load2(dev, apdev):
     if len(ev) != 1 or "over_max_bss_load=1" in ev[0]:
         raise Exception("Maximum BSS Load case reported incorrectly")
 
+def test_ap_hs20_max_bss_load_roaming(dev, apdev):
+    """Hotspot 2.0 and maximum BSS load (roaming)"""
+    check_eap_capa(dev[0], "MSCHAPV2")
+    params = hs20_ap_params()
+    params['bss_load_test'] = "12:200:20000"
+    hostapd.add_ap(apdev[0], params)
+
+    values = default_cred()
+    values['domain'] = "roaming.example.com"
+    values['max_bss_load'] = "100"
+    events = policy_test(dev[0], apdev[0], values, only_one=True)
+    ev = [e for e in events if "INTERWORKING-AP " + apdev[0]['bssid'] in e]
+    if len(ev) != 1:
+        raise Exception("No INTERWORKING-AP event")
+    if "over_max_bss_load=1" in ev[0]:
+        raise Exception("Maximum BSS Load reported for roaming")
+
 def test_ap_hs20_multi_cred_sp_prio(dev, apdev):
     """Hotspot 2.0 multi-cred sp_priority"""
     check_eap_capa(dev[0], "MSCHAPV2")
@@ -1388,7 +1900,7 @@ def _test_ap_hs20_multi_cred_sp_prio(dev, apdev):
     params['hessid'] = bssid
     del params['domain_name']
     params['anqp_3gpp_cell_net'] = "232,01"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].scan_for_bss(bssid, freq="2412")
@@ -1433,7 +1945,7 @@ def _test_ap_hs20_multi_cred_sp_prio2(dev, apdev):
     del params['nai_realm']
     del params['domain_name']
     params['anqp_3gpp_cell_net'] = "232,01"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     bssid2 = apdev[1]['bssid']
     params = hs20_ap_params()
@@ -1441,7 +1953,7 @@ def _test_ap_hs20_multi_cred_sp_prio2(dev, apdev):
     params['hessid'] = bssid2
     del params['domain_name']
     del params['anqp_3gpp_cell_net']
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     dev[0].hs20_enable()
     dev[0].request("SET external_sim 1")
@@ -1476,11 +1988,42 @@ def _test_ap_hs20_multi_cred_sp_prio2(dev, apdev):
     if conn_bssid != bssid2:
         raise Exception("Connected to incorrect BSS")
 
+def test_ap_hs20_multi_cred_sp_prio_same(dev, apdev):
+    """Hotspot 2.0 multi-cred and same sp_priority"""
+    check_eap_capa(dev[0], "MSCHAPV2")
+    hlr_auc_gw_available()
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    del params['domain_name']
+    params['anqp_3gpp_cell_net'] = "232,01"
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    dev[0].scan_for_bss(bssid, freq="2412")
+    id1 = dev[0].add_cred_values({ 'realm': "example.com",
+                                   'ca_cert': "auth_serv/ca.pem",
+                                   'username': "hs20-test",
+                                   'password': "password",
+                                   'domain': "domain1.example.com",
+                                   'provisioning_sp': "example.com",
+                                   'sp_priority': "1" })
+    id2 = dev[0].add_cred_values({ 'realm': "example.com",
+                                   'ca_cert': "auth_serv/ca.pem",
+                                   'username': "hs20-test",
+                                   'password': "password",
+                                   'domain': "domain2.example.com",
+                                   'provisioning_sp': "example.com",
+                                   'sp_priority': "1" })
+    dev[0].dump_monitor()
+    dev[0].scan_for_bss(bssid, freq="2412")
+    check_auto_select(dev[0], bssid)
+
 def check_conn_capab_selection(dev, type, missing):
     dev.request("INTERWORKING_SELECT freq=2412")
     ev = dev.wait_event(["INTERWORKING-AP"])
     if ev is None:
-        raise Exception("Network selection timed out");
+        raise Exception("Network selection timed out")
     if "type=" + type not in ev:
         raise Exception("Unexpected network type")
     if missing and "conn_capab_missing=1" not in ev:
@@ -1499,7 +2042,7 @@ def test_ap_hs20_req_conn_capab(dev, apdev):
     check_eap_capa(dev[0], "MSCHAPV2")
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].scan_for_bss(bssid, freq="2412")
@@ -1532,7 +2075,7 @@ def test_ap_hs20_req_conn_capab(dev, apdev):
     bssid2 = apdev[1]['bssid']
     params = hs20_ap_params(ssid="test-hs20b")
     params['hs20_conn_capab'] = [ "1:0:2", "6:22:1", "17:5060:0", "50:0:1" ]
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     dev[0].remove_cred(id)
     values = conn_capab_cred(domain="example.org", req_conn_capab="50")
@@ -1543,12 +2086,26 @@ def test_ap_hs20_req_conn_capab(dev, apdev):
     for i in range(0, 2):
         ev = dev[0].wait_event(["INTERWORKING-AP"])
         if ev is None:
-            raise Exception("Network selection timed out");
+            raise Exception("Network selection timed out")
         if bssid in ev and "conn_capab_missing=1" not in ev:
             raise Exception("Missing protocol connection capability not reported")
         if bssid2 in ev and "conn_capab_missing=1" in ev:
             raise Exception("Protocol connection capability not reported correctly")
 
+def test_ap_hs20_req_conn_capab2(dev, apdev):
+    """Hotspot 2.0 network selection with req_conn_capab (not present)"""
+    check_eap_capa(dev[0], "MSCHAPV2")
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    del params['hs20_conn_capab']
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    dev[0].scan_for_bss(bssid, freq="2412")
+    values = conn_capab_cred(domain="example.org", req_conn_capab="6:1234")
+    id = dev[0].add_cred_values(values)
+    check_conn_capab_selection(dev[0], "roaming", False)
+
 def test_ap_hs20_req_conn_capab_and_roaming_partner_preference(dev, apdev):
     """Hotspot 2.0 and req_conn_capab with roaming partner preference"""
     check_eap_capa(dev[0], "MSCHAPV2")
@@ -1556,12 +2113,12 @@ def test_ap_hs20_req_conn_capab_and_roaming_partner_preference(dev, apdev):
     params = hs20_ap_params()
     params['domain_name'] = "roaming.example.org"
     params['hs20_conn_capab'] = [ "1:0:2", "6:22:1", "17:5060:0", "50:0:1" ]
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     bssid2 = apdev[1]['bssid']
     params = hs20_ap_params(ssid="test-hs20-b")
     params['domain_name'] = "roaming.example.net"
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     values = default_cred()
     values['roaming_partner'] = "roaming.example.net,1,127,*"
@@ -1580,7 +2137,7 @@ def check_bandwidth_selection(dev, type, below):
     dev.request("INTERWORKING_SELECT freq=2412")
     ev = dev.wait_event(["INTERWORKING-AP"])
     if ev is None:
-        raise Exception("Network selection timed out");
+        raise Exception("Network selection timed out")
     logger.debug("BSS entries:\n" + dev.request("BSS RANGE=ALL"))
     if "type=" + type not in ev:
         raise Exception("Unexpected network type")
@@ -1606,7 +2163,7 @@ def test_ap_hs20_min_bandwidth_home(dev, apdev):
     check_eap_capa(dev[0], "MSCHAPV2")
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].scan_for_bss(bssid, freq="2412")
@@ -1633,25 +2190,52 @@ def test_ap_hs20_min_bandwidth_home(dev, apdev):
     bssid2 = apdev[1]['bssid']
     params = hs20_ap_params(ssid="test-hs20-b")
     params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     check_auto_select(dev[0], bssid2)
 
+def test_ap_hs20_min_bandwidth_home2(dev, apdev):
+    """Hotspot 2.0 network selection with min bandwidth - special cases"""
+    check_eap_capa(dev[0], "MSCHAPV2")
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    dev[0].scan_for_bss(bssid, freq="2412")
+    values = bw_cred(domain="example.com", dl_home=5490, ul_home=58)
+    id = dev[0].add_cred_values(values)
+    check_bandwidth_selection(dev[0], "home", False)
+
+    logger.info("WAN link at capacity")
+    hapd.set('hs20_wan_metrics', "09:8000:1000:80:240:3000")
+    check_bandwidth_selection(dev[0], "home", True)
+
+    logger.info("Downlink/Uplink Load was not measured")
+    hapd.set('hs20_wan_metrics', "01:8000:1000:80:240:0")
+    check_bandwidth_selection(dev[0], "home", False)
+
+    logger.info("Uplink and Downlink max values")
+    hapd.set('hs20_wan_metrics', "01:4294967295:4294967295:80:240:3000")
+    check_bandwidth_selection(dev[0], "home", False)
+
+    dev[0].remove_cred(id)
+
 def test_ap_hs20_min_bandwidth_home_hidden_ssid_in_scan_res(dev, apdev):
     """Hotspot 2.0 network selection with min bandwidth (home) while hidden SSID is included in scan results"""
     check_eap_capa(dev[0], "MSCHAPV2")
     bssid = apdev[0]['bssid']
 
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": 'secret',
-                                                "ignore_broadcast_ssid": "1" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": 'secret',
+                                      "ignore_broadcast_ssid": "1" })
     dev[0].scan_for_bss(bssid, freq=2412)
     hapd.disable()
-    hapd_global = hostapd.HostapdGlobal()
+    hapd_global = hostapd.HostapdGlobal(apdev[0])
     hapd_global.flush()
     hapd_global.remove(apdev[0]['ifname'])
 
     params = hs20_ap_params()
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].scan_for_bss(bssid, freq="2412")
@@ -1678,7 +2262,7 @@ def test_ap_hs20_min_bandwidth_home_hidden_ssid_in_scan_res(dev, apdev):
     bssid2 = apdev[1]['bssid']
     params = hs20_ap_params(ssid="test-hs20-b")
     params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     check_auto_select(dev[0], bssid2)
 
@@ -1689,7 +2273,7 @@ def test_ap_hs20_min_bandwidth_roaming(dev, apdev):
     check_eap_capa(dev[0], "MSCHAPV2")
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].scan_for_bss(bssid, freq="2412")
@@ -1716,7 +2300,7 @@ def test_ap_hs20_min_bandwidth_roaming(dev, apdev):
     bssid2 = apdev[1]['bssid']
     params = hs20_ap_params(ssid="test-hs20-b")
     params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     check_auto_select(dev[0], bssid2)
 
@@ -1727,12 +2311,12 @@ def test_ap_hs20_min_bandwidth_and_roaming_partner_preference(dev, apdev):
     params = hs20_ap_params()
     params['domain_name'] = "roaming.example.org"
     params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     bssid2 = apdev[1]['bssid']
     params = hs20_ap_params(ssid="test-hs20-b")
     params['domain_name'] = "roaming.example.net"
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     values = default_cred()
     values['roaming_partner'] = "roaming.example.net,1,127,*"
@@ -1750,7 +2334,7 @@ def test_ap_hs20_min_bandwidth_no_wan_metrics(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     del params['hs20_wan_metrics']
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].scan_for_bss(bssid, freq="2412")
@@ -1834,7 +2418,7 @@ def _test_ap_hs20_deauth_req_from_radius(dev, apdev):
     params = hs20_ap_params()
     params['nai_realm'] = [ "0,example.com,21[2:4]" ]
     params['hs20_deauth_req_timeout'] = "2"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].request("SET pmf 2")
     dev[0].hs20_enable()
@@ -1850,6 +2434,19 @@ def _test_ap_hs20_deauth_req_from_radius(dev, apdev):
         raise Exception("Unexpected deauth imminent contents")
     dev[0].wait_disconnected(timeout=3)
 
+def test_ap_hs20_deauth_req_without_pmf(dev, apdev):
+    """Hotspot 2.0 connection and deauthentication request without PMF"""
+    check_eap_capa(dev[0], "MSCHAPV2")
+    dev[0].request("SET pmf 0")
+    eap_test(dev[0], apdev[0], "21[3:26]", "TTLS", "user")
+    dev[0].dump_monitor()
+    addr = dev[0].own_addr()
+    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd.request("HS20_DEAUTH_REQ " + addr + " 1 120 http://example.com/")
+    ev = dev[0].wait_event(["HS20-DEAUTH-IMMINENT-NOTICE"], timeout=0.2)
+    if ev is not None:
+        raise Exception("Deauth imminent notice without PMF accepted")
+
 def test_ap_hs20_remediation_required(dev, apdev):
     """Hotspot 2.0 connection and remediation required from RADIUS"""
     check_eap_capa(dev[0], "MSCHAPV2")
@@ -1862,7 +2459,7 @@ def _test_ap_hs20_remediation_required(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['nai_realm'] = [ "0,example.com,21[2:4]" ]
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].request("SET pmf 1")
     dev[0].hs20_enable()
@@ -1890,7 +2487,7 @@ def _test_ap_hs20_remediation_required_ctrl(dev, apdev):
     addr = dev[0].own_addr()
     params = hs20_ap_params()
     params['nai_realm'] = [ "0,example.com,21[2:4]" ]
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].request("SET pmf 1")
     dev[0].hs20_enable()
@@ -1931,7 +2528,7 @@ def _test_ap_hs20_session_info(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['nai_realm'] = [ "0,example.com,21[2:4]" ]
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].request("SET pmf 1")
     dev[0].hs20_enable()
@@ -1959,7 +2556,7 @@ def test_ap_hs20_osen(dev, apdev):
                'auth_server_addr': "127.0.0.1",
                'auth_server_port': "1812",
                'auth_server_shared_secret': "radius" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[1].connect("osen", key_mgmt="NONE", scan_freq="2412",
                    wait_connect=False)
@@ -1994,7 +2591,7 @@ def test_ap_hs20_network_preference(dev, apdev):
     check_eap_capa(dev[0], "MSCHAPV2")
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     values = { 'realm': "example.com",
@@ -2017,7 +2614,7 @@ def test_ap_hs20_network_preference(dev, apdev):
 
     bssid2 = apdev[1]['bssid']
     params = hostapd.wpa2_params(ssid="home", passphrase="12345678")
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     dev[0].scan_for_bss(bssid2, freq="2412")
     dev[0].request("INTERWORKING_SELECT auto freq=2412")
@@ -2035,7 +2632,7 @@ def test_ap_hs20_network_preference2(dev, apdev):
     check_eap_capa(dev[0], "MSCHAPV2")
     bssid2 = apdev[1]['bssid']
     params = hostapd.wpa2_params(ssid="home", passphrase="12345678")
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     dev[0].hs20_enable()
     values = { 'realm': "example.com",
@@ -2058,7 +2655,7 @@ def test_ap_hs20_network_preference2(dev, apdev):
 
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].scan_for_bss(bssid, freq="2412")
     dev[0].request("INTERWORKING_SELECT auto freq=2412")
@@ -2076,12 +2673,12 @@ def test_ap_hs20_network_preference3(dev, apdev):
     check_eap_capa(dev[0], "MSCHAPV2")
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     bssid2 = apdev[1]['bssid']
     params = hs20_ap_params(ssid="test-hs20b")
     params['nai_realm'] = "0,example.org,13[5:6],21[2:4][5:7]"
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     dev[0].hs20_enable()
     values = { 'realm': "example.com",
@@ -2117,14 +2714,14 @@ def test_ap_hs20_network_preference4(dev, apdev):
     check_eap_capa(dev[0], "MSCHAPV2")
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     bssid2 = apdev[1]['bssid']
     params = hs20_ap_params(ssid="test-hs20b")
     params['hessid'] = bssid2
     params['anqp_3gpp_cell_net'] = "555,444"
     params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     dev[0].hs20_enable()
     values = { 'realm': "example.com",
@@ -2160,7 +2757,7 @@ def test_ap_hs20_interworking_select_blocking_scan(dev, apdev):
     check_eap_capa(dev[0], "MSCHAPV2")
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     values = { 'realm': "example.com",
@@ -2186,7 +2783,7 @@ def test_ap_hs20_fetch_osu(dev, apdev):
     params['osu_icon'] = "w1fi_logo"
     params['osu_service_desc'] = [ "eng:Example services", "fin:Esimerkkipalveluja" ]
     params['osu_server_uri'] = "https://example.com/osu/"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     bssid2 = apdev[1]['bssid']
     params = hs20_ap_params(ssid="test-hs20b")
@@ -2199,7 +2796,7 @@ def test_ap_hs20_fetch_osu(dev, apdev):
     params['osu_icon'] = "w1fi_logo"
     params['osu_service_desc'] = [ "eng:Example services2", "fin:Esimerkkipalveluja2" ]
     params['osu_server_uri'] = "https://example.org/osu/"
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     with open("w1fi_logo.png", "r") as f:
         orig_logo = f.read()
@@ -2216,12 +2813,15 @@ def test_ap_hs20_fetch_osu(dev, apdev):
             pass
     try:
         dev[1].scan_for_bss(bssid, freq="2412")
+        dev[2].scan_for_bss(bssid, freq="2412")
         dev[0].request("SET osu_dir " + dir)
         dev[0].request("FETCH_OSU")
         if "FAIL" not in dev[1].request("HS20_ICON_REQUEST foo w1fi_logo"):
             raise Exception("Invalid HS20_ICON_REQUEST accepted")
         if "OK" not in dev[1].request("HS20_ICON_REQUEST " + bssid + " w1fi_logo"):
             raise Exception("HS20_ICON_REQUEST failed")
+        if "OK" not in dev[2].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
+            raise Exception("REQ_HS20_ICON failed")
         icons = 0
         while True:
             ev = dev[0].wait_event(["OSU provider fetch completed",
@@ -2266,6 +2866,304 @@ def test_ap_hs20_fetch_osu(dev, apdev):
     if "Icon Binary File" not in ev:
         raise Exception("Unexpected ANQP element")
 
+    ev = dev[2].wait_event(["RX-HS20-ICON"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on RX-HS20-ICON")
+    event_icon_len = ev.split(' ')[3]
+    if " w1fi_logo " not in ev:
+        raise Exception("RX-HS20-ICON did not have the expected file name")
+    if bssid not in ev:
+        raise Exception("RX-HS20-ICON did not have the expected BSSID")
+    if "FAIL" in dev[2].request("GET_HS20_ICON " + bssid + " w1fi_logo 0 10"):
+        raise Exception("GET_HS20_ICON 0..10 failed")
+    if "FAIL" in dev[2].request("GET_HS20_ICON " + bssid + " w1fi_logo 5 10"):
+        raise Exception("GET_HS20_ICON 5..15 failed")
+    if "FAIL" not in  dev[2].request("GET_HS20_ICON " + bssid + " w1fi_logo 100000 10"):
+        raise Exception("Unexpected success of GET_HS20_ICON with too large offset")
+    if "FAIL" not in dev[2].request("GET_HS20_ICON " + bssid + " no_such_logo 0 10"):
+        raise Exception("GET_HS20_ICON for not existing icon succeeded")
+    if "FAIL" not in dev[2].request("GET_HS20_ICON " + bssid + " w1fi_logo 0 3070"):
+        raise Exception("GET_HS20_ICON with too many output bytes to fit the buffer succeeded")
+    if "FAIL" not in dev[2].request("GET_HS20_ICON " + bssid + " w1fi_logo 0 0"):
+        raise Exception("GET_HS20_ICON 0..0 succeeded")
+    icon = ""
+    pos = 0
+    while True:
+        if pos > 100000:
+            raise Exception("Unexpectedly long icon")
+        res = dev[2].request("GET_HS20_ICON " + bssid + " w1fi_logo %d 1000" % pos)
+        if res.startswith("FAIL"):
+            break
+        icon += base64.b64decode(res)
+        pos += 1000
+    hex = binascii.hexlify(icon)
+    if not hex.startswith("0009696d6167652f706e677d1d"):
+        raise Exception("Unexpected beacon binary header: " + hex)
+    with open('w1fi_logo.png', 'r') as f:
+        data = f.read()
+        if icon[13:] != data:
+            raise Exception("Unexpected icon data")
+    if len(icon) != int(event_icon_len):
+        raise Exception("Unexpected RX-HS20-ICON event length: " + event_icon_len)
+
+    for i in range(3):
+        if "OK" not in dev[i].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
+            raise Exception("REQ_HS20_ICON failed [2]")
+    for i in range(3):
+        ev = dev[i].wait_event(["RX-HS20-ICON"], timeout=5)
+        if ev is None:
+            raise Exception("Timeout on RX-HS20-ICON [2]")
+
+    if "FAIL" not in dev[2].request("DEL_HS20_ICON foo w1fi_logo"):
+        raise Exception("Invalid DEL_HS20_ICON accepted")
+    if "OK" not in dev[2].request("DEL_HS20_ICON " + bssid + " w1fi_logo"):
+        raise Exception("DEL_HS20_ICON failed")
+    if "OK" not in dev[1].request("DEL_HS20_ICON " + bssid):
+        raise Exception("DEL_HS20_ICON failed")
+    if "OK" not in dev[0].request("DEL_HS20_ICON "):
+        raise Exception("DEL_HS20_ICON failed")
+    for i in range(3):
+        if "FAIL" not in dev[i].request("DEL_HS20_ICON "):
+            raise Exception("DEL_HS20_ICON accepted when no icons left")
+
+def test_ap_hs20_fetch_osu_no_info(dev, apdev):
+    """Hotspot 2.0 OSU provider and no AP with info"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    dir = "/tmp/osu-fetch"
+    if os.path.isdir(dir):
+       files = [ f for f in os.listdir(dir) if f.startswith("osu-") ]
+       for f in files:
+           os.remove(dir + "/" + f)
+    else:
+        try:
+            os.makedirs(dir)
+        except:
+            pass
+    dev[0].scan_for_bss(bssid, freq="2412")
+    try:
+        dev[0].request("SET osu_dir " + dir)
+        dev[0].request("FETCH_OSU")
+        ev = dev[0].wait_event(["OSU provider fetch completed"], timeout=30)
+        if ev is None:
+            raise Exception("Timeout on OSU fetch")
+    finally:
+        files = [ f for f in os.listdir(dir) if f.startswith("osu-") ]
+        for f in files:
+            os.remove(dir + "/" + f)
+        os.rmdir(dir)
+
+def test_ap_hs20_fetch_osu_no_icon(dev, apdev):
+    """Hotspot 2.0 OSU provider and no icon found"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hs20_icon'] = "128:80:zxx:image/png:w1fi_logo:w1fi_logo-no-file.png"
+    params['osu_ssid'] = '"HS 2.0 OSU open"'
+    params['osu_method_list'] = "1"
+    params['osu_friendly_name'] = [ "eng:Test OSU", "fin:Testi-OSU" ]
+    params['osu_icon'] = "w1fi_logo"
+    params['osu_service_desc'] = [ "eng:Example services", "fin:Esimerkkipalveluja" ]
+    params['osu_server_uri'] = "https://example.com/osu/"
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    dir = "/tmp/osu-fetch"
+    if os.path.isdir(dir):
+       files = [ f for f in os.listdir(dir) if f.startswith("osu-") ]
+       for f in files:
+           os.remove(dir + "/" + f)
+    else:
+        try:
+            os.makedirs(dir)
+        except:
+            pass
+    dev[0].scan_for_bss(bssid, freq="2412")
+    try:
+        dev[0].request("SET osu_dir " + dir)
+        dev[0].request("FETCH_OSU")
+        ev = dev[0].wait_event(["OSU provider fetch completed"], timeout=30)
+        if ev is None:
+            raise Exception("Timeout on OSU fetch")
+    finally:
+        files = [ f for f in os.listdir(dir) if f.startswith("osu-") ]
+        for f in files:
+            os.remove(dir + "/" + f)
+        os.rmdir(dir)
+
+def get_icon(dev, bssid, iconname):
+    icon = ""
+    pos = 0
+    while True:
+        if pos > 100000:
+            raise Exception("Unexpectedly long icon")
+        res = dev.request("GET_HS20_ICON " + bssid + " " + iconname + " %d 3000" % pos)
+        if res.startswith("FAIL"):
+            break
+        icon += base64.b64decode(res)
+        pos += 3000
+    if len(icon) < 13:
+        raise Exception("Too short GET_HS20_ICON response")
+    return icon[0:13], icon[13:]
+
+def test_ap_hs20_req_hs20_icon(dev, apdev):
+    """Hotspot 2.0 OSU provider and multi-icon fetch with REQ_HS20_ICON"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hs20_icon'] = [ "128:80:zxx:image/png:w1fi_logo:w1fi_logo.png",
+                            "128:80:zxx:image/png:test_logo:auth_serv/sha512-server.pem" ]
+    params['osu_ssid'] = '"HS 2.0 OSU open"'
+    params['osu_method_list'] = "1"
+    params['osu_friendly_name'] = [ "eng:Test OSU", "fin:Testi-OSU" ]
+    params['osu_icon'] = [ "w1fi_logo", "w1fi_logo2" ]
+    params['osu_service_desc'] = [ "eng:Example services", "fin:Esimerkkipalveluja" ]
+    params['osu_server_uri'] = "https://example.com/osu/"
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].scan_for_bss(bssid, freq="2412")
+
+    # First, fetch two icons from the AP to wpa_supplicant
+
+    if "OK" not in dev[0].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
+        raise Exception("REQ_HS20_ICON failed")
+    ev = dev[0].wait_event(["RX-HS20-ICON"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on RX-HS20-ICON (1)")
+
+    if "OK" not in dev[0].request("REQ_HS20_ICON " + bssid + " test_logo"):
+        raise Exception("REQ_HS20_ICON failed")
+    ev = dev[0].wait_event(["RX-HS20-ICON"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on RX-HS20-ICON (2)")
+
+    # Then, fetch the icons from wpa_supplicant for validation
+
+    hdr, data1 = get_icon(dev[0], bssid, "w1fi_logo")
+    hdr, data2 = get_icon(dev[0], bssid, "test_logo")
+
+    with open('w1fi_logo.png', 'r') as f:
+        data = f.read()
+        if data1 != data:
+            raise Exception("Unexpected icon data (1)")
+
+    with open('auth_serv/sha512-server.pem', 'r') as f:
+        data = f.read()
+        if data2 != data:
+            raise Exception("Unexpected icon data (2)")
+
+    # Finally, delete the icons from wpa_supplicant
+
+    if "OK" not in dev[0].request("DEL_HS20_ICON " + bssid + " w1fi_logo"):
+        raise Exception("DEL_HS20_ICON failed")
+    if "OK" not in dev[0].request("DEL_HS20_ICON " + bssid + " test_logo"):
+        raise Exception("DEL_HS20_ICON failed")
+
+def test_ap_hs20_req_hs20_icon_oom(dev, apdev):
+    """Hotspot 2.0 icon fetch OOM with REQ_HS20_ICON"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hs20_icon'] = [ "128:80:zxx:image/png:w1fi_logo:w1fi_logo.png",
+                            "128:80:zxx:image/png:test_logo:auth_serv/sha512-server.pem" ]
+    params['osu_ssid'] = '"HS 2.0 OSU open"'
+    params['osu_method_list'] = "1"
+    params['osu_friendly_name'] = [ "eng:Test OSU", "fin:Testi-OSU" ]
+    params['osu_icon'] = [ "w1fi_logo", "w1fi_logo2" ]
+    params['osu_service_desc'] = [ "eng:Example services", "fin:Esimerkkipalveluja" ]
+    params['osu_server_uri'] = "https://example.com/osu/"
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].scan_for_bss(bssid, freq="2412")
+
+    if "FAIL" not in dev[0].request("REQ_HS20_ICON 11:22:33:44:55:66 w1fi_logo"):
+        raise Exception("REQ_HS20_ICON succeeded with unknown BSSID")
+
+    with alloc_fail(dev[0], 1, "hs20_build_anqp_req;hs20_anqp_send_req"):
+        if "FAIL" not in dev[0].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
+            raise Exception("REQ_HS20_ICON succeeded during OOM")
+
+    with alloc_fail(dev[0], 1, "gas_query_req;hs20_anqp_send_req"):
+        if "FAIL" not in dev[0].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
+            raise Exception("REQ_HS20_ICON succeeded during OOM")
+
+    with alloc_fail(dev[0], 1, "=hs20_anqp_send_req"):
+        if "FAIL" not in dev[0].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
+            raise Exception("REQ_HS20_ICON succeeded during OOM")
+    with alloc_fail(dev[0], 2, "=hs20_anqp_send_req"):
+        if "FAIL" not in dev[0].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
+            raise Exception("REQ_HS20_ICON succeeded during OOM")
+
+    if "OK" not in dev[0].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
+        raise Exception("REQ_HS20_ICON failed")
+    ev = dev[0].wait_event(["RX-HS20-ICON"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on RX-HS20-ICON (1)")
+
+    with alloc_fail(dev[0], 1, "hs20_get_icon"):
+        if "FAIL" not in dev[0].request("GET_HS20_ICON " + bssid + "w1fi_logo 0 100"):
+            raise Exception("GET_HS20_ICON succeeded during OOM")
+
+    if "OK" not in dev[0].request("DEL_HS20_ICON " + bssid + " w1fi_logo"):
+        raise Exception("DEL_HS20_ICON failed")
+
+    with alloc_fail(dev[0], 1, "=hs20_process_icon_binary_file"):
+        if "OK" not in dev[0].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
+            raise Exception("REQ_HS20_ICON failed")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+def test_ap_hs20_req_hs20_icon_parallel(dev, apdev):
+    """Hotspot 2.0 OSU provider and multi-icon parallel fetch with REQ_HS20_ICON"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hs20_icon'] = [ "128:80:zxx:image/png:w1fi_logo:w1fi_logo.png",
+                            "128:80:zxx:image/png:test_logo:auth_serv/sha512-server.pem" ]
+    params['osu_ssid'] = '"HS 2.0 OSU open"'
+    params['osu_method_list'] = "1"
+    params['osu_friendly_name'] = [ "eng:Test OSU", "fin:Testi-OSU" ]
+    params['osu_icon'] = [ "w1fi_logo", "w1fi_logo2" ]
+    params['osu_service_desc'] = [ "eng:Example services", "fin:Esimerkkipalveluja" ]
+    params['osu_server_uri'] = "https://example.com/osu/"
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].scan_for_bss(bssid, freq="2412")
+
+    # First, fetch two icons from the AP to wpa_supplicant
+
+    if "OK" not in dev[0].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
+        raise Exception("REQ_HS20_ICON failed")
+
+    if "OK" not in dev[0].request("REQ_HS20_ICON " + bssid + " test_logo"):
+        raise Exception("REQ_HS20_ICON failed")
+    ev = dev[0].wait_event(["RX-HS20-ICON"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on RX-HS20-ICON (1)")
+    ev = dev[0].wait_event(["RX-HS20-ICON"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on RX-HS20-ICON (2)")
+
+    # Then, fetch the icons from wpa_supplicant for validation
+
+    hdr, data1 = get_icon(dev[0], bssid, "w1fi_logo")
+    hdr, data2 = get_icon(dev[0], bssid, "test_logo")
+
+    with open('w1fi_logo.png', 'r') as f:
+        data = f.read()
+        if data1 != data:
+            raise Exception("Unexpected icon data (1)")
+
+    with open('auth_serv/sha512-server.pem', 'r') as f:
+        data = f.read()
+        if data2 != data:
+            raise Exception("Unexpected icon data (2)")
+
+    # Finally, delete the icons from wpa_supplicant
+
+    if "OK" not in dev[0].request("DEL_HS20_ICON " + bssid + " w1fi_logo"):
+        raise Exception("DEL_HS20_ICON failed")
+    if "OK" not in dev[0].request("DEL_HS20_ICON " + bssid + " test_logo"):
+        raise Exception("DEL_HS20_ICON failed")
+
 def test_ap_hs20_fetch_osu_stop(dev, apdev):
     """Hotspot 2.0 OSU provider fetch stopped"""
     bssid = apdev[0]['bssid']
@@ -2277,7 +3175,7 @@ def test_ap_hs20_fetch_osu_stop(dev, apdev):
     params['osu_icon'] = "w1fi_logo"
     params['osu_service_desc'] = [ "eng:Example services", "fin:Esimerkkipalveluja" ]
     params['osu_server_uri'] = "https://example.com/osu/"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dir = "/tmp/osu-fetch"
@@ -2319,7 +3217,7 @@ def test_ap_hs20_fetch_osu_stop(dev, apdev):
         ev = dev[0].wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH"],
                                timeout=15)
         if ev is None:
-            raise Exception("Network selection timed out");
+            raise Exception("Network selection timed out")
 
         dev[0].dump_monitor()
         if "OK" not in dev[0].request("FETCH_OSU"):
@@ -2351,26 +3249,245 @@ def test_ap_hs20_fetch_osu_stop(dev, apdev):
             os.remove(dir + "/" + f)
         os.rmdir(dir)
 
-def test_ap_hs20_ft(dev, apdev):
-    """Hotspot 2.0 connection with FT"""
-    check_eap_capa(dev[0], "MSCHAPV2")
+def test_ap_hs20_fetch_osu_proto(dev, apdev):
+    """Hotspot 2.0 OSU provider and protocol testing"""
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
-    params['wpa_key_mgmt'] = "FT-EAP"
-    params['nas_identifier'] = "nas1.w1.fi"
-    params['r1_key_holder'] = "000102030405"
-    params["mobility_domain"] = "a1b2"
-    params["reassociation_deadline"] = "1000"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
-    id = dev[0].add_cred_values({ 'realm': "example.com",
-                                  'username': "hs20-test",
-                                  'password': "password",
-                                  'ca_cert': "auth_serv/ca.pem",
-                                  'domain': "example.com",
-                                  'update_identifier': "1234" })
-    interworking_select(dev[0], bssid, "home", freq="2412")
+    dir = "/tmp/osu-fetch"
+    if os.path.isdir(dir):
+       files = [ f for f in os.listdir(dir) if f.startswith("osu-") ]
+       for f in files:
+           os.remove(dir + "/" + f)
+    else:
+        try:
+            os.makedirs(dir)
+        except:
+            pass
+
+    tests = [ ( "Empty provider list (no OSU SSID field)", '' ),
+              ( "HS 2.0: Not enough room for OSU SSID",
+                binascii.unhexlify('01') ),
+              ( "HS 2.0: Invalid OSU SSID Length 33",
+                binascii.unhexlify('21') + 33*'A' ),
+              ( "HS 2.0: Not enough room for Number of OSU Providers",
+                binascii.unhexlify('0130') ),
+              ( "Truncated OSU Provider",
+                binascii.unhexlify('013001020000') ),
+              ( "HS 2.0: Ignored 5 bytes of extra data after OSU Providers",
+                binascii.unhexlify('0130001122334455') ),
+              ( "HS 2.0: Not enough room for OSU Friendly Name Length",
+                binascii.unhexlify('013001000000') ),
+              ( "HS 2.0: Not enough room for OSU Friendly Name Duples",
+                build_prov('0100') ),
+              ( "Invalid OSU Friendly Name", build_prov('040000000000') ),
+              ( "Invalid OSU Friendly Name(2)", build_prov('040004000000') ),
+              ( "HS 2.0: Not enough room for OSU Server URI length",
+                build_prov('0000') ),
+              ( "HS 2.0: Not enough room for OSU Server URI",
+                build_prov('000001') ),
+              ( "HS 2.0: Not enough room for OSU Method list length",
+                build_prov('000000') ),
+              ( "HS 2.0: Not enough room for OSU Method list",
+                build_prov('00000001') ),
+              ( "HS 2.0: Not enough room for Icons Available Length",
+                build_prov('00000000') ),
+              ( "HS 2.0: Not enough room for Icons Available Length(2)",
+                build_prov('00000001ff00') ),
+              ( "HS 2.0: Not enough room for Icons Available",
+                build_prov('000000000100') ),
+              ( "HS 2.0: Invalid Icon Metadata",
+                build_prov('00000000010000') ),
+              ( "HS 2.0: Not room for Icon Type",
+                build_prov('000000000900111122223333330200') ),
+              ( "HS 2.0: Not room for Icon Filename length",
+                build_prov('000000000900111122223333330100') ),
+              ( "HS 2.0: Not room for Icon Filename",
+                build_prov('000000000900111122223333330001') ),
+              ( "HS 2.0: Not enough room for OSU_NAI",
+                build_prov('000000000000') ),
+              ( "HS 2.0: Not enough room for OSU_NAI(2)",
+                build_prov('00000000000001') ),
+              ( "HS 2.0: Not enough room for OSU Service Description Length",
+                build_prov('00000000000000') ),
+              ( "HS 2.0: Not enough room for OSU Service Description Length(2)",
+                build_prov('0000000000000000') ),
+              ( "HS 2.0: Not enough room for OSU Service Description Duples",
+                build_prov('000000000000000100') ),
+              ( "Invalid OSU Service Description",
+                build_prov('00000000000000040000000000') ),
+              ( "Invalid OSU Service Description(2)",
+                build_prov('00000000000000040004000000') ) ]
+
+    try:
+        dev[0].request("SET osu_dir " + dir)
+        run_fetch_osu_icon_failure(hapd, dev, bssid)
+        for note, prov in tests:
+            run_fetch_osu(hapd, dev, bssid, note, prov)
+    finally:
+        files = [ f for f in os.listdir(dir) if f.startswith("osu-") ]
+        for f in files:
+            os.remove(dir + "/" + f)
+        os.rmdir(dir)
+
+def test_ap_hs20_fetch_osu_invalid_dir(dev, apdev):
+    """Hotspot 2.0 OSU provider and invalid directory"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hs20_icon'] = "128:80:zxx:image/png:w1fi_logo:w1fi_logo.png"
+    params['osu_ssid'] = '"HS 2.0 OSU open"'
+    params['osu_method_list'] = "1"
+    params['osu_friendly_name'] = [ "eng:Test OSU", "fin:Testi-OSU" ]
+    params['osu_icon'] = "w1fi_logo"
+    params['osu_service_desc'] = [ "eng:Example services", "fin:Esimerkkipalveluja" ]
+    params['osu_server_uri'] = "https://example.com/osu/"
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    dir = "/tmp/osu-fetch-no-such-dir"
+    dev[0].scan_for_bss(bssid, freq="2412")
+    dev[0].request("SET osu_dir " + dir)
+    dev[0].request("FETCH_OSU no-scan")
+    ev = dev[0].wait_event(["Could not write OSU provider information"],
+                           timeout=15)
+    if ev is None:
+        raise Exception("Timeout on OSU fetch")
+
+def test_ap_hs20_fetch_osu_oom(dev, apdev):
+    """Hotspot 2.0 OSU provider and OOM"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hs20_icon'] = "128:80:zxx:image/png:w1fi_logo:w1fi_logo.png"
+    params['osu_ssid'] = '"HS 2.0 OSU open"'
+    params['osu_method_list'] = "1"
+    params['osu_friendly_name'] = [ "eng:Test OSU", "fin:Testi-OSU" ]
+    params['osu_icon'] = "w1fi_logo"
+    params['osu_service_desc'] = [ "eng:Example services", "fin:Esimerkkipalveluja" ]
+    params['osu_server_uri'] = "https://example.com/osu/"
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    dir = "/tmp/osu-fetch"
+    if os.path.isdir(dir):
+       files = [ f for f in os.listdir(dir) if f.startswith("osu-") ]
+       for f in files:
+           os.remove(dir + "/" + f)
+    else:
+        try:
+            os.makedirs(dir)
+        except:
+            pass
+    dev[0].scan_for_bss(bssid, freq="2412")
+    try:
+        dev[0].request("SET osu_dir " + dir)
+        with alloc_fail(dev[0], 1, "=hs20_osu_add_prov"):
+            dev[0].request("FETCH_OSU no-scan")
+            ev = dev[0].wait_event(["OSU provider fetch completed"], timeout=30)
+            if ev is None:
+                raise Exception("Timeout on OSU fetch")
+        with alloc_fail(dev[0], 1, "hs20_anqp_send_req;hs20_next_osu_icon"):
+            dev[0].request("FETCH_OSU no-scan")
+            ev = dev[0].wait_event(["OSU provider fetch completed"], timeout=30)
+            if ev is None:
+                raise Exception("Timeout on OSU fetch")
+    finally:
+        files = [ f for f in os.listdir(dir) if f.startswith("osu-") ]
+        for f in files:
+            os.remove(dir + "/" + f)
+        os.rmdir(dir)
+
+def build_prov(prov):
+    data = binascii.unhexlify(prov)
+    return binascii.unhexlify('013001') + struct.pack('<H', len(data)) + data
+
+def handle_osu_prov_fetch(hapd, dev, prov):
+    # GAS/ANQP query for OSU Providers List
+    query = gas_rx(hapd)
+    gas = parse_gas(query['payload'])
+    dialog_token = gas['dialog_token']
+
+    resp = action_response(query)
+    osu_prov = struct.pack('<HH', 0xdddd, len(prov) + 6) + binascii.unhexlify('506f9a110800') + prov
+    data = struct.pack('<H', len(osu_prov)) + osu_prov
+    resp['payload'] = anqp_initial_resp(dialog_token, 0) + data
+    send_gas_resp(hapd, resp)
+
+    ev = dev[0].wait_event(["RX-HS20-ANQP"], timeout=5)
+    if ev is None:
+        raise Exception("ANQP query response for OSU Providers not received")
+    if "OSU Providers list" not in ev:
+        raise Exception("ANQP query response for OSU Providers not received(2)")
+    ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
+    if ev is None:
+        raise Exception("ANQP query for OSU Providers list not completed")
+
+def start_osu_fetch(hapd, dev, bssid, note):
+    hapd.set("ext_mgmt_frame_handling", "0")
+    dev[0].request("BSS_FLUSH 0")
+    dev[0].scan_for_bss(bssid, freq="2412")
+    hapd.set("ext_mgmt_frame_handling", "1")
+    dev[0].dump_monitor()
+    dev[0].request("NOTE " + note)
+    dev[0].request("FETCH_OSU no-scan")
+
+def wait_osu_fetch_completed(dev):
+    ev = dev[0].wait_event(["OSU provider fetch completed"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on OSU fetch")
+
+def run_fetch_osu_icon_failure(hapd, dev, bssid):
+    start_osu_fetch(hapd, dev, bssid, "Icon fetch failure")
+
+    prov = binascii.unhexlify('01ff' + '01' + '800019000b656e6754657374204f53550c66696e54657374692d4f53551868747470733a2f2f6578616d706c652e636f6d2f6f73752f01011b00800050007a787809696d6167652f706e6709773166695f6c6f676f002a0013656e674578616d706c652073657276696365731566696e4573696d65726b6b6970616c76656c756a61')
+    handle_osu_prov_fetch(hapd, dev, prov)
+
+    # GAS/ANQP query for icon
+    query = gas_rx(hapd)
+    gas = parse_gas(query['payload'])
+    dialog_token = gas['dialog_token']
+
+    resp = action_response(query)
+    # Unexpected Advertisement Protocol in response
+    adv_proto = struct.pack('8B', 108, 6, 127, 0xdd, 0x00, 0x11, 0x22, 0x33)
+    data = struct.pack('<H', 0)
+    resp['payload'] = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC,
+                                  GAS_INITIAL_RESPONSE,
+                                  gas['dialog_token'], 0, 0) + adv_proto + data
+    send_gas_resp(hapd, resp)
+
+    ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
+    if ev is None:
+        raise Exception("ANQP query for icon not completed")
+
+    wait_osu_fetch_completed(dev)
+
+def run_fetch_osu(hapd, dev, bssid, note, prov):
+    start_osu_fetch(hapd, dev, bssid, note)
+    handle_osu_prov_fetch(hapd, dev, prov)
+    wait_osu_fetch_completed(dev)
+
+def test_ap_hs20_ft(dev, apdev):
+    """Hotspot 2.0 connection with FT"""
+    check_eap_capa(dev[0], "MSCHAPV2")
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['wpa_key_mgmt'] = "FT-EAP"
+    params['nas_identifier'] = "nas1.w1.fi"
+    params['r1_key_holder'] = "000102030405"
+    params["mobility_domain"] = "a1b2"
+    params["reassociation_deadline"] = "1000"
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'username': "hs20-test",
+                                  'password': "password",
+                                  'ca_cert': "auth_serv/ca.pem",
+                                  'domain': "example.com",
+                                  'update_identifier': "1234" })
+    interworking_select(dev[0], bssid, "home", freq="2412")
     interworking_connect(dev[0], bssid, "TTLS")
 
 def test_ap_hs20_remediation_sql(dev, apdev, params):
@@ -2405,12 +3522,12 @@ def test_ap_hs20_remediation_sql(dev, apdev, params):
                    "private_key": "auth_serv/server.key",
                    "subscr_remediation_url": "https://example.org/",
                    "subscr_remediation_method": "1" }
-        hostapd.add_ap(apdev[1]['ifname'], params)
+        hostapd.add_ap(apdev[1], params)
 
         bssid = apdev[0]['bssid']
         params = hs20_ap_params()
         params['auth_server_port'] = "18128"
-        hostapd.add_ap(apdev[0]['ifname'], params)
+        hostapd.add_ap(apdev[0], params)
 
         dev[0].request("SET pmf 1")
         dev[0].hs20_enable()
@@ -2444,7 +3561,7 @@ def test_ap_hs20_external_selection(dev, apdev):
     params = hs20_ap_params()
     params['hessid'] = bssid
     params['disable_dgaf'] = '1'
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].connect("test-hs20", proto="RSN", key_mgmt="WPA-EAP", eap="TTLS",
@@ -2461,7 +3578,7 @@ def test_ap_hs20_random_mac_addr(dev, apdev):
     params = hs20_ap_params()
     params['hessid'] = bssid
     params['disable_dgaf'] = '1'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5")
@@ -2496,7 +3613,7 @@ def test_ap_hs20_multi_network_and_cred_removal(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['nai_realm'] = [ "0,example.com,25[3:26]"]
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].add_network()
     dev[0].hs20_enable()
@@ -2532,7 +3649,7 @@ def test_ap_hs20_interworking_add_network(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['nai_realm'] = [ "0,example.com,21[3:26][6:7][99:99]" ]
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].add_cred_values(default_cred(user="user"))
@@ -2547,7 +3664,7 @@ def _test_ap_hs20_proxyarp(dev, apdev):
     params['hessid'] = bssid
     params['disable_dgaf'] = '0'
     params['proxy_arp'] = '1'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, no_enable=True)
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
     if "OK" in hapd.request("ENABLE"):
         raise Exception("Incomplete hostapd configuration was accepted")
     hapd.set("ap_isolate", "1")
@@ -2632,17 +3749,17 @@ def test_ap_hs20_hidden_ssid_in_scan_res(dev, apdev):
     check_eap_capa(dev[0], "MSCHAPV2")
     bssid = apdev[0]['bssid']
 
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": 'secret',
-                                                "ignore_broadcast_ssid": "1" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": 'secret',
+                                      "ignore_broadcast_ssid": "1" })
     dev[0].scan_for_bss(bssid, freq=2412)
     hapd.disable()
-    hapd_global = hostapd.HostapdGlobal()
+    hapd_global = hostapd.HostapdGlobal(apdev[0])
     hapd_global.flush()
     hapd_global.remove(apdev[0]['ifname'])
 
     params = hs20_ap_params()
     params['hessid'] = bssid
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     id = dev[0].add_cred_values({ 'realm': "example.com",
@@ -2680,7 +3797,7 @@ def _test_ap_hs20_proxyarp_dgaf(dev, apdev, disabled):
     params['na_mcast_to_ucast'] = '1'
     params['ap_isolate'] = '1'
     params['bridge'] = 'ap-br0'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, no_enable=True)
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
     try:
         hapd.enable()
     except:
@@ -2875,7 +3992,7 @@ def send_ns(dev, src_ll=None, target=None, ip_src=None, ip_dst=None, opt=None,
     if "OK" not in dev.request(cmd + binascii.hexlify(pkt)):
         raise Exception("DATA_TEST_FRAME failed")
 
-def build_na(src_ll, ip_src, ip_dst, target, opt=None):
+def build_na(src_ll, ip_src, ip_dst, target, opt=None, flags=0):
     link_mc = binascii.unhexlify("3333ff000002")
     _src_ll = binascii.unhexlify(src_ll.replace(':',''))
     proto = '\x86\xdd'
@@ -2883,12 +4000,11 @@ def build_na(src_ll, ip_src, ip_dst, target, opt=None):
     _ip_src = socket.inet_pton(socket.AF_INET6, ip_src)
     _ip_dst = socket.inet_pton(socket.AF_INET6, ip_dst)
 
-    reserved = '\x00\x00\x00\x00'
     _target = socket.inet_pton(socket.AF_INET6, target)
     if opt:
-        payload = reserved + _target + opt
+        payload = struct.pack('>Bxxx', flags) + _target + opt
     else:
-        payload = reserved + _target
+        payload = struct.pack('>Bxxx', flags) + _target
     icmp = build_icmpv6(_ip_src + _ip_dst, 136, 0, payload)
 
     ipv6 = struct.pack('>BBBBHBB', 0x60, 0, 0, 0, len(icmp), 58, 255)
@@ -3071,7 +4187,7 @@ def _test_proxyarp_open(dev, apdev, params, ebtables=False):
     bssid = apdev[0]['bssid']
     params = { 'ssid': 'open' }
     params['proxy_arp'] = '1'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, no_enable=True)
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
     hapd.set("ap_isolate", "1")
     hapd.set('bridge', 'ap-br0')
     hapd.dump_monitor()
@@ -3087,7 +4203,7 @@ def _test_proxyarp_open(dev, apdev, params, ebtables=False):
         raise Exception("AP startup failed")
 
     params2 = { 'ssid': 'another' }
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params2, no_enable=True)
+    hapd2 = hostapd.add_ap(apdev[1], params2, no_enable=True)
     hapd2.set('bridge', 'ap-br0')
     hapd2.enable()
 
@@ -3540,7 +4656,7 @@ def test_ap_hs20_connect_deinit(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5", drv_params="")
@@ -3568,3 +4684,706 @@ def test_ap_hs20_connect_deinit(dev, apdev):
     # Remove the interface while the gas-query radio work is still pending and
     # GAS query has not yet been started.
     wpas.interface_remove("wlan5")
+
+def test_ap_hs20_anqp_format_errors(dev, apdev):
+    """Interworking network selection and ANQP format errors"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    values = { 'realm': "example.com",
+               'ca_cert': "auth_serv/ca.pem",
+               'username': "hs20-test",
+               'password': "password",
+               'domain': "example.com" }
+    id = dev[0].add_cred_values(values)
+
+    dev[0].scan_for_bss(bssid, freq="2412")
+
+    tests = [ "00", "ffff", "010011223344", "020008000005112233445500",
+              "01000400000000", "01000000000000",
+              "01000300000200", "0100040000ff0000", "01000300000100",
+              "01000300000001",
+              "01000600000056112233",
+              "01000900000002050001000111",
+              "01000600000001000000", "01000600000001ff0000",
+              "01000600000001020001",
+              "010008000000010400010001", "0100080000000104000100ff",
+              "010011000000010d00050200020100030005000600",
+              "0000" ]
+    for t in tests:
+        hapd.set("anqp_elem", "263:" + t)
+        dev[0].request("INTERWORKING_SELECT freq=2412")
+        ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=5)
+        if ev is None:
+            raise Exception("Network selection timed out")
+        dev[0].dump_monitor()
+
+    dev[0].remove_cred(id)
+    id = dev[0].add_cred_values({ 'imsi': "555444-333222111", 'eap': "AKA",
+                                  'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"})
+
+    tests = [ "00", "0100", "0001", "00ff", "000200ff", "0003000101",
+              "00020100" ]
+    for t in tests:
+        hapd.set("anqp_elem", "264:" + t)
+        dev[0].request("INTERWORKING_SELECT freq=2412")
+        ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=5)
+        if ev is None:
+            raise Exception("Network selection timed out")
+        dev[0].dump_monitor()
+
+def test_ap_hs20_cred_with_nai_realm(dev, apdev):
+    """Hotspot 2.0 network selection and cred_with_nai_realm cred->realm"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'username': "test",
+                                  'password': "secret",
+                                  'domain': "example.com",
+                                  'eap': 'TTLS' })
+    interworking_select(dev[0], bssid, "home", freq=2412)
+    dev[0].remove_cred(id)
+
+    id = dev[0].add_cred_values({ 'realm': "foo.com",
+                                  'username': "test",
+                                  'password': "secret",
+                                  'domain': "example.com",
+                                  'roaming_consortium': "112234",
+                                  'eap': 'TTLS' })
+    interworking_select(dev[0], bssid, "home", freq=2412, no_match=True)
+    dev[0].remove_cred(id)
+
+def test_ap_hs20_cred_and_no_roaming_consortium(dev, apdev):
+    """Hotspot 2.0 network selection and no roaming consortium"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    del params['roaming_consortium']
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'username': "test",
+                                  'password': "secret",
+                                  'domain': "example.com",
+                                  'roaming_consortium': "112234",
+                                  'eap': 'TTLS' })
+    interworking_select(dev[0], bssid, "home", freq=2412, no_match=True)
+
+def test_ap_hs20_interworking_oom(dev, apdev):
+    """Hotspot 2.0 network selection and OOM"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    params['nai_realm'] = [ "0,no.match.here;example.com;no.match.here.either,21[2:1][5:7]",
+                            "0,example.com,13[5:6],21[2:4][5:7]",
+                            "0,another.example.com" ]
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'username': "test",
+                                  'password': "secret",
+                                  'domain': "example.com",
+                                  'eap': 'TTLS' })
+
+    dev[0].scan_for_bss(bssid, freq="2412")
+
+    funcs = [ "wpabuf_alloc;interworking_anqp_send_req",
+              "anqp_build_req;interworking_anqp_send_req",
+              "gas_query_req;interworking_anqp_send_req",
+              "dup_binstr;nai_realm_parse_realm",
+              "=nai_realm_parse_realm",
+              "=nai_realm_parse",
+              "=nai_realm_match" ]
+    for func in funcs:
+        with alloc_fail(dev[0], 1, func):
+            dev[0].request("INTERWORKING_SELECT auto freq=2412")
+            ev = dev[0].wait_event(["Starting ANQP"], timeout=5)
+            if ev is None:
+                raise Exception("ANQP did not start")
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+def test_ap_hs20_no_cred_connect(dev, apdev):
+    """Hotspot 2.0 and connect attempt without credential"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    dev[0].scan_for_bss(bssid, freq="2412")
+    if "FAIL" not in dev[0].request("INTERWORKING_CONNECT " + bssid):
+        raise Exception("Unexpected INTERWORKING_CONNECT success")
+
+def test_ap_hs20_no_rsn_connect(dev, apdev):
+    """Hotspot 2.0 and connect attempt without RSN"""
+    bssid = apdev[0]['bssid']
+    params = hostapd.wpa_params(ssid="test-hs20")
+    params['wpa_key_mgmt'] = "WPA-EAP"
+    params['ieee80211w'] = "1"
+    params['ieee8021x'] = "1"
+    params['auth_server_addr'] = "127.0.0.1"
+    params['auth_server_port'] = "1812"
+    params['auth_server_shared_secret'] = "radius"
+    params['interworking'] = "1"
+    params['roaming_consortium'] = [ "112233", "1020304050", "010203040506",
+                                     "fedcba" ]
+    params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]",
+                            "0,another.example.com" ]
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    dev[0].scan_for_bss(bssid, freq="2412")
+
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'username': "test",
+                                  'password': "secret",
+                                  'domain': "example.com",
+                                  'roaming_consortium': "112233",
+                                  'eap': 'TTLS' })
+
+    interworking_select(dev[0], bssid, freq=2412, no_match=True)
+    if "FAIL" not in dev[0].request("INTERWORKING_CONNECT " + bssid):
+        raise Exception("Unexpected INTERWORKING_CONNECT success")
+
+def test_ap_hs20_no_match_connect(dev, apdev):
+    """Hotspot 2.0 and connect attempt without matching cred"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    dev[0].scan_for_bss(bssid, freq="2412")
+
+    id = dev[0].add_cred_values({ 'realm': "example.org",
+                                  'username': "test",
+                                  'password': "secret",
+                                  'domain': "example.org",
+                                  'roaming_consortium': "112234",
+                                  'eap': 'TTLS' })
+
+    interworking_select(dev[0], bssid, freq=2412, no_match=True)
+    if "FAIL" not in dev[0].request("INTERWORKING_CONNECT " + bssid):
+        raise Exception("Unexpected INTERWORKING_CONNECT success")
+
+def test_ap_hs20_multiple_home_cred(dev, apdev):
+    """Hotspot 2.0 and select with multiple matching home credentials"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]" ]
+    params['domain_name'] = "example.com"
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    bssid2 = apdev[1]['bssid']
+    params = hs20_ap_params(ssid="test-hs20-other")
+    params['hessid'] = bssid2
+    params['nai_realm'] = [ "0,example.org,13[5:6],21[2:4][5:7]" ]
+    params['domain_name'] = "example.org"
+    hapd2 = hostapd.add_ap(apdev[1], params)
+
+    dev[0].hs20_enable()
+    dev[0].scan_for_bss(bssid2, freq="2412")
+    dev[0].scan_for_bss(bssid, freq="2412")
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'priority': '2',
+                                  'username': "hs20-test",
+                                  'password': "password",
+                                  'domain': "example.com" })
+    id2 = dev[0].add_cred_values({ 'realm': "example.org",
+                                   'priority': '3',
+                                   'username': "hs20-test",
+                                   'password': "password",
+                                   'domain': "example.org" })
+    dev[0].request("INTERWORKING_SELECT auto freq=2412")
+    ev = dev[0].wait_connected(timeout=15)
+    if bssid2 not in ev:
+        raise Exception("Connected to incorrect network")
+
+def test_ap_hs20_anqp_invalid_gas_response(dev, apdev):
+    """Hotspot 2.0 network selection and invalid GAS response"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].scan_for_bss(bssid, freq="2412")
+    hapd.set("ext_mgmt_frame_handling", "1")
+
+    dev[0].hs20_enable()
+
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'username': "test",
+                                  'password': "secret",
+                                  'domain': "example.com",
+                                  'roaming_consortium': "112234",
+                                  'eap': 'TTLS' })
+    dev[0].request("INTERWORKING_SELECT freq=2412")
+
+    query = gas_rx(hapd)
+    gas = parse_gas(query['payload'])
+
+    logger.info("ANQP: Unexpected Advertisement Protocol in response")
+    resp = action_response(query)
+    adv_proto = struct.pack('8B', 108, 6, 127, 0xdd, 0x00, 0x11, 0x22, 0x33)
+    data = struct.pack('<H', 0)
+    resp['payload'] = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC,
+                                  GAS_INITIAL_RESPONSE,
+                                  gas['dialog_token'], 0, 0) + adv_proto + data
+    send_gas_resp(hapd, resp)
+
+    ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
+    if ev is None:
+        raise Exception("No ANQP-QUERY-DONE seen")
+    if "result=INVALID_FRAME" not in ev:
+        raise Exception("Unexpected result: " + ev)
+
+    dev[0].request("INTERWORKING_SELECT freq=2412")
+
+    query = gas_rx(hapd)
+    gas = parse_gas(query['payload'])
+
+    logger.info("ANQP: Invalid element length for Info ID 1234")
+    resp = action_response(query)
+    adv_proto = struct.pack('BBBB', 108, 2, 127, 0)
+    elements = struct.pack('<HH', 1234, 1)
+    data = struct.pack('<H', len(elements)) + elements
+    resp['payload'] = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC,
+                                  GAS_INITIAL_RESPONSE,
+                                  gas['dialog_token'], 0, 0) + adv_proto + data
+    send_gas_resp(hapd, resp)
+
+    ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
+    if ev is None:
+        raise Exception("No ANQP-QUERY-DONE seen")
+    if "result=INVALID_FRAME" not in ev:
+        raise Exception("Unexpected result: " + ev)
+
+    with alloc_fail(dev[0], 1, "=anqp_add_extra"):
+        dev[0].request("INTERWORKING_SELECT freq=2412")
+
+        query = gas_rx(hapd)
+        gas = parse_gas(query['payload'])
+
+        resp = action_response(query)
+        elements = struct.pack('<HHHH', 1, 0, 1, 0)
+        data = struct.pack('<H', len(elements)) + elements
+        resp['payload'] = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC,
+                                      GAS_INITIAL_RESPONSE,
+                                      gas['dialog_token'], 0, 0) + adv_proto + data
+        send_gas_resp(hapd, resp)
+
+        ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
+        if ev is None:
+            raise Exception("No ANQP-QUERY-DONE seen")
+        if "result=SUCCESS" not in ev:
+            raise Exception("Unexpected result: " + ev)
+
+    with alloc_fail(dev[0], 1, "wpabuf_alloc_copy;anqp_add_extra"):
+        dev[0].request("INTERWORKING_SELECT freq=2412")
+
+        query = gas_rx(hapd)
+        gas = parse_gas(query['payload'])
+
+        resp = action_response(query)
+        elements = struct.pack('<HHHH', 1, 0, 1, 0)
+        data = struct.pack('<H', len(elements)) + elements
+        resp['payload'] = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC,
+                                      GAS_INITIAL_RESPONSE,
+                                      gas['dialog_token'], 0, 0) + adv_proto + data
+        send_gas_resp(hapd, resp)
+
+        ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
+        if ev is None:
+            raise Exception("No ANQP-QUERY-DONE seen")
+        if "result=SUCCESS" not in ev:
+            raise Exception("Unexpected result: " + ev)
+
+    tests = [ struct.pack('<HH', 0xdddd, 0),
+              struct.pack('<HH3B', 0xdddd, 3, 0x50, 0x6f, 0x9a),
+              struct.pack('<HH4B', 0xdddd, 4, 0x50, 0x6f, 0x9a, 0),
+              struct.pack('<HH4B', 0xdddd, 4, 0x11, 0x22, 0x33, 0),
+              struct.pack('<HHHH', 1, 0, 1, 0) ]
+    for elements in tests:
+        dev[0].request("INTERWORKING_SELECT freq=2412")
+
+        query = gas_rx(hapd)
+        gas = parse_gas(query['payload'])
+
+        resp = action_response(query)
+        data = struct.pack('<H', len(elements)) + elements
+        resp['payload'] = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC,
+                                      GAS_INITIAL_RESPONSE,
+                                      gas['dialog_token'], 0, 0) + adv_proto + data
+        send_gas_resp(hapd, resp)
+
+        ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
+        if ev is None:
+            raise Exception("No ANQP-QUERY-DONE seen")
+        if "result=SUCCESS" not in ev:
+            raise Exception("Unexpected result: " + ev)
+
+def test_ap_hs20_set_profile_failures(dev, apdev):
+    """Hotspot 2.0 and failures during profile configuration"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    params['anqp_3gpp_cell_net'] = "555,444"
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    dev[0].scan_for_bss(bssid, freq="2412")
+
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'domain': "example.com",
+                                  'username': "test",
+                                  'password': "secret",
+                                  'eap': 'TTLS' })
+    interworking_select(dev[0], bssid, "home", freq=2412)
+    dev[0].dump_monitor()
+    dev[0].request("NOTE ssid->eap.eap_methods = os_malloc()")
+    with alloc_fail(dev[0], 1, "interworking_set_eap_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].remove_cred(id)
+
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'domain': "example.com",
+                                  'username': "hs20-test-with-domain@example.com",
+                                  'password': "password" })
+    interworking_select(dev[0], bssid, "home", freq=2412)
+    dev[0].dump_monitor()
+    dev[0].request("NOTE anon = os_malloc()")
+    with alloc_fail(dev[0], 1, "interworking_set_eap_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].request("NOTE Successful connection with cred->username including realm")
+    dev[0].request("INTERWORKING_CONNECT " + bssid)
+    dev[0].wait_connected()
+    dev[0].remove_cred(id)
+    dev[0].wait_disconnected()
+
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'domain': "example.com",
+                                  'username': "hs20-test",
+                                  'password': "password" })
+    interworking_select(dev[0], bssid, "home", freq=2412)
+    dev[0].dump_monitor()
+    dev[0].request("NOTE anon = os_malloc() (second)")
+    with alloc_fail(dev[0], 1, "interworking_set_eap_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    with alloc_fail(dev[0], 1, "wpa_config_add_network;interworking_connect"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    with alloc_fail(dev[0], 1, "=interworking_connect"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].request("NOTE wpa_config_set(eap)")
+    with alloc_fail(dev[0], 1, "wpa_config_parse_eap;wpa_config_set;interworking_connect"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].request("NOTE wpa_config_set(TTLS-NON_EAP_MSCHAPV2-phase2)")
+    with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].remove_cred(id)
+
+    id = dev[0].add_cred_values({ 'roaming_consortium': "112233",
+                                  'domain': "example.com",
+                                  'username': "hs20-test",
+                                  'password': "password",
+                                  'eap': 'TTLS',
+                                  'phase2': "auth=MSCHAPV2" })
+    interworking_select(dev[0], bssid, "home", freq=2412)
+    dev[0].dump_monitor()
+    dev[0].request("NOTE anon = os_strdup()")
+    with alloc_fail(dev[0], 2, "interworking_set_eap_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].request("NOTE wpa_config_set_quoted(anonymous_identity)")
+    with alloc_fail(dev[0], 1, "=wpa_config_set_quoted;interworking_set_eap_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].request("NOTE Successful connection with cred->realm not included")
+    dev[0].request("INTERWORKING_CONNECT " + bssid)
+    dev[0].wait_connected()
+    dev[0].remove_cred(id)
+    dev[0].wait_disconnected()
+
+    id = dev[0].add_cred_values({ 'roaming_consortium': "112233",
+                                  'domain': "example.com",
+                                  'realm': "example.com",
+                                  'username': "user",
+                                  'password': "password",
+                                  'eap': 'PEAP' })
+    interworking_select(dev[0], bssid, "home", freq=2412)
+    dev[0].dump_monitor()
+    dev[0].request("NOTE id = os_strdup()")
+    with alloc_fail(dev[0], 2, "interworking_set_eap_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].request("NOTE wpa_config_set_quoted(identity)")
+    with alloc_fail(dev[0], 1, "=wpa_config_set_quoted;interworking_set_eap_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].remove_cred(id)
+
+    id = dev[0].add_cred_values({ 'roaming_consortium': "112233",
+                                  'domain': "example.com",
+                                  'realm': "example.com",
+                                  'username': "user",
+                                  'password': "password",
+                                  'eap': "TTLS" })
+    interworking_select(dev[0], bssid, "home", freq=2412)
+    dev[0].dump_monitor()
+    dev[0].request("NOTE wpa_config_set_quoted(identity) (second)")
+    with alloc_fail(dev[0], 2, "=wpa_config_set_quoted;interworking_set_eap_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].request("NOTE wpa_config_set_quoted(password)")
+    with alloc_fail(dev[0], 3, "=wpa_config_set_quoted;interworking_set_eap_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    with alloc_fail(dev[0], 1, "wpa_config_add_network;interworking_connect_roaming_consortium"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    with alloc_fail(dev[0], 1, "=interworking_connect_roaming_consortium"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].remove_cred(id)
+
+    id = dev[0].add_cred_values({ 'roaming_consortium': "112233",
+                                  'domain': "example.com",
+                                  'realm': "example.com",
+                                  'username': "user",
+                                  'eap': "PEAP" })
+    dev[0].set_cred(id, "password", "ext:password");
+    interworking_select(dev[0], bssid, "home", freq=2412)
+    dev[0].dump_monitor()
+    dev[0].request("NOTE wpa_config_set(password)")
+    with alloc_fail(dev[0], 3, "wpa_config_set;interworking_set_eap_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    with alloc_fail(dev[0], 1, "interworking_set_hs20_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].remove_cred(id)
+
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'domain': "example.com",
+                                  'username': "certificate-user",
+                                  'phase1': "include_tls_length=0",
+                                  'domain_suffix_match': "example.com",
+                                  'ca_cert': "auth_serv/ca.pem",
+                                  'client_cert': "auth_serv/user.pem",
+                                  'private_key': "auth_serv/user.key",
+                                  'private_key_passwd': "secret" })
+    interworking_select(dev[0], bssid, "home", freq=2412)
+    dev[0].dump_monitor()
+    dev[0].request("NOTE wpa_config_set_quoted(client_cert)")
+    with alloc_fail(dev[0], 2, "=wpa_config_set_quoted;interworking_set_eap_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].request("NOTE wpa_config_set_quoted(private_key)")
+    with alloc_fail(dev[0], 3, "=wpa_config_set_quoted;interworking_set_eap_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].request("NOTE wpa_config_set_quoted(private_key_passwd)")
+    with alloc_fail(dev[0], 4, "=wpa_config_set_quoted;interworking_set_eap_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].request("NOTE wpa_config_set_quoted(ca_cert)")
+    with alloc_fail(dev[0], 5, "=wpa_config_set_quoted;interworking_set_eap_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].request("NOTE wpa_config_set_quoted(domain_suffix_match)")
+    with alloc_fail(dev[0], 6, "=wpa_config_set_quoted;interworking_set_eap_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    with alloc_fail(dev[0], 1, "interworking_set_hs20_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].remove_cred(id)
+
+    id = dev[0].add_cred_values({ 'imsi': "555444-333222111", 'eap': "SIM",
+                                  'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"})
+    interworking_select(dev[0], bssid, freq=2412)
+    dev[0].dump_monitor()
+    with alloc_fail(dev[0], 1, "interworking_set_hs20_params"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].request("NOTE wpa_config_set_quoted(password;milenage)")
+    with alloc_fail(dev[0], 2, "=wpa_config_set_quoted;interworking_connect_3gpp"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].request("NOTE wpa_config_set(eap)")
+    with alloc_fail(dev[0], 1, "wpa_config_parse_eap;wpa_config_set;interworking_connect_3gpp"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].request("NOTE set_root_nai:wpa_config_set(identity)")
+    with alloc_fail(dev[0], 1, "wpa_config_parse_str;interworking_connect_3gpp"):
+            dev[0].request("INTERWORKING_CONNECT " + bssid)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].remove_cred(id)
+
+    id = dev[0].add_cred_values({ 'roaming_consortium': "112233",
+                                  'username': "user@example.com",
+                                  'password': "password" })
+    interworking_select(dev[0], bssid, freq=2412)
+    dev[0].dump_monitor()
+    dev[0].request("NOTE Interworking: No EAP method set for credential using roaming consortium")
+    dev[0].request("INTERWORKING_CONNECT " + bssid)
+    dev[0].remove_cred(id)
+
+    hapd.disable()
+    params = hs20_ap_params()
+    params['nai_realm'] = "0,example.com,25[3:26]"
+    hapd = hostapd.add_ap(apdev[0], params)
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'domain': "example.com",
+                                  'username': "hs20-test",
+                                  'password': "password" })
+    interworking_select(dev[0], bssid, freq=2412)
+    dev[0].dump_monitor()
+    dev[0].request("NOTE wpa_config_set(PEAP/FAST-phase1)")
+    with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].request("NOTE wpa_config_set(PEAP/FAST-pac_interworking)")
+    with alloc_fail(dev[0], 2, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].request("NOTE wpa_config_set(PEAP/FAST-phase2)")
+    with alloc_fail(dev[0], 3, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+    hapd.disable()
+    params = hs20_ap_params()
+    params['nai_realm'] = "0,example.com,21"
+    hapd = hostapd.add_ap(apdev[0], params)
+    interworking_select(dev[0], bssid, freq=2412)
+    dev[0].request("NOTE wpa_config_set(TTLS-defaults-phase2)")
+    with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+    hapd.disable()
+    params = hs20_ap_params()
+    params['nai_realm'] = "0,example.com,21[2:3]"
+    hapd = hostapd.add_ap(apdev[0], params)
+    interworking_select(dev[0], bssid, freq=2412)
+    dev[0].request("NOTE wpa_config_set(TTLS-NON_EAP_MSCHAP-phase2)")
+    with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+    hapd.disable()
+    params = hs20_ap_params()
+    params['nai_realm'] = "0,example.com,21[2:2]"
+    hapd = hostapd.add_ap(apdev[0], params)
+    interworking_select(dev[0], bssid, freq=2412)
+    dev[0].request("NOTE wpa_config_set(TTLS-NON_EAP_CHAP-phase2)")
+    with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+    hapd.disable()
+    params = hs20_ap_params()
+    params['nai_realm'] = "0,example.com,21[2:1]"
+    hapd = hostapd.add_ap(apdev[0], params)
+    interworking_select(dev[0], bssid, freq=2412)
+    dev[0].request("NOTE wpa_config_set(TTLS-NON_EAP_PAP-phase2)")
+    with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+    hapd.disable()
+    params = hs20_ap_params()
+    params['nai_realm'] = "0,example.com,21[3:26]"
+    hapd = hostapd.add_ap(apdev[0], params)
+    interworking_select(dev[0], bssid, freq=2412)
+    dev[0].request("NOTE wpa_config_set(TTLS-EAP-MSCHAPV2-phase2)")
+    with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
+        dev[0].request("INTERWORKING_CONNECT " + bssid)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+    dev[0].remove_cred(id)
+
+def test_ap_hs20_unexpected(dev, apdev):
+    """Unexpected Hotspot 2.0 AP configuration"""
+    check_eap_capa(dev[0], "MSCHAPV2")
+    bssid = apdev[0]['bssid']
+    params = hostapd.wpa_eap_params(ssid="test-hs20-fake")
+    params['wpa'] = "3"
+    params['wpa_pairwise'] = "TKIP CCMP"
+    params['rsn_pairwise'] = "CCMP"
+    #params['vendor_elements'] = 'dd07506f9a10140000'
+    params['vendor_elements'] = 'dd04506f9a10'
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    dev[0].scan_for_bss(bssid, freq="2412")
+    dev[0].connect("test-hs20-fake", key_mgmt="WPA-EAP", eap="TTLS",
+                   pairwise="TKIP",
+                   identity="hs20-test", password="password",
+                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                   scan_freq="2412")
+
+    dev[1].hs20_enable()
+    dev[1].scan_for_bss(bssid, freq="2412")
+    dev[1].connect("test-hs20-fake", key_mgmt="WPA-EAP", eap="TTLS",
+                   proto="WPA",
+                   identity="hs20-test", password="password",
+                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                   scan_freq="2412")
+
+    dev[2].hs20_enable()
+    dev[2].scan_for_bss(bssid, freq="2412")
+    dev[2].connect("test-hs20-fake", key_mgmt="WPA-EAP", eap="TTLS",
+                   proto="RSN", pairwise="CCMP",
+                   identity="hs20-test", password="password",
+                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                   scan_freq="2412")
+
+def test_ap_interworking_element_update(dev, apdev):
+    """Dynamic Interworking element update"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].hs20_enable()
+    dev[0].scan_for_bss(bssid, freq="2412")
+    bss = dev[0].get_bss(bssid)
+    logger.info("Before update: " + str(bss))
+    if '6b091e0701020000000300' not in bss['ie']:
+        raise Exception("Expected Interworking element not seen before update")
+
+    # Update configuration parameters related to Interworking element
+    hapd.set('access_network_type', '2')
+    hapd.set('asra', '1')
+    hapd.set('esr', '1')
+    hapd.set('uesa', '1')
+    hapd.set('venue_group', '2')
+    hapd.set('venue_type', '8')
+    if "OK" not in hapd.request("UPDATE_BEACON"):
+        raise Exception("UPDATE_BEACON failed")
+    dev[0].request("BSS_FLUSH 0")
+    dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
+    bss = dev[0].get_bss(bssid)
+    logger.info("After update: " + str(bss))
+    if '6b09f20208020000000300' not in bss['ie']:
+        raise Exception("Expected Interworking element not seen after update")
index 8a8aa9f..0cc4b1b 100644 (file)
@@ -4,30 +4,40 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import time
 import logging
 logger = logging.getLogger()
 import struct
-import subprocess
 
 import hostapd
 from utils import HwsimSkip, alloc_fail
 import hwsim_utils
 from test_ap_csa import csa_supported
 
-def clear_scan_cache(ifname):
-    subprocess.call(['ifconfig', ifname, 'up'])
-    subprocess.call(['iw', ifname, 'scan', 'trigger', 'freq', '2412', 'flush'])
+def clear_scan_cache(apdev):
+    ifname = apdev['ifname']
+    hostapd.cmd_execute(apdev, ['ifconfig', ifname, 'up'])
+    hostapd.cmd_execute(apdev, ['iw', ifname, 'scan', 'trigger', 'freq', '2412',
+                                'flush'])
     time.sleep(0.1)
-    subprocess.call(['ifconfig', ifname, 'down'])
+    hostapd.cmd_execute(apdev, ['ifconfig', ifname, 'down'])
+
+def set_world_reg(apdev0=None, apdev1=None, dev0=None):
+    if apdev0:
+        hostapd.cmd_execute(apdev0, ['iw', 'reg', 'set', '00'])
+    if apdev1:
+        hostapd.cmd_execute(apdev1, ['iw', 'reg', 'set', '00'])
+    if dev0:
+        dev0.cmd_execute(['iw', 'reg', 'set', '00'])
 
 def test_ap_ht40_scan(dev, apdev):
     """HT40 co-ex scan"""
-    clear_scan_cache(apdev[0]['ifname'])
+    clear_scan_cache(apdev[0])
     params = { "ssid": "test-ht40",
                "channel": "5",
                "ht_capab": "[HT40-]"}
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
 
     state = hapd.get_status_field("state")
     if state != "HT_SCAN":
@@ -56,18 +66,19 @@ def test_ap_ht40_scan(dev, apdev):
 
     dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
 
+@remote_compatible
 def test_ap_ht40_scan_conflict(dev, apdev):
     """HT40 co-ex scan conflict"""
-    clear_scan_cache(apdev[0]['ifname'])
+    clear_scan_cache(apdev[0])
     params = { "ssid": "test-ht40",
                "channel": "6",
                "ht_capab": "[HT40+]"}
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     params = { "ssid": "test-ht40",
                "channel": "5",
                "ht_capab": "[HT40-]"}
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
 
     state = hapd.get_status_field("state")
     if state != "HT_SCAN":
@@ -96,18 +107,19 @@ def test_ap_ht40_scan_conflict(dev, apdev):
 
     dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
 
+@remote_compatible
 def test_ap_ht40_scan_conflict2(dev, apdev):
     """HT40 co-ex scan conflict (HT40-)"""
-    clear_scan_cache(apdev[0]['ifname'])
+    clear_scan_cache(apdev[0])
     params = { "ssid": "test-ht40",
                "channel": "11",
                "ht_capab": "[HT40-]"}
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     params = { "ssid": "test-ht40",
                "channel": "1",
                "ht_capab": "[HT40+]"}
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
 
     state = hapd.get_status_field("state")
     if state != "HT_SCAN":
@@ -138,23 +150,23 @@ def test_ap_ht40_scan_conflict2(dev, apdev):
 
 def test_ap_ht40_scan_not_affected(dev, apdev):
     """HT40 co-ex scan and other BSS not affected"""
-    clear_scan_cache(apdev[0]['ifname'])
+    clear_scan_cache(apdev[0])
     params = { "ssid": "test-ht20",
                "channel": "11" }
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
-    subprocess.call(['ifconfig', apdev[0]['ifname'], 'up'])
-    subprocess.call(['iw', apdev[0]['ifname'], 'scan', 'trigger', 'freq', '2462'])
+    hostapd.cmd_execute(apdev[0], ['ifconfig', apdev[0]['ifname'], 'up'])
+    hostapd.cmd_execute(apdev[0], ['iw', apdev[0]['ifname'], 'scan', 'trigger',
+                                   'freq', '2462'])
     time.sleep(0.5)
-    subprocess.call(['iw', apdev[0]['ifname'], 'scan', 'dump'],
-                    stdout=open('/dev/null', 'w'))
+    hostapd.cmd_execute(apdev[0], ['iw', apdev[0]['ifname'], 'scan', 'dump'])
     time.sleep(0.1)
-    subprocess.call(['ifconfig', apdev[0]['ifname'], 'down'])
+    hostapd.cmd_execute(apdev[0], ['ifconfig', apdev[0]['ifname'], 'down'])
 
     params = { "ssid": "test-ht40",
                "channel": "1",
                "ht_capab": "[HT40+]"}
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
 
     state = hapd.get_status_field("state")
     if state != "HT_SCAN":
@@ -183,17 +195,18 @@ def test_ap_ht40_scan_not_affected(dev, apdev):
 
     dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
 
+@remote_compatible
 def test_ap_ht40_scan_legacy_conflict(dev, apdev):
     """HT40 co-ex scan conflict with legacy 20 MHz AP"""
-    clear_scan_cache(apdev[0]['ifname'])
+    clear_scan_cache(apdev[0])
     params = { "ssid": "legacy-20",
                "channel": "7", "ieee80211n": "0" }
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     params = { "ssid": "test-ht40",
                "channel": "5",
                "ht_capab": "[HT40-]"}
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
 
     state = hapd.get_status_field("state")
     if state != "HT_SCAN":
@@ -222,17 +235,18 @@ def test_ap_ht40_scan_legacy_conflict(dev, apdev):
 
     dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
 
+@remote_compatible
 def test_ap_ht40_scan_ht20_conflict(dev, apdev):
     """HT40 co-ex scan conflict with HT 20 MHz AP"""
-    clear_scan_cache(apdev[0]['ifname'])
+    clear_scan_cache(apdev[0])
     params = { "ssid": "ht-20",
                "channel": "7", "ieee80211n": "1" }
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     params = { "ssid": "test-ht40",
                "channel": "5",
                "ht_capab": "[HT40-]"}
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
 
     state = hapd.get_status_field("state")
     if state != "HT_SCAN":
@@ -263,16 +277,16 @@ def test_ap_ht40_scan_ht20_conflict(dev, apdev):
 
 def test_ap_ht40_scan_intolerant(dev, apdev):
     """HT40 co-ex scan finding an AP advertising 40 MHz intolerant"""
-    clear_scan_cache(apdev[0]['ifname'])
+    clear_scan_cache(apdev[0])
     params = { "ssid": "another-bss",
                "channel": "1",
                "ht_capab": "[40-INTOLERANT]" }
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     params = { "ssid": "test-ht40",
                "channel": "1",
                "ht_capab": "[HT40+]"}
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
 
     state = hapd.get_status_field("state")
     if state != "HT_SCAN":
@@ -303,16 +317,16 @@ def test_ap_ht40_scan_intolerant(dev, apdev):
 
 def test_ap_ht40_scan_match(dev, apdev):
     """HT40 co-ex scan matching configuration"""
-    clear_scan_cache(apdev[0]['ifname'])
+    clear_scan_cache(apdev[0])
     params = { "ssid": "test-ht40",
                "channel": "5",
                "ht_capab": "[HT40-]"}
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     params = { "ssid": "test-ht40",
                "channel": "5",
                "ht_capab": "[HT40-]"}
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
 
     state = hapd.get_status_field("state")
     if state != "HT_SCAN":
@@ -343,7 +357,7 @@ def test_ap_ht40_scan_match(dev, apdev):
 
 def test_ap_ht40_5ghz_match(dev, apdev):
     """HT40 co-ex scan on 5 GHz with matching pri/sec channel"""
-    clear_scan_cache(apdev[0]['ifname'])
+    clear_scan_cache(apdev[0])
     try:
         hapd = None
         hapd2 = None
@@ -352,13 +366,13 @@ def test_ap_ht40_5ghz_match(dev, apdev):
                    "channel": "36",
                    "country_code": "US",
                    "ht_capab": "[HT40+]"}
-        hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+        hapd2 = hostapd.add_ap(apdev[1], params)
 
         params = { "ssid": "test-ht40",
                    "hw_mode": "a",
                    "channel": "36",
                    "ht_capab": "[HT40+]"}
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
 
         state = hapd.get_status_field("state")
         if state != "HT_SCAN":
@@ -392,12 +406,12 @@ def test_ap_ht40_5ghz_match(dev, apdev):
             hapd.request("DISABLE")
         if hapd2:
             hapd2.request("DISABLE")
-        subprocess.call(['iw', 'reg', 'set', '00'])
+        set_world_reg(apdev[0], apdev[1], dev[0])
         dev[0].flush_scan_cache()
 
 def test_ap_ht40_5ghz_switch(dev, apdev):
     """HT40 co-ex scan on 5 GHz switching pri/sec channel"""
-    clear_scan_cache(apdev[0]['ifname'])
+    clear_scan_cache(apdev[0])
     try:
         hapd = None
         hapd2 = None
@@ -406,13 +420,13 @@ def test_ap_ht40_5ghz_switch(dev, apdev):
                    "channel": "36",
                    "country_code": "US",
                    "ht_capab": "[HT40+]"}
-        hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+        hapd2 = hostapd.add_ap(apdev[1], params)
 
         params = { "ssid": "test-ht40",
                    "hw_mode": "a",
                    "channel": "40",
                    "ht_capab": "[HT40-]"}
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
 
         state = hapd.get_status_field("state")
         if state != "HT_SCAN":
@@ -446,11 +460,11 @@ def test_ap_ht40_5ghz_switch(dev, apdev):
             hapd.request("DISABLE")
         if hapd2:
             hapd2.request("DISABLE")
-        subprocess.call(['iw', 'reg', 'set', '00'])
+        set_world_reg(apdev[0], apdev[1], dev[0])
 
 def test_ap_ht40_5ghz_switch2(dev, apdev):
     """HT40 co-ex scan on 5 GHz switching pri/sec channel (2)"""
-    clear_scan_cache(apdev[0]['ifname'])
+    clear_scan_cache(apdev[0])
     try:
         hapd = None
         hapd2 = None
@@ -459,7 +473,7 @@ def test_ap_ht40_5ghz_switch2(dev, apdev):
                    "channel": "36",
                    "country_code": "US",
                    "ht_capab": "[HT40+]"}
-        hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+        hapd2 = hostapd.add_ap(apdev[1], params)
 
         id = dev[0].add_network()
         dev[0].set_network(id, "mode", "2")
@@ -474,7 +488,7 @@ def test_ap_ht40_5ghz_switch2(dev, apdev):
                    "hw_mode": "a",
                    "channel": "40",
                    "ht_capab": "[HT40-]"}
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
 
         state = hapd.get_status_field("state")
         if state != "HT_SCAN":
@@ -508,7 +522,7 @@ def test_ap_ht40_5ghz_switch2(dev, apdev):
             hapd.request("DISABLE")
         if hapd2:
             hapd2.request("DISABLE")
-        subprocess.call(['iw', 'reg', 'set', '00'])
+        set_world_reg(apdev[0], apdev[1], dev[0])
         dev[0].flush_scan_cache()
 
 def test_obss_scan(dev, apdev):
@@ -517,13 +531,29 @@ def test_obss_scan(dev, apdev):
                "channel": "6",
                "ht_capab": "[HT40-]",
                "obss_interval": "10" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    params = { "ssid": "another-bss",
+               "channel": "9",
+               "ieee80211n": "0" }
+    hostapd.add_ap(apdev[1], params)
+    run_obss_scan(hapd, dev)
+
+def test_obss_scan_ht40_plus(dev, apdev):
+    """Overlapping BSS scan request (HT40+)"""
+    params = { "ssid": "obss-scan",
+               "channel": "6",
+               "ht_capab": "[HT40+]",
+               "obss_interval": "10" }
+    hapd = hostapd.add_ap(apdev[0], params)
 
     params = { "ssid": "another-bss",
                "channel": "9",
                "ieee80211n": "0" }
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
+    run_obss_scan(hapd, dev)
 
+def run_obss_scan(hapd, dev):
     dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437")
     hapd.set("ext_mgmt_frame_handling", "1")
     logger.info("Waiting for OBSS scan to occur")
@@ -561,12 +591,12 @@ def test_obss_scan_40_intolerant(dev, apdev):
                "channel": "6",
                "ht_capab": "[HT40-]",
                "obss_interval": "10" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     params = { "ssid": "another-bss",
                "channel": "7",
                "ht_capab": "[40-INTOLERANT]" }
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437")
     hapd.set("ext_mgmt_frame_handling", "1")
@@ -601,11 +631,11 @@ def test_obss_scan_40_intolerant(dev, apdev):
 
 def test_obss_coex_report_handling(dev, apdev):
     """Overlapping BSS scan report handling with obss_interval=0"""
-    clear_scan_cache(apdev[0]['ifname'])
+    clear_scan_cache(apdev[0])
     params = { "ssid": "obss-scan",
                "channel": "6",
                "ht_capab": "[HT40-]" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
     dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437")
 
@@ -630,12 +660,12 @@ def test_obss_coex_report_handling(dev, apdev):
 
 def test_obss_coex_report_handling1(dev, apdev):
     """Overlapping BSS scan report handling with obss_interval=1"""
-    clear_scan_cache(apdev[0]['ifname'])
+    clear_scan_cache(apdev[0])
     params = { "ssid": "obss-scan",
                "channel": "6",
                "ht_capab": "[HT40+]",
                "obss_interval": "1" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
     dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437")
 
@@ -668,7 +698,7 @@ def test_olbc(dev, apdev):
                "channel": "6",
                "ht_capab": "[HT40-]",
                "ap_table_expiration_time": "2" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     status = hapd.get_status()
     if status['olbc'] != '0' or status['olbc_ht'] != '0':
         raise Exception("Unexpected OLBC information")
@@ -677,14 +707,13 @@ def test_olbc(dev, apdev):
                "hw_mode": "b",
                "channel": "6",
                "wmm_enabled": "0" }
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
     time.sleep(0.5)
     status = hapd.get_status()
     if status['olbc'] != '1' or status['olbc_ht'] != '1':
         raise Exception("Missing OLBC information")
 
-    hapd_global = hostapd.HostapdGlobal()
-    hapd_global.remove(apdev[1]['ifname'])
+    hostapd.remove_bss(apdev[1])
 
     logger.info("Waiting for OLBC state to time out")
     cleared = False
@@ -702,14 +731,14 @@ def test_olbc_table_limit(dev, apdev):
     ifname1 = apdev[0]['ifname']
     ifname2 = apdev[0]['ifname'] + '-2'
     ifname3 = apdev[0]['ifname'] + '-3'
-    hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
-    hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
-    hostapd.add_bss('phy3', ifname3, 'bss-3.conf')
+    hostapd.add_bss(apdev[0], ifname1, 'bss-1.conf')
+    hostapd.add_bss(apdev[0], ifname2, 'bss-2.conf')
+    hostapd.add_bss(apdev[0], ifname3, 'bss-3.conf')
 
     params = { "ssid": "test-olbc",
                "channel": "1",
                "ap_table_max_size": "2" }
-    hapd = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[1], params)
 
     time.sleep(0.3)
     with alloc_fail(hapd, 1, "ap_list_process_beacon"):
@@ -729,7 +758,7 @@ def test_olbc_5ghz(dev, apdev):
                    "hw_mode": "a",
                    "channel": "36",
                    "ht_capab": "[HT40+]" }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
         status = hapd.get_status()
         if status['olbc'] != '0' or status['olbc_ht'] != '0':
             raise Exception("Unexpected OLBC information")
@@ -740,7 +769,7 @@ def test_olbc_5ghz(dev, apdev):
                    "channel": "36",
                    "ieee80211n": "0",
                    "wmm_enabled": "0" }
-        hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+        hapd2 = hostapd.add_ap(apdev[1], params)
         found = False
         for i in range(20):
             time.sleep(0.1)
@@ -756,18 +785,19 @@ def test_olbc_5ghz(dev, apdev):
             hapd.request("DISABLE")
         if hapd2:
             hapd2.request("DISABLE")
-        subprocess.call(['iw', 'reg', 'set', '00'])
+        set_world_reg(apdev[0], apdev[1], None)
 
 def test_ap_require_ht(dev, apdev):
     """Require HT"""
     params = { "ssid": "require-ht",
                "require_ht": "1" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
 
     dev[1].connect("require-ht", key_mgmt="NONE", scan_freq="2412",
                    disable_ht="1", wait_connect=False)
     dev[0].connect("require-ht", key_mgmt="NONE", scan_freq="2412")
     ev = dev[1].wait_event(["CTRL-EVENT-ASSOC-REJECT"])
+    dev[1].request("DISCONNECT")
     if ev is None:
         raise Exception("Association rejection timed out")
     if "status_code=27" not in ev:
@@ -778,38 +808,41 @@ def test_ap_require_ht(dev, apdev):
                    ampdu_density="1", disable_ht40="1", disable_sgi="1",
                    disable_ldpc="1")
 
+@remote_compatible
 def test_ap_require_ht_limited_rates(dev, apdev):
     """Require HT with limited supported rates"""
     params = { "ssid": "require-ht",
                "supported_rates": "60 120 240 360 480 540",
                "require_ht": "1" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
 
     dev[1].connect("require-ht", key_mgmt="NONE", scan_freq="2412",
                    disable_ht="1", wait_connect=False)
     dev[0].connect("require-ht", key_mgmt="NONE", scan_freq="2412")
     ev = dev[1].wait_event(["CTRL-EVENT-ASSOC-REJECT"])
+    dev[1].request("DISCONNECT")
     if ev is None:
         raise Exception("Association rejection timed out")
     if "status_code=27" not in ev:
         raise Exception("Unexpected rejection status code")
 
+@remote_compatible
 def test_ap_ht_capab_not_supported(dev, apdev):
     """HT configuration with driver not supporting all ht_capab entries"""
     params = { "ssid": "test-ht40",
                "channel": "5",
                "ht_capab": "[HT40-][LDPC][SMPS-STATIC][SMPS-DYNAMIC][GF][SHORT-GI-20][SHORT-GI-40][TX-STBC][RX-STBC1][RX-STBC12][RX-STBC123][DELAYED-BA][MAX-AMSDU-7935][DSSS_CCK-40][LSIG-TXOP-PROT]"}
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, no_enable=True)
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
     if "FAIL" not in hapd.request("ENABLE"):
         raise Exception("Unexpected ENABLE success")
 
 def test_ap_ht_40mhz_intolerant_sta(dev, apdev):
     """Associated STA indicating 40 MHz intolerant"""
-    clear_scan_cache(apdev[0]['ifname'])
+    clear_scan_cache(apdev[0])
     params = { "ssid": "intolerant",
                "channel": "6",
                "ht_capab": "[HT40-]" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     if hapd.get_status_field("num_sta_ht40_intolerant") != "0":
         raise Exception("Unexpected num_sta_ht40_intolerant value")
     if hapd.get_status_field("secondary_channel") != "-1":
@@ -838,12 +871,12 @@ def test_ap_ht_40mhz_intolerant_sta(dev, apdev):
 
 def test_ap_ht_40mhz_intolerant_ap(dev, apdev):
     """Associated STA reports 40 MHz intolerant AP after association"""
-    clear_scan_cache(apdev[0]['ifname'])
+    clear_scan_cache(apdev[0])
     params = { "ssid": "ht",
                "channel": "6",
                "ht_capab": "[HT40-]",
                "obss_interval": "3" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("ht", key_mgmt="NONE", scan_freq="2437")
 
@@ -854,7 +887,7 @@ def test_ap_ht_40mhz_intolerant_ap(dev, apdev):
     params = { "ssid": "intolerant",
                "channel": "5",
                "ht_capab": "[40-INTOLERANT]" }
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd2 = hostapd.add_ap(apdev[1], params)
 
     logger.info("Waiting for co-ex report from STA")
     ok = False
@@ -897,7 +930,7 @@ def test_ap_ht40_csa(dev, apdev):
                    "channel": "36",
                    "ht_capab": "[HT40+]",
                    "ieee80211n": "1" }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
 
         dev[0].connect("ht", key_mgmt="NONE", scan_freq="5180")
         hwsim_utils.test_connectivity(dev[0], hapd)
@@ -927,7 +960,7 @@ def test_ap_ht40_csa(dev, apdev):
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['iw', 'reg', 'set', '00'])
+        set_world_reg(apdev[0], None, dev[0])
         dev[0].flush_scan_cache()
 
 def test_ap_ht40_csa2(dev, apdev):
@@ -941,7 +974,7 @@ def test_ap_ht40_csa2(dev, apdev):
                    "channel": "36",
                    "ht_capab": "[HT40+]",
                    "ieee80211n": "1" }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
 
         dev[0].connect("ht", key_mgmt="NONE", scan_freq="5180")
         hwsim_utils.test_connectivity(dev[0], hapd)
@@ -971,7 +1004,7 @@ def test_ap_ht40_csa2(dev, apdev):
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['iw', 'reg', 'set', '00'])
+        set_world_reg(apdev[0], None, dev[0])
         dev[0].flush_scan_cache()
 
 def test_ap_ht40_csa3(dev, apdev):
@@ -985,7 +1018,7 @@ def test_ap_ht40_csa3(dev, apdev):
                    "channel": "36",
                    "ht_capab": "[HT40+]",
                    "ieee80211n": "1" }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
 
         dev[0].connect("ht", key_mgmt="NONE", scan_freq="5180")
         hwsim_utils.test_connectivity(dev[0], hapd)
@@ -1015,35 +1048,37 @@ def test_ap_ht40_csa3(dev, apdev):
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['iw', 'reg', 'set', '00'])
+        set_world_reg(apdev[0], None, dev[0])
         dev[0].flush_scan_cache()
 
+@remote_compatible
 def test_ap_ht_smps(dev, apdev):
     """SMPS AP configuration options"""
     params = { "ssid": "ht1", "ht_capab": "[SMPS-STATIC]" }
     try:
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
     except:
         raise HwsimSkip("Assume mac80211_hwsim was not recent enough to support SMPS")
     params = { "ssid": "ht2", "ht_capab": "[SMPS-DYNAMIC]" }
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd2 = hostapd.add_ap(apdev[1], params)
 
     dev[0].connect("ht1", key_mgmt="NONE", scan_freq="2412")
     dev[1].connect("ht2", key_mgmt="NONE", scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
     hwsim_utils.test_connectivity(dev[1], hapd2)
 
+@remote_compatible
 def test_prefer_ht20(dev, apdev):
     """Preference on HT20 over no-HT"""
     params = { "ssid": "test",
                "channel": "1",
                "ieee80211n": "0" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
     params = { "ssid": "test",
                "channel": "1",
                "ieee80211n": "1" }
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd2 = hostapd.add_ap(apdev[1], params)
     bssid2 = apdev[1]['bssid']
 
     dev[0].scan_for_bss(bssid, freq=2412)
@@ -1065,13 +1100,13 @@ def test_prefer_ht40(dev, apdev):
     params = { "ssid": "test",
                "channel": "1",
                "ieee80211n": "1" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
     params = { "ssid": "test",
                "channel": "1",
                "ieee80211n": "1",
                "ht_capab": "[HT40+]" }
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd2 = hostapd.add_ap(apdev[1], params)
     bssid2 = apdev[1]['bssid']
 
     dev[0].scan_for_bss(bssid, freq=2412)
@@ -1088,12 +1123,13 @@ def test_prefer_ht40(dev, apdev):
     if est != "135000":
         raise Exception("Unexpected BSS1 est_throughput: " + est)
 
+@remote_compatible
 def test_prefer_ht20_during_roam(dev, apdev):
     """Preference on HT20 over no-HT in roaming consideration"""
     params = { "ssid": "test",
                "channel": "1",
                "ieee80211n": "0" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
 
     dev[0].scan_for_bss(bssid, freq=2412)
@@ -1102,27 +1138,99 @@ def test_prefer_ht20_during_roam(dev, apdev):
     params = { "ssid": "test",
                "channel": "1",
                "ieee80211n": "1" }
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd2 = hostapd.add_ap(apdev[1], params)
     bssid2 = apdev[1]['bssid']
     dev[0].scan_for_bss(bssid2, freq=2412)
     dev[0].scan(freq=2412)
     dev[0].wait_connected()
-    
+
     if dev[0].get_status_field('bssid') != bssid2:
         raise Exception("Unexpected BSS selected")
 
+@remote_compatible
 def test_ap_ht40_5ghz_invalid_pair(dev, apdev):
     """HT40 on 5 GHz with invalid channel pair"""
-    clear_scan_cache(apdev[0]['ifname'])
+    clear_scan_cache(apdev[0])
     try:
         params = { "ssid": "test-ht40",
                    "hw_mode": "a",
                    "channel": "40",
                    "country_code": "US",
                    "ht_capab": "[HT40+]"}
-        hapd = hostapd.add_ap(apdev[1]['ifname'], params, wait_enabled=False)
-        ev = hapd.wait_event(["AP-DISABLED"], timeout=10)
+        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
+        ev = hapd.wait_event(["AP-DISABLED", "AP-ENABLED"], timeout=10)
+        if not ev:
+            raise Exception("AP setup failure timed out")
+        if "AP-ENABLED" in ev:
+            sec = hapd.get_status_field("secondary_channel")
+            if sec != "0":
+                raise Exception("Invalid 40 MHz channel accepted")
+    finally:
+        set_world_reg(apdev[0], None, None)
+
+@remote_compatible
+def test_ap_ht40_5ghz_disabled_sec(dev, apdev):
+    """HT40 on 5 GHz with disabled secondary channel"""
+    clear_scan_cache(apdev[0])
+    try:
+        params = { "ssid": "test-ht40",
+                   "hw_mode": "a",
+                   "channel": "48",
+                   "country_code": "US",
+                   "ht_capab": "[HT40+]"}
+        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
+        ev = hapd.wait_event(["AP-DISABLED", "AP-ENABLED"], timeout=10)
         if not ev:
             raise Exception("AP setup failure timed out")
+        if "AP-ENABLED" in ev:
+            sec = hapd.get_status_field("secondary_channel")
+            if sec != "0":
+                raise Exception("Invalid 40 MHz channel accepted")
     finally:
-        subprocess.call(['iw', 'reg', 'set', '00'])
+        set_world_reg(apdev[0], None, None)
+
+def test_ap_ht40_scan_broken_ap(dev, apdev):
+    """HT40 co-ex scan and broken legacy/HT AP"""
+    clear_scan_cache(apdev[0])
+
+    # Broken AP: Include HT Capabilities element but not HT Operation element
+    params = { "ssid": "legacy-20",
+               "channel": "7", "ieee80211n": "0",
+               "wmm_enabled": "1",
+               "vendor_elements": "2d1a0e001bffff000000000000000000000100000000000000000000" }
+    hapd2 = hostapd.add_ap(apdev[1], params)
+
+    params = { "ssid": "test-ht40",
+               "channel": "5",
+               "ht_capab": "[HT40-]"}
+    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
+
+    state = hapd.get_status_field("state")
+    if state != "HT_SCAN":
+        time.sleep(0.1)
+        state = hapd.get_status_field("state")
+        if state != "HT_SCAN":
+            raise Exception("Unexpected interface state - expected HT_SCAN")
+
+    ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
+    if not ev:
+        raise Exception("AP setup timed out")
+
+    state = hapd.get_status_field("state")
+    if state != "ENABLED":
+        raise Exception("Unexpected interface state - expected ENABLED")
+
+    freq = hapd.get_status_field("freq")
+    if freq != "2432":
+        raise Exception("Unexpected frequency: " + freq)
+    pri = hapd.get_status_field("channel")
+    if pri != "5":
+        raise Exception("Unexpected primary channel: " + pri)
+    sec = hapd.get_status_field("secondary_channel")
+    if sec != "-1":
+        raise Exception("Unexpected secondary channel: " + sec)
+
+    dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
+    dev[1].connect("legacy-20", key_mgmt="NONE", scan_freq="2442")
+    hwsim_utils.test_connectivity(dev[0], hapd)
+    hwsim_utils.test_connectivity(dev[1], hapd2)
index c342d39..a65d43b 100644 (file)
@@ -24,7 +24,7 @@ def test_ap_mixed_security(dev, apdev):
     params["eap_server"] = "1"
     params["eap_user_file"] = "auth_serv/eap_user.conf"
     params['nas_identifier'] = "nas1.w1.fi"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect(ssid, key_mgmt="WPA-PSK", proto="WPA", pairwise="TKIP",
                    psk=passphrase, scan_freq="2412")
index 139756e..409d413 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 import struct
@@ -14,12 +15,16 @@ import os
 import hostapd
 import hwsim_utils
 from tshark import run_tshark
-from utils import alloc_fail
+from utils import alloc_fail, fail_test, wait_fail_trigger
 from wpasupplicant import WpaSupplicant
 
+@remote_compatible
 def test_ap_open(dev, apdev):
     """AP with open mode (no security) configuration"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    _test_ap_open(dev, apdev)
+
+def _test_ap_open(dev, apdev):
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
                    bg_scan_period="0")
     ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
@@ -39,16 +44,17 @@ def test_ap_open_packet_loss(dev, apdev):
                "ignore_auth_probability": "0.5",
                "ignore_assoc_probability": "0.5",
                "ignore_reassoc_probability": "0.5" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     for i in range(0, 3):
         dev[i].connect("open", key_mgmt="NONE", scan_freq="2412",
                        wait_connect=False)
     for i in range(0, 3):
         dev[i].wait_connected(timeout=20)
 
+@remote_compatible
 def test_ap_open_unknown_action(dev, apdev):
     """AP with open mode configuration and unknown Action frame"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
     bssid = apdev[0]['bssid']
     cmd = "MGMT_TX {} {} freq=2412 action=765432".format(bssid, bssid)
@@ -62,7 +68,7 @@ def test_ap_open_unknown_action(dev, apdev):
 
 def test_ap_open_invalid_wmm_action(dev, apdev):
     """AP with open mode configuration and invalid WMM Action frame"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
     bssid = apdev[0]['bssid']
     cmd = "MGMT_TX {} {} freq=2412 action=1100".format(bssid, bssid)
@@ -72,18 +78,20 @@ def test_ap_open_invalid_wmm_action(dev, apdev):
     if ev is None or "result=SUCCESS" not in ev:
         raise Exception("AP did not ack Action frame")
 
+@remote_compatible
 def test_ap_open_reconnect_on_inactivity_disconnect(dev, apdev):
     """Reconnect to open mode AP after inactivity related disconnection"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
     hapd.request("DEAUTHENTICATE " + dev[0].p2p_interface_addr() + " reason=4")
     dev[0].wait_disconnected(timeout=5)
     dev[0].wait_connected(timeout=2, error="Timeout on reconnection")
 
+@remote_compatible
 def test_ap_open_assoc_timeout(dev, apdev):
     """AP timing out association"""
     ssid = "test"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     dev[0].scan(freq="2412")
     hapd.set("ext_mgmt_frame_handling", "1")
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
@@ -120,9 +128,10 @@ def test_ap_open_assoc_timeout(dev, apdev):
     hapd.set("ext_mgmt_frame_handling", "0")
     dev[0].wait_connected(timeout=15)
 
+@remote_compatible
 def test_ap_open_id_str(dev, apdev):
     """AP with open mode and id_str"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412", id_str="foo",
                    wait_connect=False)
     ev = dev[0].wait_connected(timeout=10)
@@ -131,9 +140,10 @@ def test_ap_open_id_str(dev, apdev):
     if dev[0].get_status_field("id_str") != "foo":
         raise Exception("id_str mismatch")
 
+@remote_compatible
 def test_ap_open_select_any(dev, apdev):
     """AP with open mode and select any network"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     id = dev[0].connect("unknown", key_mgmt="NONE", scan_freq="2412",
                         only_add_network=True)
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
@@ -149,16 +159,17 @@ def test_ap_open_select_any(dev, apdev):
     dev[0].select_network("any")
     dev[0].wait_connected(timeout=10)
 
+@remote_compatible
 def test_ap_open_unexpected_assoc_event(dev, apdev):
     """AP with open mode and unexpected association event"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
     dev[0].request("DISCONNECT")
     dev[0].wait_disconnected(timeout=15)
     dev[0].dump_monitor()
     # This will be accepted due to matching network
-    subprocess.call(['iw', 'dev', dev[0].ifname, 'connect', 'open', "2412",
-                     apdev[0]['bssid']])
+    dev[0].cmd_execute(['iw', 'dev', dev[0].ifname, 'connect', 'open', "2412",
+                        apdev[0]['bssid']])
     dev[0].wait_connected(timeout=15)
     dev[0].dump_monitor()
 
@@ -166,13 +177,14 @@ def test_ap_open_unexpected_assoc_event(dev, apdev):
     dev[0].wait_disconnected(timeout=5)
     dev[0].dump_monitor()
     # This will result in disconnection due to no matching network
-    subprocess.call(['iw', 'dev', dev[0].ifname, 'connect', 'open', "2412",
-                     apdev[0]['bssid']])
+    dev[0].cmd_execute(['iw', 'dev', dev[0].ifname, 'connect', 'open', "2412",
+                        apdev[0]['bssid']])
     dev[0].wait_disconnected(timeout=15)
 
+@remote_compatible
 def test_ap_bss_load(dev, apdev):
     """AP with open mode (no security) configuration"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'],
+    hapd = hostapd.add_ap(apdev[0],
                           { "ssid": "open",
                             "bss_load_update_period": "10" })
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
@@ -188,16 +200,16 @@ def hapd_out_of_mem(hapd, apdev, count, func):
     with alloc_fail(hapd, count, func):
         started = False
         try:
-            hostapd.add_ap(apdev['ifname'], { "ssid": "open" })
+            hostapd.add_ap(apdev, { "ssid": "open" })
             started = True
         except:
             pass
         if started:
-            raise Exception("hostapd interface started even with memory allocation failure: " + arg)
+            raise Exception("hostapd interface started even with memory allocation failure: %d:%s" % (count, func))
 
 def test_ap_open_out_of_memory(dev, apdev):
     """hostapd failing to setup interface due to allocation failure"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     hapd_out_of_mem(hapd, apdev[1], 1, "hostapd_alloc_bss_data")
 
     for i in range(1, 3):
@@ -210,20 +222,20 @@ def test_ap_open_out_of_memory(dev, apdev):
 
     hapd_out_of_mem(hapd, apdev[1], 1, "hostapd_driver_init")
 
-    for i in range(1, 4):
+    for i in range(1, 3):
         hapd_out_of_mem(hapd, apdev[1], i, "=wpa_driver_nl80211_drv_init")
 
     # eloop_register_read_sock() call from i802_init()
-    hapd_out_of_mem(hapd, apdev[1], 1, "eloop_sock_table_add_sock;eloop_register_sock;?eloop_register_read_sock;=i802_init")
+    hapd_out_of_mem(hapd, apdev[1], 1, "eloop_sock_table_add_sock;?eloop_register_sock;?eloop_register_read_sock;=i802_init")
 
     # verify that a new interface can still be added when memory allocation does
     # not fail
-    hostapd.add_ap(apdev[1]['ifname'], { "ssid": "open" })
+    hostapd.add_ap(apdev[1], { "ssid": "open" })
 
 def test_bssid_black_white_list(dev, apdev):
     """BSSID black/white list"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
+    hapd2 = hostapd.add_ap(apdev[1], { "ssid": "open" })
 
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
                    bssid_whitelist=apdev[1]['bssid'])
@@ -272,7 +284,7 @@ def test_ap_open_wpas_in_bridge(dev, apdev):
         subprocess.call(['iw', ifname, 'set', '4addr', 'off'])
 
 def _test_ap_open_wpas_in_bridge(dev, apdev):
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
 
     br_ifname='sta-br0'
     ifname='wlan5'
@@ -297,10 +309,11 @@ def _test_ap_open_wpas_in_bridge(dev, apdev):
 
     wpas.connect("open", key_mgmt="NONE", scan_freq="2412")
 
+@remote_compatible
 def test_ap_open_start_disabled(dev, apdev):
     """AP with open mode and beaconing disabled"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open",
-                                                "start_disabled": "1" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open",
+                                      "start_disabled": "1" })
     bssid = apdev[0]['bssid']
 
     dev[0].flush_scan_cache()
@@ -312,10 +325,11 @@ def test_ap_open_start_disabled(dev, apdev):
     dev[0].scan_for_bss(bssid, freq=2412)
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
 
+@remote_compatible
 def test_ap_open_start_disabled2(dev, apdev):
     """AP with open mode and beaconing disabled (2)"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open",
-                                                "start_disabled": "1" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open",
+                                      "start_disabled": "1" })
     bssid = apdev[0]['bssid']
 
     dev[0].flush_scan_cache()
@@ -333,16 +347,17 @@ def test_ap_open_start_disabled2(dev, apdev):
     dev[0].request("RECONNECT")
     dev[0].wait_connected()
 
+@remote_compatible
 def test_ap_open_ifdown(dev, apdev):
     """AP with open mode and external ifconfig down"""
     params = { "ssid": "open",
                "ap_max_inactivity": "1" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
 
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
     dev[1].connect("open", key_mgmt="NONE", scan_freq="2412")
-    subprocess.call(['ip', 'link', 'set', 'dev', apdev[0]['ifname'], 'down'])
+    hapd.cmd_execute(['ip', 'link', 'set', 'dev', apdev[0]['ifname'], 'down'])
     ev = hapd.wait_event(["AP-STA-DISCONNECTED"], timeout=10)
     if ev is None:
         raise Exception("Timeout on AP-STA-DISCONNECTED (1)")
@@ -355,7 +370,7 @@ def test_ap_open_ifdown(dev, apdev):
     # The following wait tests beacon loss detection in mac80211 on dev0.
     # dev1 is used to test stopping of AP side functionality on client polling.
     dev[1].request("REMOVE_NETWORK all")
-    subprocess.call(['ip', 'link', 'set', 'dev', apdev[0]['ifname'], 'up'])
+    hapd.cmd_execute(['ip', 'link', 'set', 'dev', apdev[0]['ifname'], 'up'])
     dev[0].wait_disconnected()
     dev[1].wait_disconnected()
     ev = hapd.wait_event(["INTERFACE-ENABLED"], timeout=10)
@@ -366,7 +381,7 @@ def test_ap_open_ifdown(dev, apdev):
 
 def test_ap_open_disconnect_in_ps(dev, apdev, params):
     """Disconnect with the client in PS to regression-test a kernel bug"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
                    bg_scan_period="0")
     ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
@@ -406,11 +421,12 @@ def test_ap_open_disconnect_in_ps(dev, apdev, params):
         if state != 2:
             raise Exception("Didn't observe TIM bit getting set and unset (state=%d)" % state)
 
+@remote_compatible
 def test_ap_open_select_network(dev, apdev):
     """Open mode connection and SELECT_NETWORK to change network"""
-    hapd1 = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd1 = hostapd.add_ap(apdev[0], { "ssid": "open" })
     bssid1 = apdev[0]['bssid']
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], { "ssid": "open2" })
+    hapd2 = hostapd.add_ap(apdev[1], { "ssid": "open2" })
     bssid2 = apdev[1]['bssid']
 
     id1 = dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
@@ -432,9 +448,10 @@ def test_ap_open_select_network(dev, apdev):
     if bssid1 in res or bssid2 in res:
         raise Exception("Unexpected blacklist entry(2)")
 
+@remote_compatible
 def test_ap_open_disable_enable(dev, apdev):
     """AP with open mode getting disabled and re-enabled"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
                    bg_scan_period="0")
 
@@ -474,7 +491,7 @@ def sta_enable_disable(dev, bssid):
 
 def test_ap_open_sta_enable_disable(dev, apdev):
     """AP with open mode and wpa_supplicant ENABLE/DISABLE_NETWORK"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     bssid = apdev[0]['bssid']
 
     sta_enable_disable(dev[0], bssid)
@@ -482,3 +499,112 @@ def test_ap_open_sta_enable_disable(dev, apdev):
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
     sta_enable_disable(wpas, bssid)
+
+@remote_compatible
+def test_ap_open_select_twice(dev, apdev):
+    """AP with open mode and select network twice"""
+    id = dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
+                        only_add_network=True)
+    dev[0].select_network(id)
+    ev = dev[0].wait_event(["CTRL-EVENT-NETWORK-NOT-FOUND"], timeout=10)
+    if ev is None:
+        raise Exception("No result reported")
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
+    # Verify that the second SELECT_NETWORK starts a new scan immediately by
+    # waiting less than the default scan period.
+    dev[0].select_network(id)
+    dev[0].wait_connected(timeout=3)
+
+@remote_compatible
+def test_ap_open_reassoc_not_found(dev, apdev):
+    """AP with open mode and REASSOCIATE not finding a match"""
+    id = dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
+                        only_add_network=True)
+    dev[0].select_network(id)
+    ev = dev[0].wait_event(["CTRL-EVENT-NETWORK-NOT-FOUND"], timeout=10)
+    if ev is None:
+        raise Exception("No result reported")
+    dev[0].request("DISCONNECT")
+
+    time.sleep(0.1)
+    dev[0].dump_monitor()
+
+    dev[0].request("REASSOCIATE")
+    ev = dev[0].wait_event(["CTRL-EVENT-NETWORK-NOT-FOUND"], timeout=10)
+    if ev is None:
+        raise Exception("No result reported")
+    dev[0].request("DISCONNECT")
+
+@remote_compatible
+def test_ap_open_sta_statistics(dev, apdev):
+    """AP with open mode and STA statistics"""
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
+    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
+    addr = dev[0].own_addr()
+
+    stats1 = hapd.get_sta(addr)
+    logger.info("stats1: " + str(stats1))
+    time.sleep(0.4)
+    stats2 = hapd.get_sta(addr)
+    logger.info("stats2: " + str(stats2))
+    hwsim_utils.test_connectivity(dev[0], hapd)
+    stats3 = hapd.get_sta(addr)
+    logger.info("stats3: " + str(stats3))
+
+    # Cannot require specific inactive_msec changes without getting rid of all
+    # unrelated traffic, so for now, just print out the results in the log for
+    # manual checks.
+
+@remote_compatible
+def test_ap_open_poll_sta(dev, apdev):
+    """AP with open mode and STA poll"""
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
+    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
+    addr = dev[0].own_addr()
+
+    if "OK" not in hapd.request("POLL_STA " + addr):
+        raise Exception("POLL_STA failed")
+    ev = hapd.wait_event(["AP-STA-POLL-OK"], timeout=5)
+    if ev is None:
+        raise Exception("Poll response not seen")
+    if addr not in ev:
+        raise Exception("Unexpected poll response: " + ev)
+
+def test_ap_open_pmf_default(dev, apdev):
+    """AP with open mode (no security) configuration and pmf=2"""
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
+    dev[1].connect("open", key_mgmt="NONE", scan_freq="2412",
+                   ieee80211w="2", wait_connect=False)
+    dev[2].connect("open", key_mgmt="NONE", scan_freq="2412",
+                   ieee80211w="1")
+    try:
+        dev[0].request("SET pmf 2")
+        dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
+
+        dev[0].request("DISCONNECT")
+        dev[0].wait_disconnected()
+    finally:
+        dev[0].request("SET pmf 0")
+    dev[2].request("DISCONNECT")
+    dev[2].wait_disconnected()
+
+    ev = dev[1].wait_event(["CTRL-EVENT-CONNECTED"], timeout=0.1)
+    if ev is not None:
+        raise Exception("Unexpected dev[1] connection")
+    dev[1].request("DISCONNECT")
+
+def test_ap_open_drv_fail(dev, apdev):
+    """AP with open mode and driver operations failing"""
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
+
+    with fail_test(dev[0], 1, "wpa_driver_nl80211_authenticate"):
+        dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
+                       wait_connect=False)
+        wait_fail_trigger(dev[0], "GET_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+
+    with fail_test(dev[0], 1, "wpa_driver_nl80211_associate"):
+        dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
+                       wait_connect=False)
+        wait_fail_trigger(dev[0], "GET_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
index 517f2a7..9f5423b 100644 (file)
@@ -4,13 +4,17 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
-import subprocess
+import os
 
 import hwsim_utils
 import hostapd
+from tshark import run_tshark
+from utils import alloc_fail
 
+@remote_compatible
 def test_ap_fragmentation_rts_set_high(dev, apdev):
     """WPA2-PSK AP with fragmentation and RTS thresholds larger than frame length"""
     ssid = "test-wpa2-psk"
@@ -18,27 +22,29 @@ def test_ap_fragmentation_rts_set_high(dev, apdev):
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     params['rts_threshold'] = "1000"
     params['fragm_threshold'] = "2000"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_ap_fragmentation_open(dev, apdev):
     """Open AP with fragmentation threshold"""
     ssid = "fragmentation"
     params = {}
     params['ssid'] = ssid
     params['fragm_threshold'] = "1000"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_ap_fragmentation_wpa2(dev, apdev):
     """WPA2-PSK AP with fragmentation threshold"""
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     params['fragm_threshold'] = "1000"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
@@ -49,13 +55,14 @@ def test_ap_vendor_elements(dev, apdev):
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     params['vendor_elements'] = "dd0411223301"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    params['assocresp_elements'] = "dd0411223302"
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     bss = dev[0].get_bss(bssid)
     if "dd0411223301" not in bss['ie']:
         raise Exception("Vendor element not shown in scan results")
 
-    hapd.set('vendor_elements', 'dd051122330203')
+    hapd.set('vendor_elements', 'dd051122330203dd0400137400dd04001374ff')
     if "OK" not in hapd.request("UPDATE_BEACON"):
         raise Exception("UPDATE_BEACON failed")
     dev[1].scan_for_bss(apdev[0]['bssid'], freq="2412")
@@ -65,6 +72,31 @@ def test_ap_vendor_elements(dev, apdev):
     if "dd051122330203" not in bss['ie']:
         raise Exception("New vendor element not shown in scan results")
 
+def test_ap_element_parse(dev, apdev):
+    """Information element parsing - extra coverage"""
+    bssid = apdev[0]['bssid']
+    ssid = "test-wpa2-psk"
+    params = { 'ssid': ssid,
+               'vendor_elements': "380501020304059e009e009e009e009e009e00" }
+    hapd = hostapd.add_ap(apdev[0], params)
+    dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
+    bss = dev[0].get_bss(bssid)
+    if "38050102030405" not in bss['ie']:
+        raise Exception("Timeout element not shown in scan results")
+
+@remote_compatible
+def test_ap_element_parse_oom(dev, apdev):
+    """Information element parsing OOM"""
+    bssid = apdev[0]['bssid']
+    ssid = "test-wpa2-psk"
+    params = { 'ssid': ssid,
+               'vendor_elements': "dd0d506f9a0a00000600411c440028" }
+    hapd = hostapd.add_ap(apdev[0], params)
+    dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
+    with alloc_fail(dev[0], 1, "wpabuf_alloc;ieee802_11_vendor_ie_concat"):
+        bss = dev[0].get_bss(bssid)
+        logger.info(str(bss))
+
 def test_ap_country(dev, apdev):
     """WPA2-PSK AP setting country code and using 5 GHz band"""
     try:
@@ -77,14 +109,14 @@ def test_ap_country(dev, apdev):
         params['ieee80211d'] = '1'
         params['hw_mode'] = 'a'
         params['channel'] = '36'
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
         dev[0].connect(ssid, psk=passphrase, scan_freq="5180")
         hwsim_utils.test_connectivity(dev[0], hapd)
     finally:
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['iw', 'reg', 'set', '00'])
+        hostapd.cmd_execute(apdev[0], ['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
 def test_ap_acl_accept(dev, apdev):
@@ -93,7 +125,7 @@ def test_ap_acl_accept(dev, apdev):
     params = {}
     params['ssid'] = ssid
     params['accept_mac_file'] = "hostapd.macaddr"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
     dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
     dev[1].scan_for_bss(apdev[0]['bssid'], freq="2412")
@@ -114,7 +146,7 @@ def test_ap_acl_deny(dev, apdev):
     params = {}
     params['ssid'] = ssid
     params['deny_mac_file'] = "hostapd.macaddr"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
     dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412", wait_connect=False)
     dev[1].scan_for_bss(apdev[0]['bssid'], freq="2412")
@@ -123,6 +155,7 @@ def test_ap_acl_deny(dev, apdev):
     if ev is not None:
         raise Exception("Unexpected association")
 
+@remote_compatible
 def test_ap_wds_sta(dev, apdev):
     """WPA2-PSK AP with STA using 4addr mode"""
     ssid = "test-wpa2-psk"
@@ -130,28 +163,29 @@ def test_ap_wds_sta(dev, apdev):
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     params['wds_sta'] = "1"
     params['wds_bridge'] = "wds-br0"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     try:
-        subprocess.call(['brctl', 'addbr', 'wds-br0'])
-        subprocess.call(['brctl', 'setfd', 'wds-br0', '0'])
-        subprocess.call(['ip', 'link', 'set', 'dev', 'wds-br0', 'up'])
-        subprocess.call(['iw', dev[0].ifname, 'set', '4addr', 'on'])
+        dev[0].cmd_execute(['brctl', 'addbr', 'wds-br0'])
+        dev[0].cmd_execute(['brctl', 'setfd', 'wds-br0', '0'])
+        dev[0].cmd_execute(['ip', 'link', 'set', 'dev', 'wds-br0', 'up'])
+        dev[0].cmd_execute(['iw', dev[0].ifname, 'set', '4addr', 'on'])
         dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
         hwsim_utils.test_connectivity_iface(dev[0], hapd, "wds-br0",
                                             max_tries=15)
     finally:
-        subprocess.call(['iw', dev[0].ifname, 'set', '4addr', 'off'])
-        subprocess.call(['ip', 'link', 'set', 'dev', 'wds-br0', 'down'])
-        subprocess.call(['brctl', 'delbr', 'wds-br0'])
+        dev[0].cmd_execute(['iw', dev[0].ifname, 'set', '4addr', 'off'])
+        dev[0].cmd_execute(['ip', 'link', 'set', 'dev', 'wds-br0', 'down'])
+        dev[0].cmd_execute(['brctl', 'delbr', 'wds-br0'])
 
+@remote_compatible
 def test_ap_inactivity_poll(dev, apdev):
     """AP using inactivity poll"""
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     params['ap_max_inactivity'] = "1"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     hapd.set("ext_mgmt_frame_handling", "1")
     dev[0].request("DISCONNECT")
@@ -163,6 +197,7 @@ def test_ap_inactivity_poll(dev, apdev):
     if ev is None:
         raise Exception("STA disconnection on inactivity was not reported")
 
+@remote_compatible
 def test_ap_inactivity_disconnect(dev, apdev):
     """AP using inactivity disconnect"""
     ssid = "test-wpa2-psk"
@@ -170,7 +205,7 @@ def test_ap_inactivity_disconnect(dev, apdev):
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     params['ap_max_inactivity'] = "1"
     params['skip_inactivity_poll'] = "1"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     hapd.set("ext_mgmt_frame_handling", "1")
     dev[0].request("DISCONNECT")
@@ -182,22 +217,24 @@ def test_ap_inactivity_disconnect(dev, apdev):
     if ev is None:
         raise Exception("STA disconnection on inactivity was not reported")
 
+@remote_compatible
 def test_ap_basic_rates(dev, apdev):
     """Open AP with lots of basic rates"""
     ssid = "basic rates"
     params = {}
     params['ssid'] = ssid
     params['basic_rates'] = "10 20 55 110 60 90 120 180 240 360 480 540"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
 
+@remote_compatible
 def test_ap_short_preamble(dev, apdev):
     """Open AP with short preamble"""
     ssid = "short preamble"
     params = {}
     params['ssid'] = ssid
     params['preamble'] = "1"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
 
 def test_ap_spectrum_management_required(dev, apdev):
@@ -213,22 +250,23 @@ def test_ap_spectrum_management_required(dev, apdev):
     params['spectrum_mgmt_required'] = "1"
     try:
         hapd = None
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
         dev[0].connect(ssid, key_mgmt="NONE", scan_freq="5180")
     finally:
         dev[0].request("DISCONNECT")
         if hapd:
             hapd.request("DISABLE")
-        subprocess.call(['iw', 'reg', 'set', '00'])
+        hostapd.cmd_execute(apdev[0], ['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
+@remote_compatible
 def test_ap_max_listen_interval(dev, apdev):
     """Open AP with maximum listen interval limit"""
     ssid = "listen"
     params = {}
     params['ssid'] = ssid
     params['max_listen_interval'] = "1"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412", wait_connect=False)
     ev = dev[0].wait_event(["CTRL-EVENT-ASSOC-REJECT"])
     if ev is None:
@@ -236,19 +274,50 @@ def test_ap_max_listen_interval(dev, apdev):
     if "status_code=51" not in ev:
         raise Exception("Unexpected ASSOC-REJECT reason")
 
+@remote_compatible
 def test_ap_max_num_sta(dev, apdev):
     """Open AP with maximum STA count"""
     ssid = "max"
     params = {}
     params['ssid'] = ssid
     params['max_num_sta'] = "1"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[1].connect(ssid, key_mgmt="NONE", scan_freq="2412")
     dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412", wait_connect=False)
     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
     if ev is not None:
         raise Exception("Unexpected association")
 
+def test_ap_max_num_sta_no_probe_resp(dev, apdev, params):
+    """Maximum STA count and limit on Probe Response frames"""
+    logdir = params['logdir']
+    dev[0].flush_scan_cache()
+    ssid = "max"
+    params = {}
+    params['ssid'] = ssid
+    params['beacon_int'] = "2000"
+    params['max_num_sta'] = "1"
+    params['no_probe_resp_if_max_sta'] = "1"
+    hostapd.add_ap(apdev[0], params)
+    dev[1].connect(ssid, key_mgmt="NONE", scan_freq="2412")
+    dev[0].scan(freq=2412, type="ONLY")
+    dev[0].scan(freq=2412, type="ONLY")
+    seen = dev[0].get_bss(apdev[0]['bssid']) != None
+    dev[1].scan(freq=2412, type="ONLY")
+    if seen:
+        out = run_tshark(os.path.join(logdir, "hwsim0.pcapng"),
+                         "wlan.fc.type_subtype == 5", ["wlan.da" ])
+        if out:
+            if dev[0].own_addr() not in out:
+                # Discovery happened through Beacon frame reception. That's not
+                # an error case.
+                seen = False
+            if dev[1].own_addr() not in out:
+                raise Exception("No Probe Response frames to dev[1] seen")
+        if seen:
+            raise Exception("AP found unexpectedly")
+
+@remote_compatible
 def test_ap_tx_queue_params(dev, apdev):
     """Open AP with TX queue params set"""
     ssid = "tx"
@@ -262,6 +331,6 @@ def test_ap_tx_queue_params(dev, apdev):
     params['tx_queue_data1_cwmin'] = "7"
     params['tx_queue_data1_cwmax'] = "1023"
     params['tx_queue_data1_burst'] = "2"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
index 62306b5..fa47e20 100644 (file)
@@ -4,27 +4,29 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import time
-import subprocess
 import logging
 logger = logging.getLogger()
 
 import hwsim_utils
 import hostapd
+from utils import alloc_fail, fail_test, wait_fail_trigger
 from wlantest import Wlantest
 from wpasupplicant import WpaSupplicant
-from test_ap_eap import eap_connect
 
+@remote_compatible
 def test_ap_pmf_required(dev, apdev):
     """WPA2-PSK AP with PMF required"""
     ssid = "test-pmf-required"
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
+    params["ieee80211w"] = "2"
+    hapd = hostapd.add_ap(apdev[0], params)
+    Wlantest.setup(hapd)
     wt = Wlantest()
     wt.flush()
     wt.add_passphrase("12345678")
-    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
-    params["wpa_key_mgmt"] = "WPA-PSK-SHA256";
-    params["ieee80211w"] = "2";
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     key_mgmt = hapd.get_config()['key_mgmt']
     if key_mgmt.split(' ')[0] != "WPA-PSK-SHA256":
         raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
@@ -38,7 +40,6 @@ def test_ap_pmf_required(dev, apdev):
                    key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
                    scan_freq="2412")
     hwsim_utils.test_connectivity(dev[1], hapd)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
     hapd.request("SA_QUERY " + dev[0].p2p_interface_addr())
     hapd.request("SA_QUERY " + dev[1].p2p_interface_addr())
     wt.require_ap_pmf_mandatory(apdev[0]['bssid'])
@@ -52,16 +53,18 @@ def test_ap_pmf_required(dev, apdev):
                           dev[1].p2p_interface_addr()) < 1:
         raise Exception("STA did not reply to SA Query")
 
+@remote_compatible
 def test_ap_pmf_optional(dev, apdev):
     """WPA2-PSK AP with PMF optional"""
     ssid = "test-pmf-optional"
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    params["wpa_key_mgmt"] = "WPA-PSK"
+    params["ieee80211w"] = "1"
+    hapd = hostapd.add_ap(apdev[0], params)
+    Wlantest.setup(hapd)
     wt = Wlantest()
     wt.flush()
     wt.add_passphrase("12345678")
-    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
-    params["wpa_key_mgmt"] = "WPA-PSK";
-    params["ieee80211w"] = "1";
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     dev[0].connect(ssid, psk="12345678", ieee80211w="1",
                    key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
                    scan_freq="2412")
@@ -74,16 +77,18 @@ def test_ap_pmf_optional(dev, apdev):
     wt.require_sta_pmf(apdev[0]['bssid'], dev[0].p2p_interface_addr())
     wt.require_sta_pmf_mandatory(apdev[0]['bssid'], dev[1].p2p_interface_addr())
 
+@remote_compatible
 def test_ap_pmf_optional_2akm(dev, apdev):
     """WPA2-PSK AP with PMF optional (2 AKMs)"""
     ssid = "test-pmf-optional-2akm"
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    params["wpa_key_mgmt"] = "WPA-PSK WPA-PSK-SHA256"
+    params["ieee80211w"] = "1"
+    hapd = hostapd.add_ap(apdev[0], params)
+    Wlantest.setup(hapd)
     wt = Wlantest()
     wt.flush()
     wt.add_passphrase("12345678")
-    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
-    params["wpa_key_mgmt"] = "WPA-PSK WPA-PSK-SHA256";
-    params["ieee80211w"] = "1";
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     dev[0].connect(ssid, psk="12345678", ieee80211w="1",
                    key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
                    scan_freq="2412")
@@ -100,14 +105,16 @@ def test_ap_pmf_optional_2akm(dev, apdev):
     wt.require_sta_key_mgmt(apdev[0]['bssid'], dev[1].p2p_interface_addr(),
                             "PSK-SHA256")
 
+@remote_compatible
 def test_ap_pmf_negative(dev, apdev):
     """WPA2-PSK AP without PMF (negative test)"""
     ssid = "test-pmf-negative"
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    hapd = hostapd.add_ap(apdev[0], params)
+    Wlantest.setup(hapd)
     wt = Wlantest()
     wt.flush()
     wt.add_passphrase("12345678")
-    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     dev[0].connect(ssid, psk="12345678", ieee80211w="1",
                    key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
                    scan_freq="2412")
@@ -122,16 +129,18 @@ def test_ap_pmf_negative(dev, apdev):
         logger.debug("Ignore expected exception: " + str(e))
     wt.require_ap_no_pmf(apdev[0]['bssid'])
 
+@remote_compatible
 def test_ap_pmf_assoc_comeback(dev, apdev):
     """WPA2-PSK AP with PMF association comeback"""
     ssid = "assoc-comeback"
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
+    params["ieee80211w"] = "2"
+    hapd = hostapd.add_ap(apdev[0], params)
+    Wlantest.setup(hapd)
     wt = Wlantest()
     wt.flush()
     wt.add_passphrase("12345678")
-    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
-    params["wpa_key_mgmt"] = "WPA-PSK-SHA256";
-    params["ieee80211w"] = "2";
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     dev[0].connect(ssid, psk="12345678", ieee80211w="1",
                    key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
                    scan_freq="2412")
@@ -145,16 +154,18 @@ def test_ap_pmf_assoc_comeback(dev, apdev):
                           dev[0].p2p_interface_addr()) < 1:
         raise Exception("AP did not use association comeback request")
 
+@remote_compatible
 def test_ap_pmf_assoc_comeback2(dev, apdev):
     """WPA2-PSK AP with PMF association comeback (using DROP_SA)"""
     ssid = "assoc-comeback"
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    params["wpa_key_mgmt"] = "WPA-PSK"
+    params["ieee80211w"] = "1"
+    hapd = hostapd.add_ap(apdev[0], params)
+    Wlantest.setup(hapd)
     wt = Wlantest()
     wt.flush()
     wt.add_passphrase("12345678")
-    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
-    params["wpa_key_mgmt"] = "WPA-PSK";
-    params["ieee80211w"] = "1";
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     dev[0].connect(ssid, psk="12345678", ieee80211w="2",
                    key_mgmt="WPA-PSK", proto="WPA2", scan_freq="2412")
     if "OK" not in dev[0].request("DROP_SA"):
@@ -165,14 +176,7 @@ def test_ap_pmf_assoc_comeback2(dev, apdev):
                           dev[0].p2p_interface_addr()) < 1:
         raise Exception("AP did not use reassociation comeback request")
 
-def test_ap_pmf_sta_sa_query(dev, apdev):
-    """WPA2-PSK AP with station using SA Query"""
-    ssid = "assoc-comeback"
-    addr = dev[0].own_addr()
-    wt = Wlantest()
-    wt.flush()
-    wt.add_passphrase("12345678")
-
+def start_wpas_ap(ssid):
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5", drv_params="use_monitor=1")
     id = wpas.add_network()
@@ -185,20 +189,40 @@ def test_ap_pmf_sta_sa_query(dev, apdev):
     wpas.set_network(id, "pairwise", "CCMP")
     wpas.set_network(id, "group", "CCMP")
     wpas.set_network(id, "frequency", "2412")
+    wpas.set_network(id, "scan_freq", "2412")
     wpas.connect_network(id)
+    wpas.dump_monitor()
+    return wpas
+
+def test_ap_pmf_sta_sa_query(dev, apdev):
+    """WPA2-PSK AP with station using SA Query"""
+    ssid = "assoc-comeback"
+    addr = dev[0].own_addr()
+
+    wpas = start_wpas_ap(ssid)
     bssid = wpas.own_addr()
 
+    Wlantest.setup(wpas)
+    wt = Wlantest()
+    wt.flush()
+    wt.add_passphrase("12345678")
+
     dev[0].connect(ssid, psk="12345678", ieee80211w="1",
                    key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
                    scan_freq="2412")
+    wpas.dump_monitor()
     wpas.request("DEAUTHENTICATE " + addr + " test=0")
+    wpas.dump_monitor()
     wpas.request("DISASSOCIATE " + addr + " test=0")
+    wpas.dump_monitor()
     ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
     if ev is not None:
         raise Exception("Unexpected disconnection")
 
     wpas.request("DEAUTHENTICATE " + addr + " reason=6 test=0")
+    wpas.dump_monitor()
     wpas.request("DISASSOCIATE " + addr + " reason=7 test=0")
+    wpas.dump_monitor()
     ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
     if ev is not None:
         raise Exception("Unexpected disconnection")
@@ -206,66 +230,52 @@ def test_ap_pmf_sta_sa_query(dev, apdev):
         raise Exception("STA did not send SA Query")
     if wt.get_sta_counter("valid_saqueryresp_rx", bssid, addr) < 1:
         raise Exception("AP did not reply to SA Query")
+    wpas.dump_monitor()
 
 def test_ap_pmf_sta_sa_query_no_response(dev, apdev):
     """WPA2-PSK AP with station using SA Query and getting no response"""
     ssid = "assoc-comeback"
     addr = dev[0].own_addr()
 
-    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
-    wpas.interface_add("wlan5", drv_params="use_monitor=1")
-    id = wpas.add_network()
-    wpas.set_network(id, "mode", "2")
-    wpas.set_network_quoted(id, "ssid", ssid)
-    wpas.set_network(id, "proto", "WPA2")
-    wpas.set_network(id, "key_mgmt", "WPA-PSK-SHA256")
-    wpas.set_network(id, "ieee80211w", "2")
-    wpas.set_network_quoted(id, "psk", "12345678")
-    wpas.set_network(id, "pairwise", "CCMP")
-    wpas.set_network(id, "group", "CCMP")
-    wpas.set_network(id, "frequency", "2412")
-    wpas.connect_network(id)
+    wpas = start_wpas_ap(ssid)
     bssid = wpas.own_addr()
 
     dev[0].connect(ssid, psk="12345678", ieee80211w="1",
                    key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
                    scan_freq="2412")
+    wpas.dump_monitor()
     wpas.request("DEAUTHENTICATE " + addr + " test=0")
+    wpas.dump_monitor()
     wpas.request("DISASSOCIATE " + addr + " test=0")
+    wpas.dump_monitor()
     ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
     if ev is not None:
         raise Exception("Unexpected disconnection")
 
     wpas.request("SET ext_mgmt_frame_handling 1")
     wpas.request("DEAUTHENTICATE " + addr + " reason=6 test=0")
+    wpas.dump_monitor()
     wpas.request("DISASSOCIATE " + addr + " reason=7 test=0")
+    wpas.dump_monitor()
     dev[0].wait_disconnected()
+    wpas.dump_monitor()
     wpas.request("SET ext_mgmt_frame_handling 0")
     dev[0].wait_connected()
+    wpas.dump_monitor()
 
 def test_ap_pmf_sta_unprot_deauth_burst(dev, apdev):
     """WPA2-PSK AP with station receiving burst of unprotected Deauthentication frames"""
     ssid = "deauth-attack"
     addr = dev[0].own_addr()
+
+    wpas = start_wpas_ap(ssid)
+    bssid = wpas.own_addr()
+
+    Wlantest.setup(wpas)
     wt = Wlantest()
     wt.flush()
     wt.add_passphrase("12345678")
 
-    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
-    wpas.interface_add("wlan5", drv_params="use_monitor=1")
-    id = wpas.add_network()
-    wpas.set_network(id, "mode", "2")
-    wpas.set_network_quoted(id, "ssid", ssid)
-    wpas.set_network(id, "proto", "WPA2")
-    wpas.set_network(id, "key_mgmt", "WPA-PSK-SHA256")
-    wpas.set_network(id, "ieee80211w", "2")
-    wpas.set_network_quoted(id, "psk", "12345678")
-    wpas.set_network(id, "pairwise", "CCMP")
-    wpas.set_network(id, "group", "CCMP")
-    wpas.set_network(id, "frequency", "2412")
-    wpas.connect_network(id)
-    bssid = wpas.own_addr()
-
     dev[0].connect(ssid, psk="12345678", ieee80211w="1",
                    key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
                    scan_freq="2412")
@@ -297,13 +307,43 @@ def test_ap_pmf_sta_unprot_deauth_burst(dev, apdev):
     if num_req != 2 or num_resp != 2:
         raise Exception("Unexpected number of SA Query procedures (req=%d resp=%d)" % (num_req, num_resp))
 
+def test_ap_pmf_sta_sa_query_oom(dev, apdev):
+    """WPA2-PSK AP with station using SA Query (OOM)"""
+    ssid = "assoc-comeback"
+    addr = dev[0].own_addr()
+    wpas = start_wpas_ap(ssid)
+    dev[0].connect(ssid, psk="12345678", ieee80211w="1",
+                   key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
+                   scan_freq="2412")
+    with alloc_fail(dev[0], 1, "=sme_sa_query_timer"):
+        wpas.request("DEAUTHENTICATE " + addr + " reason=6 test=0")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].request("DISCONNECT")
+    wpas.request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+def test_ap_pmf_sta_sa_query_local_failure(dev, apdev):
+    """WPA2-PSK AP with station using SA Query (local failure)"""
+    ssid = "assoc-comeback"
+    addr = dev[0].own_addr()
+    wpas = start_wpas_ap(ssid)
+    dev[0].connect(ssid, psk="12345678", ieee80211w="1",
+                   key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
+                   scan_freq="2412")
+    with fail_test(dev[0], 1, "os_get_random;sme_sa_query_timer"):
+        wpas.request("DEAUTHENTICATE " + addr + " reason=6 test=0")
+        wait_fail_trigger(dev[0], "GET_FAIL")
+    dev[0].request("DISCONNECT")
+    wpas.request("DISCONNECT")
+    dev[0].wait_disconnected()
+
 def test_ap_pmf_required_eap(dev, apdev):
     """WPA2-EAP AP with PMF required"""
     ssid = "test-pmf-required-eap"
     params = hostapd.wpa2_eap_params(ssid=ssid)
-    params["wpa_key_mgmt"] = "WPA-EAP-SHA256";
-    params["ieee80211w"] = "2";
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    params["wpa_key_mgmt"] = "WPA-EAP-SHA256"
+    params["ieee80211w"] = "2"
+    hapd = hostapd.add_ap(apdev[0], params)
     key_mgmt = hapd.get_config()['key_mgmt']
     if key_mgmt.split(' ')[0] != "WPA-EAP-SHA256":
         raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
@@ -319,8 +359,8 @@ def test_ap_pmf_required_eap(dev, apdev):
 def test_ap_pmf_optional_eap(dev, apdev):
     """WPA2EAP AP with PMF optional"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    params["ieee80211w"] = "1";
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    params["ieee80211w"] = "1"
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
                    identity="pap user", anonymous_identity="ttls",
                    password="password",
@@ -332,16 +372,18 @@ def test_ap_pmf_optional_eap(dev, apdev):
                    ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
                    ieee80211w="2", scan_freq="2412")
 
+@remote_compatible
 def test_ap_pmf_required_sha1(dev, apdev):
     """WPA2-PSK AP with PMF required with SHA1 AKM"""
     ssid = "test-pmf-required-sha1"
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    params["wpa_key_mgmt"] = "WPA-PSK"
+    params["ieee80211w"] = "2"
+    hapd = hostapd.add_ap(apdev[0], params)
+    Wlantest.setup(hapd)
     wt = Wlantest()
     wt.flush()
     wt.add_passphrase("12345678")
-    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
-    params["wpa_key_mgmt"] = "WPA-PSK";
-    params["ieee80211w"] = "2";
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
     key_mgmt = hapd.get_config()['key_mgmt']
     if key_mgmt.split(' ')[0] != "WPA-PSK":
         raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
@@ -351,6 +393,7 @@ def test_ap_pmf_required_sha1(dev, apdev):
         raise Exception("Scan results missing RSN element info")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_ap_pmf_toggle(dev, apdev):
     """WPA2-PSK AP with PMF optional and changing PMF on reassociation"""
     try:
@@ -360,15 +403,16 @@ def test_ap_pmf_toggle(dev, apdev):
 
 def _test_ap_pmf_toggle(dev, apdev):
     ssid = "test-pmf-optional"
-    wt = Wlantest()
-    wt.flush()
-    wt.add_passphrase("12345678")
     params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
-    params["wpa_key_mgmt"] = "WPA-PSK";
-    params["ieee80211w"] = "1";
+    params["wpa_key_mgmt"] = "WPA-PSK"
+    params["ieee80211w"] = "1"
     params["assoc_sa_query_max_timeout"] = "1"
     params["assoc_sa_query_retry_timeout"] = "1"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
+    Wlantest.setup(hapd)
+    wt = Wlantest()
+    wt.flush()
+    wt.add_passphrase("12345678")
     bssid = apdev[0]['bssid']
     addr = dev[0].own_addr()
     dev[0].request("SET reassoc_same_bss_optim 1")
@@ -388,9 +432,8 @@ def _test_ap_pmf_toggle(dev, apdev):
     sta = hapd.get_sta(addr)
     if '[MFP]' in sta['flags']:
         raise Exception("MFP flag unexpectedly present for STA")
-    cmd = subprocess.Popen(['iw', 'dev', apdev[0]['ifname'], 'station', 'get',
-                            addr], stdout=subprocess.PIPE)
-    (data,err) = cmd.communicate()
+    err, data = hapd.cmd_execute(['iw', 'dev', apdev[0]['ifname'], 'station',
+                                  'get', addr])
     if "yes" in [l for l in data.splitlines() if "MFP" in l][0]:
         raise Exception("Kernel STA entry had MFP enabled")
 
@@ -401,8 +444,28 @@ def _test_ap_pmf_toggle(dev, apdev):
     sta = hapd.get_sta(addr)
     if '[MFP]' not in sta['flags']:
         raise Exception("MFP flag not present for STA")
-    cmd = subprocess.Popen(['iw', 'dev', apdev[0]['ifname'], 'station', 'get',
-                            addr], stdout=subprocess.PIPE)
-    (data,err) = cmd.communicate()
+    err, data = hapd.cmd_execute(['iw', 'dev', apdev[0]['ifname'], 'station',
+                                  'get', addr])
     if "yes" not in [l for l in data.splitlines() if "MFP" in l][0]:
         raise Exception("Kernel STA entry did not have MFP enabled")
+
+@remote_compatible
+def test_ap_pmf_required_sta_no_pmf(dev, apdev):
+    """WPA2-PSK AP with PMF required and PMF disabled on STA"""
+    ssid = "test-pmf-required"
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
+    params["ieee80211w"] = "2"
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    # Disable PMF on the station and try to connect
+    dev[0].connect(ssid, psk="12345678", ieee80211w="0",
+                   key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
+                   scan_freq="2412", wait_connect=False)
+    ev = dev[0].wait_event(["CTRL-EVENT-NETWORK-NOT-FOUND",
+                            "CTRL-EVENT-ASSOC-REJECT"], timeout=2)
+    if ev is None:
+        raise Exception("No connection result")
+    if "CTRL-EVENT-ASSOC-REJECT" in ev:
+        raise Exception("Tried to connect to PMF required AP without PMF enabled")
+    dev[0].request("REMOVE_NETWORK all")
index 281d54b..2ca4279 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import binascii
 from Crypto.Cipher import AES
 import hashlib
@@ -27,6 +28,7 @@ def check_mib(dev, vals):
         if mib[v[0]] != v[1]:
             raise Exception("Unexpected {} = {} (expected {})".format(v[0], mib[v[0]], v[1]))
 
+@remote_compatible
 def test_ap_wpa2_psk(dev, apdev):
     """WPA2-PSK AP with PSK instead of passphrase"""
     ssid = "test-wpa2-psk"
@@ -34,7 +36,7 @@ def test_ap_wpa2_psk(dev, apdev):
     psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
     params = hostapd.wpa2_params(ssid=ssid)
     params['wpa_psk'] = psk
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     key_mgmt = hapd.get_config()['key_mgmt']
     if key_mgmt.split(' ')[0] != "WPA-PSK":
         raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
@@ -55,7 +57,7 @@ def test_ap_wpa2_psk_file(dev, apdev):
     psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     params['wpa_psk_file'] = 'hostapd.wpa_psk'
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[1].connect(ssid, psk="very secret", scan_freq="2412", wait_connect=False)
     dev[2].connect(ssid, raw_psk=psk, scan_freq="2412")
     dev[2].request("REMOVE_NETWORK all")
@@ -68,6 +70,7 @@ def test_ap_wpa2_psk_file(dev, apdev):
         raise Exception("Timed out while waiting for failure report")
     dev[1].request("REMOVE_NETWORK all")
 
+@remote_compatible
 def test_ap_wpa2_psk_mem(dev, apdev):
     """WPA2-PSK AP with passphrase only in memory"""
     try:
@@ -82,7 +85,7 @@ def _test_ap_wpa2_psk_mem(dev, apdev):
     psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
     params = hostapd.wpa2_params(ssid=ssid)
     params['wpa_psk'] = psk
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect(ssid, mem_only_psk="1", scan_freq="2412", wait_connect=False)
     dev[0].request("SCAN_INTERVAL 1")
@@ -102,38 +105,41 @@ def _test_ap_wpa2_psk_mem(dev, apdev):
     dev[1].request("CTRL-RSP-PSK_PASSPHRASE-" + id + ':' + psk)
     dev[1].wait_connected(timeout=10)
 
+@remote_compatible
 def test_ap_wpa2_ptk_rekey(dev, apdev):
     """WPA2-PSK AP and PTK rekey enforced by station"""
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, wpa_ptk_rekey="1", scan_freq="2412")
     ev = dev[0].wait_event(["WPA: Key negotiation completed"])
     if ev is None:
         raise Exception("PTK rekey timed out")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_ap_wpa2_ptk_rekey_ap(dev, apdev):
     """WPA2-PSK AP and PTK rekey enforced by AP"""
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     params['wpa_ptk_rekey'] = '2'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     ev = dev[0].wait_event(["WPA: Key negotiation completed"])
     if ev is None:
         raise Exception("PTK rekey timed out")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_ap_wpa2_sha256_ptk_rekey(dev, apdev):
     """WPA2-PSK/SHA256 AKM AP and PTK rekey enforced by station"""
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, key_mgmt="WPA-PSK-SHA256",
                    wpa_ptk_rekey="1", scan_freq="2412")
     ev = dev[0].wait_event(["WPA: Key negotiation completed"])
@@ -143,6 +149,7 @@ def test_ap_wpa2_sha256_ptk_rekey(dev, apdev):
     check_mib(dev[0], [ ("dot11RSNAAuthenticationSuiteRequested", "00-0f-ac-6"),
                         ("dot11RSNAAuthenticationSuiteSelected", "00-0f-ac-6") ])
 
+@remote_compatible
 def test_ap_wpa2_sha256_ptk_rekey_ap(dev, apdev):
     """WPA2-PSK/SHA256 AKM AP and PTK rekey enforced by AP"""
     ssid = "test-wpa2-psk"
@@ -150,7 +157,7 @@ def test_ap_wpa2_sha256_ptk_rekey_ap(dev, apdev):
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
     params['wpa_ptk_rekey'] = '2'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, key_mgmt="WPA-PSK-SHA256",
                    scan_freq="2412")
     ev = dev[0].wait_event(["WPA: Key negotiation completed"])
@@ -160,13 +167,14 @@ def test_ap_wpa2_sha256_ptk_rekey_ap(dev, apdev):
     check_mib(dev[0], [ ("dot11RSNAAuthenticationSuiteRequested", "00-0f-ac-6"),
                         ("dot11RSNAAuthenticationSuiteSelected", "00-0f-ac-6") ])
 
+@remote_compatible
 def test_ap_wpa_ptk_rekey(dev, apdev):
     """WPA-PSK/TKIP AP and PTK rekey enforced by station"""
     skip_with_fips(dev[0])
     ssid = "test-wpa-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa_params(ssid=ssid, passphrase=passphrase)
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, wpa_ptk_rekey="1", scan_freq="2412")
     if "[WPA-PSK-TKIP]" not in dev[0].request("SCAN_RESULTS"):
         raise Exception("Scan results missing WPA element info")
@@ -175,6 +183,7 @@ def test_ap_wpa_ptk_rekey(dev, apdev):
         raise Exception("PTK rekey timed out")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_ap_wpa_ptk_rekey_ap(dev, apdev):
     """WPA-PSK/TKIP AP and PTK rekey enforced by AP"""
     skip_with_fips(dev[0])
@@ -182,20 +191,21 @@ def test_ap_wpa_ptk_rekey_ap(dev, apdev):
     passphrase = 'qwertyuiop'
     params = hostapd.wpa_params(ssid=ssid, passphrase=passphrase)
     params['wpa_ptk_rekey'] = '2'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     ev = dev[0].wait_event(["WPA: Key negotiation completed"], timeout=10)
     if ev is None:
         raise Exception("PTK rekey timed out")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_ap_wpa_ccmp(dev, apdev):
     """WPA-PSK/CCMP"""
     ssid = "test-wpa-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa_params(ssid=ssid, passphrase=passphrase)
     params['wpa_pairwise'] = "CCMP"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
     check_mib(dev[0], [ ("dot11RSNAConfigGroupCipherSize", "128"),
@@ -224,7 +234,7 @@ def test_ap_wpa2_psk_file(dev, apdev):
 
     try:
         # missing PSK file
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params, no_enable=True)
+        hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
         if "FAIL" not in hapd.request("ENABLE"):
             raise Exception("Unexpected ENABLE success")
         hapd.request("DISABLE")
@@ -270,30 +280,33 @@ def test_ap_wpa2_psk_file(dev, apdev):
         except:
             pass
 
+@remote_compatible
 def test_ap_wpa2_psk_wildcard_ssid(dev, apdev):
     """WPA2-PSK AP and wildcard SSID configuration"""
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
     psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect("", bssid=apdev[0]['bssid'], psk=passphrase,
                    scan_freq="2412")
     dev[1].connect("", bssid=apdev[0]['bssid'], raw_psk=psk, scan_freq="2412")
 
+@remote_compatible
 def test_ap_wpa2_gtk_rekey(dev, apdev):
     """WPA2-PSK AP and GTK rekey enforced by AP"""
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     params['wpa_group_rekey'] = '1'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     ev = dev[0].wait_event(["WPA: Group rekeying completed"], timeout=2)
     if ev is None:
         raise Exception("GTK rekey timed out")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_ap_wpa_gtk_rekey(dev, apdev):
     """WPA-PSK/TKIP AP and GTK rekey enforced by AP"""
     skip_with_fips(dev[0])
@@ -301,13 +314,14 @@ def test_ap_wpa_gtk_rekey(dev, apdev):
     passphrase = 'qwertyuiop'
     params = hostapd.wpa_params(ssid=ssid, passphrase=passphrase)
     params['wpa_group_rekey'] = '1'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     ev = dev[0].wait_event(["WPA: Group rekeying completed"], timeout=2)
     if ev is None:
         raise Exception("GTK rekey timed out")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_ap_wpa2_gmk_rekey(dev, apdev):
     """WPA2-PSK AP and GMK and GTK rekey enforced by AP"""
     ssid = "test-wpa2-psk"
@@ -315,7 +329,7 @@ def test_ap_wpa2_gmk_rekey(dev, apdev):
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     params['wpa_group_rekey'] = '1'
     params['wpa_gmk_rekey'] = '2'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     for i in range(0, 3):
         ev = dev[0].wait_event(["WPA: Group rekeying completed"], timeout=2)
@@ -323,13 +337,14 @@ def test_ap_wpa2_gmk_rekey(dev, apdev):
             raise Exception("GTK rekey timed out")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_ap_wpa2_strict_rekey(dev, apdev):
     """WPA2-PSK AP and strict GTK rekey enforced by AP"""
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     params['wpa_strict_rekey'] = '1'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     dev[1].connect(ssid, psk=passphrase, scan_freq="2412")
     dev[1].request("DISCONNECT")
@@ -338,31 +353,30 @@ def test_ap_wpa2_strict_rekey(dev, apdev):
         raise Exception("GTK rekey timed out")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_ap_wpa2_bridge_fdb(dev, apdev):
     """Bridge FDB entry removal"""
+    hapd = None
     try:
         ssid = "test-wpa2-psk"
         passphrase = "12345678"
         params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
         params['bridge'] = 'ap-br0'
-        hostapd.add_ap(apdev[0]['ifname'], params)
-        subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
-        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
+        hapd = hostapd.add_ap(apdev[0], params)
+        hapd.cmd_execute(['brctl', 'setfd', 'ap-br0', '0'])
+        hapd.cmd_execute(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
         dev[0].connect(ssid, psk=passphrase, scan_freq="2412",
                        bssid=apdev[0]['bssid'])
         dev[1].connect(ssid, psk=passphrase, scan_freq="2412",
                        bssid=apdev[0]['bssid'])
         addr0 = dev[0].p2p_interface_addr()
         hwsim_utils.test_connectivity_sta(dev[0], dev[1])
-        cmd = subprocess.Popen(['brctl', 'showmacs', 'ap-br0'],
-                               stdout=subprocess.PIPE)
-        macs1 = cmd.stdout.read()
+        err, macs1 = hapd.cmd_execute(['brctl', 'showmacs', 'ap-br0'])
+        hapd.cmd_execute(['brctl', 'setageing', 'ap-br0', '1'])
         dev[0].request("DISCONNECT")
         dev[1].request("DISCONNECT")
         time.sleep(1)
-        cmd = subprocess.Popen(['brctl', 'showmacs', 'ap-br0'],
-                               stdout=subprocess.PIPE)
-        macs2 = cmd.stdout.read()
+        err, macs2 = hapd.cmd_execute(['brctl', 'showmacs', 'ap-br0'])
 
         addr1 = dev[1].p2p_interface_addr()
         if addr0 not in macs1 or addr1 not in macs1:
@@ -370,9 +384,11 @@ def test_ap_wpa2_bridge_fdb(dev, apdev):
         if addr0 in macs2 or addr1 in macs2:
             raise Exception("Bridge FDB entry was not removed")
     finally:
-        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'])
-        subprocess.call(['brctl', 'delbr', 'ap-br0'])
+        hostapd.cmd_execute(apdev[0], ['ip', 'link', 'set', 'dev', 'ap-br0',
+                                       'down'])
+        hostapd.cmd_execute(apdev[0], ['brctl', 'delbr', 'ap-br0'])
 
+@remote_compatible
 def test_ap_wpa2_already_in_bridge(dev, apdev):
     """hostapd behavior with interface already in bridge"""
     ifname = apdev[0]['ifname']
@@ -380,22 +396,25 @@ def test_ap_wpa2_already_in_bridge(dev, apdev):
     try:
         ssid = "test-wpa2-psk"
         passphrase = "12345678"
-        subprocess.call(['brctl', 'addbr', br_ifname])
-        subprocess.call(['brctl', 'setfd', br_ifname, '0'])
-        subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'up'])
-        subprocess.call(['iw', ifname, 'set', 'type', '__ap'])
-        subprocess.call(['brctl', 'addif', br_ifname, ifname])
+        hostapd.cmd_execute(apdev[0], ['brctl', 'addbr', br_ifname])
+        hostapd.cmd_execute(apdev[0], ['brctl', 'setfd', br_ifname, '0'])
+        hostapd.cmd_execute(apdev[0], ['ip', 'link', 'set', 'dev', br_ifname,
+                                       'up'])
+        hostapd.cmd_execute(apdev[0], ['iw', ifname, 'set', 'type', '__ap'])
+        hostapd.cmd_execute(apdev[0], ['brctl', 'addif', br_ifname, ifname])
         params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
-        hapd = hostapd.add_ap(ifname, params)
+        hapd = hostapd.add_ap(apdev[0], params)
         if hapd.get_driver_status_field('brname') != br_ifname:
             raise Exception("Bridge name not identified correctly")
         dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     finally:
-        subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'down'])
-        subprocess.call(['brctl', 'delif', br_ifname, ifname])
-        subprocess.call(['iw', ifname, 'set', 'type', 'station'])
-        subprocess.call(['brctl', 'delbr', br_ifname])
+        hostapd.cmd_execute(apdev[0], ['ip', 'link', 'set', 'dev', br_ifname,
+                                       'down'])
+        hostapd.cmd_execute(apdev[0], ['brctl', 'delif', br_ifname, ifname])
+        hostapd.cmd_execute(apdev[0], ['iw', ifname, 'set', 'type', 'station'])
+        hostapd.cmd_execute(apdev[0], ['brctl', 'delbr', br_ifname])
 
+@remote_compatible
 def test_ap_wpa2_in_different_bridge(dev, apdev):
     """hostapd behavior with interface in different bridge"""
     ifname = apdev[0]['ifname']
@@ -403,17 +422,19 @@ def test_ap_wpa2_in_different_bridge(dev, apdev):
     try:
         ssid = "test-wpa2-psk"
         passphrase = "12345678"
-        subprocess.call(['brctl', 'addbr', br_ifname])
-        subprocess.call(['brctl', 'setfd', br_ifname, '0'])
-        subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'up'])
-        subprocess.call(['iw', ifname, 'set', 'type', '__ap'])
-        subprocess.call(['brctl', 'addif', br_ifname, ifname])
+        hostapd.cmd_execute(apdev[0], ['brctl', 'addbr', br_ifname])
+        hostapd.cmd_execute(apdev[0], ['brctl', 'setfd', br_ifname, '0'])
+        hostapd.cmd_execute(apdev[0], ['ip', 'link', 'set', 'dev', br_ifname,
+                                       'up'])
+        hostapd.cmd_execute(apdev[0], ['iw', ifname, 'set', 'type', '__ap'])
+        hostapd.cmd_execute(apdev[0], ['brctl', 'addif', br_ifname, ifname])
         time.sleep(0.5)
         params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
         params['bridge'] = 'ap-br0'
-        hapd = hostapd.add_ap(ifname, params)
-        subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
-        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
+        hapd = hostapd.add_ap(apdev[0], params)
+        hostapd.cmd_execute(apdev[0], ['brctl', 'setfd', 'ap-br0', '0'])
+        hostapd.cmd_execute(apdev[0], ['ip', 'link', 'set', 'dev', 'ap-br0',
+                                       'up'])
         brname = hapd.get_driver_status_field('brname')
         if brname != 'ap-br0':
             raise Exception("Incorrect bridge: " + brname)
@@ -426,11 +447,13 @@ def test_ap_wpa2_in_different_bridge(dev, apdev):
         dev[0].request("DISCONNECT")
         hapd.disable()
     finally:
-        subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'down'])
-        subprocess.call(['brctl', 'delif', br_ifname, ifname],
-                        stderr=open('/dev/null', 'w'))
-        subprocess.call(['brctl', 'delbr', br_ifname])
+        hostapd.cmd_execute(apdev[0], ['ip', 'link', 'set', 'dev', br_ifname,
+                                       'down'])
+        hostapd.cmd_execute(apdev[0], ['brctl', 'delif', br_ifname, ifname,
+                                       "2>", "/dev/null"], shell=True)
+        hostapd.cmd_execute(apdev[0], ['brctl', 'delbr', br_ifname])
 
+@remote_compatible
 def test_ap_wpa2_ext_add_to_bridge(dev, apdev):
     """hostapd behavior with interface added to bridge externally"""
     ifname = apdev[0]['ifname']
@@ -439,19 +462,21 @@ def test_ap_wpa2_ext_add_to_bridge(dev, apdev):
         ssid = "test-wpa2-psk"
         passphrase = "12345678"
         params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
-        hapd = hostapd.add_ap(ifname, params)
+        hapd = hostapd.add_ap(apdev[0], params)
 
-        subprocess.call(['brctl', 'addbr', br_ifname])
-        subprocess.call(['brctl', 'setfd', br_ifname, '0'])
-        subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'up'])
-        subprocess.call(['brctl', 'addif', br_ifname, ifname])
+        hostapd.cmd_execute(apdev[0], ['brctl', 'addbr', br_ifname])
+        hostapd.cmd_execute(apdev[0], ['brctl', 'setfd', br_ifname, '0'])
+        hostapd.cmd_execute(apdev[0], ['ip', 'link', 'set', 'dev', br_ifname,
+                                       'up'])
+        hostapd.cmd_execute(apdev[0], ['brctl', 'addif', br_ifname, ifname])
         dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
         if hapd.get_driver_status_field('brname') != br_ifname:
             raise Exception("Bridge name not identified correctly")
     finally:
-        subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'down'])
-        subprocess.call(['brctl', 'delif', br_ifname, ifname])
-        subprocess.call(['brctl', 'delbr', br_ifname])
+        hostapd.cmd_execute(apdev[0], ['ip', 'link', 'set', 'dev', br_ifname,
+                                       'down'])
+        hostapd.cmd_execute(apdev[0], ['brctl', 'delif', br_ifname, ifname])
+        hostapd.cmd_execute(apdev[0], ['brctl', 'delbr', br_ifname])
 
 def test_ap_wpa2_psk_ext(dev, apdev):
     """WPA2-PSK AP using external EAPOL I/O"""
@@ -461,7 +486,7 @@ def test_ap_wpa2_psk_ext(dev, apdev):
     psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
     params = hostapd.wpa2_params(ssid=ssid)
     params['wpa_psk'] = psk
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     hapd.request("SET ext_eapol_frame_io 1")
     dev[0].request("SET ext_eapol_frame_io 1")
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412", wait_connect=False)
@@ -485,6 +510,73 @@ def test_ap_wpa2_psk_ext(dev, apdev):
         if "OK" not in res:
             raise Exception("EAPOL_RX to hostapd failed")
 
+def test_ap_wpa2_psk_ext_retry_msg_3(dev, apdev):
+    """WPA2-PSK AP using external EAPOL I/O and retry for EAPOL-Key msg 3/4"""
+    bssid = apdev[0]['bssid']
+    ssid = "test-wpa2-psk"
+    passphrase = 'qwertyuiop'
+    psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
+    params = hostapd.wpa2_params(ssid=ssid)
+    params['wpa_psk'] = psk
+    hapd = hostapd.add_ap(apdev[0], params)
+    hapd.request("SET ext_eapol_frame_io 1")
+    dev[0].request("SET ext_eapol_frame_io 1")
+    dev[0].connect(ssid, psk=passphrase, scan_freq="2412", wait_connect=False)
+    addr = dev[0].p2p_interface_addr()
+
+    # EAPOL-Key msg 1/4
+    ev = hapd.wait_event(["EAPOL-TX"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on EAPOL-TX from hostapd")
+    res = dev[0].request("EAPOL_RX " + bssid + " " + ev.split(' ')[2])
+    if "OK" not in res:
+        raise Exception("EAPOL_RX to wpa_supplicant failed")
+
+    # EAPOL-Key msg 2/4
+    ev = dev[0].wait_event(["EAPOL-TX"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on EAPOL-TX from wpa_supplicant")
+    res = hapd.request("EAPOL_RX " + addr + " " + ev.split(' ')[2])
+    if "OK" not in res:
+        raise Exception("EAPOL_RX to hostapd failed")
+
+    # EAPOL-Key msg 3/4
+    ev = hapd.wait_event(["EAPOL-TX"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on EAPOL-TX from hostapd")
+    res = dev[0].request("EAPOL_RX " + bssid + " " + ev.split(' ')[2])
+    if "OK" not in res:
+        raise Exception("EAPOL_RX to wpa_supplicant failed")
+
+    # EAPOL-Key msg 4/4
+    ev = dev[0].wait_event(["EAPOL-TX"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on EAPOL-TX from wpa_supplicant")
+    # Do not send to the AP
+    dev[0].wait_connected(timeout=15)
+
+    # EAPOL-Key msg 3/4 (retry)
+    ev = hapd.wait_event(["EAPOL-TX"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on EAPOL-TX from hostapd")
+    res = dev[0].request("EAPOL_RX " + bssid + " " + ev.split(' ')[2])
+    if "OK" not in res:
+        raise Exception("EAPOL_RX to wpa_supplicant failed")
+
+    # EAPOL-Key msg 4/4
+    ev = dev[0].wait_event(["EAPOL-TX"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on EAPOL-TX from wpa_supplicant")
+    res = hapd.request("EAPOL_RX " + addr + " " + ev.split(' ')[2])
+    if "OK" not in res:
+        raise Exception("EAPOL_RX to hostapd failed")
+
+    ev = hapd.wait_event(["AP-STA-CONNECTED"], timeout=15)
+    if ev is None:
+        raise Exception("Timeout on AP-STA-CONNECTED from hostapd")
+
+    hwsim_utils.test_connectivity(dev[0], hapd)
+
 def parse_eapol(data):
     (version, type, length) = struct.unpack('>BBH', data[0:4])
     payload = data[4:]
@@ -626,7 +718,7 @@ def eapol_test(apdev, dev, wpa2=True):
     else:
         params = hostapd.wpa_params(ssid=ssid)
     params['wpa_psk'] = psk
-    hapd = hostapd.add_ap(apdev['ifname'], params)
+    hapd = hostapd.add_ap(apdev, params)
     hapd.request("SET ext_eapol_frame_io 1")
     dev.request("SET ext_eapol_frame_io 1")
     dev.connect(ssid, raw_psk=psk, scan_freq="2412", wait_connect=False)
@@ -638,6 +730,7 @@ def eapol_test(apdev, dev, wpa2=True):
     snonce = binascii.unhexlify('1111111111111111111111111111111111111111111111111111111111111111')
     return (bssid,ssid,hapd,snonce,pmk,addr,rsne)
 
+@remote_compatible
 def test_ap_wpa2_psk_ext_eapol(dev, apdev):
     """WPA2-PSK AP using external EAPOL supplicant"""
     (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
@@ -665,6 +758,7 @@ def test_ap_wpa2_psk_ext_eapol(dev, apdev):
     reply_eapol("4/4", hapd, addr, msg, 0x030a, None, None, kck)
     hapd_connected(hapd)
 
+@remote_compatible
 def test_ap_wpa2_psk_ext_eapol_retry1(dev, apdev):
     """WPA2 4-way handshake with EAPOL-Key 1/4 retransmitted"""
     (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
@@ -691,6 +785,7 @@ def test_ap_wpa2_psk_ext_eapol_retry1(dev, apdev):
     reply_eapol("4/4", hapd, addr, msg, 0x030a, None, None, kck)
     hapd_connected(hapd)
 
+@remote_compatible
 def test_ap_wpa2_psk_ext_eapol_retry1b(dev, apdev):
     """WPA2 4-way handshake with EAPOL-Key 1/4 and 2/4 retransmitted"""
     (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
@@ -712,6 +807,7 @@ def test_ap_wpa2_psk_ext_eapol_retry1b(dev, apdev):
     reply_eapol("4/4", hapd, addr, msg, 0x030a, None, None, kck)
     hapd_connected(hapd)
 
+@remote_compatible
 def test_ap_wpa2_psk_ext_eapol_retry1c(dev, apdev):
     """WPA2 4-way handshake with EAPOL-Key 1/4 and 2/4 retransmitted and SNonce changing"""
     (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
@@ -735,6 +831,7 @@ def test_ap_wpa2_psk_ext_eapol_retry1c(dev, apdev):
     reply_eapol("4/4", hapd, addr, msg, 0x030a, None, None, kck)
     hapd_connected(hapd)
 
+@remote_compatible
 def test_ap_wpa2_psk_ext_eapol_retry1d(dev, apdev):
     """WPA2 4-way handshake with EAPOL-Key 1/4 and 2/4 retransmitted and SNonce changing and older used"""
     (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
@@ -758,6 +855,7 @@ def test_ap_wpa2_psk_ext_eapol_retry1d(dev, apdev):
     reply_eapol("4/4", hapd, addr, msg, 0x030a, None, None, kck)
     hapd_connected(hapd)
 
+@remote_compatible
 def test_ap_wpa2_psk_ext_eapol_type_diff(dev, apdev):
     """WPA2 4-way handshake using external EAPOL supplicant"""
     (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
@@ -788,6 +886,7 @@ def test_ap_wpa2_psk_ext_eapol_type_diff(dev, apdev):
     reply_eapol("4/4", hapd, addr, msg, 0x030a, None, None, kck)
     hapd_connected(hapd)
 
+@remote_compatible
 def test_ap_wpa_psk_ext_eapol(dev, apdev):
     """WPA2-PSK AP using external EAPOL supplicant"""
     (bssid,ssid,hapd,snonce,pmk,addr,wpae) = eapol_test(apdev[0], dev[0],
@@ -815,6 +914,7 @@ def test_ap_wpa_psk_ext_eapol(dev, apdev):
     reply_eapol("4/4", hapd, addr, msg, 0x030a, None, None, kck)
     hapd_connected(hapd)
 
+@remote_compatible
 def test_ap_wpa2_psk_ext_eapol_key_info(dev, apdev):
     """WPA2-PSK 4-way handshake with strange key info values"""
     (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
@@ -1291,6 +1391,7 @@ def test_ap_wpa2_psk_supp_proto_unexpected_group_msg(dev, apdev):
         raise Exception("Unexpected group key message not reported")
     dev[0].wait_disconnected(timeout=1)
 
+@remote_compatible
 def test_ap_wpa2_psk_supp_proto_msg_1_invalid_kde(dev, apdev):
     """WPA2-PSK supplicant protocol testing: invalid KDE in msg 1/4"""
     (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
@@ -1598,8 +1699,7 @@ def test_ap_wpa2_psk_supp_proto_gtk_not_encrypted(dev, apdev):
 
 def find_wpas_process(dev):
     ifname = dev.ifname
-    cmd = subprocess.Popen(['ps', 'ax'], stdout=subprocess.PIPE)
-    (data,err) = cmd.communicate()
+    err, data = dev.cmd_execute(['ps', 'ax'])
     for l in data.splitlines():
         if "wpa_supplicant" not in l:
             continue
@@ -1610,6 +1710,7 @@ def find_wpas_process(dev):
 
 def read_process_memory(pid, key=None):
     buf = bytes()
+    logger.info("Reading process memory (pid=%d)" % pid)
     with open('/proc/%d/maps' % pid, 'r') as maps, \
          open('/proc/%d/mem' % pid, 'r') as mem:
         for l in maps.readlines():
@@ -1625,11 +1726,15 @@ def read_process_memory(pid, key=None):
                 continue
             if not perm.startswith('rw'):
                 continue
+            for name in [ "[heap]", "[stack]" ]:
+                if name in l:
+                    logger.info("%s 0x%x-0x%x is at %d-%d" % (name, start, end, len(buf), len(buf) + (end - start)))
             mem.seek(start)
             data = mem.read(end - start)
             buf += data
             if key and key in data:
                 logger.info("Key found in " + l)
+    logger.info("Total process memory read: %d bytes" % len(buf))
     return buf
 
 def verify_not_present(buf, key, fname, keyname):
@@ -1650,6 +1755,13 @@ def get_key_locations(buf, key, keyname):
         if pos < 0:
             break
         logger.info("Found %s at %d" % (keyname, pos))
+        context = 128
+        start = pos - context if pos > context else 0
+        before = binascii.hexlify(buf[start:pos])
+        context += len(key)
+        end = pos + context if pos < len(buf) - context else len(buf) - context
+        after = binascii.hexlify(buf[pos + len(key):end])
+        logger.debug("Memory context %d-%d: %s|%s|%s" % (start, end, before, binascii.hexlify(key), after))
         count += 1
         pos += len(key)
     return count
@@ -1662,7 +1774,7 @@ def test_wpa2_psk_key_lifetime_in_memory(dev, apdev, params):
     pmk = binascii.unhexlify(psk)
     p = hostapd.wpa2_params(ssid=ssid)
     p['wpa_psk'] = psk
-    hapd = hostapd.add_ap(apdev[0]['ifname'], p)
+    hapd = hostapd.add_ap(apdev[0], p)
 
     pid = find_wpas_process(dev[0])
 
@@ -1686,7 +1798,11 @@ def test_wpa2_psk_key_lifetime_in_memory(dev, apdev, params):
     get_key_locations(buf, pmk, "PMK")
 
     dev[0].connect_network(id, timeout=20)
+    # The decrypted copy of GTK is freed only after the CTRL-EVENT-CONNECTED
+    # event has been delivered, so verify that wpa_supplicant has returned to
+    # eloop before reading process memory.
     time.sleep(1)
+    dev[0].ping()
 
     buf = read_process_memory(pid, pmk)
 
@@ -1724,6 +1840,7 @@ def test_wpa2_psk_key_lifetime_in_memory(dev, apdev, params):
     if tk in buf:
         raise Exception("TK found from memory")
     if gtk in buf:
+        get_key_locations(buf, gtk, "GTK")
         raise Exception("GTK found from memory")
 
     logger.info("Checking keys in memory after disassociation")
@@ -1751,12 +1868,13 @@ def test_wpa2_psk_key_lifetime_in_memory(dev, apdev, params):
     verify_not_present(buf, tk, fname, "TK")
     verify_not_present(buf, gtk, fname, "GTK")
 
+@remote_compatible
 def test_ap_wpa2_psk_wep(dev, apdev):
     """WPA2-PSK AP and WEP enabled"""
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     try:
         hapd.set('wep_key0', '"hello"')
         raise Exception("WEP key accepted to WPA2 network")
@@ -1779,7 +1897,7 @@ def _test_ap_wpa2_psk_wpas_in_bridge(dev, apdev):
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     br_ifname='sta-br0'
     ifname='wlan5'
@@ -1790,25 +1908,28 @@ def _test_ap_wpa2_psk_wpas_in_bridge(dev, apdev):
     subprocess.call(['iw', ifname, 'set', '4addr', 'on'])
     subprocess.check_call(['brctl', 'addif', br_ifname, ifname])
     wpas.interface_add(ifname, br_ifname=br_ifname)
+    wpas.dump_monitor()
 
     wpas.connect(ssid, psk=passphrase, scan_freq="2412")
+    wpas.dump_monitor()
 
+@remote_compatible
 def test_ap_wpa2_psk_ifdown(dev, apdev):
     """AP with open mode and external ifconfig down"""
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
 
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
-    subprocess.call(['ip', 'link', 'set', 'dev', apdev[0]['ifname'], 'down'])
+    hapd.cmd_execute(['ip', 'link', 'set', 'dev', apdev[0]['ifname'], 'down'])
     ev = hapd.wait_event(["INTERFACE-DISABLED"], timeout=10)
     if ev is None:
         raise Exception("No INTERFACE-DISABLED event")
     # this wait tests beacon loss detection in mac80211
     dev[0].wait_disconnected()
-    subprocess.call(['ip', 'link', 'set', 'dev', apdev[0]['ifname'], 'up'])
+    hapd.cmd_execute(['ip', 'link', 'set', 'dev', apdev[0]['ifname'], 'up'])
     ev = hapd.wait_event(["INTERFACE-ENABLED"], timeout=10)
     if ev is None:
         raise Exception("No INTERFACE-ENABLED event")
@@ -1823,7 +1944,7 @@ def test_ap_wpa2_psk_drop_first_msg_4(dev, apdev):
     psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
     params = hostapd.wpa2_params(ssid=ssid)
     params['wpa_psk'] = psk
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     hapd.request("SET ext_eapol_frame_io 1")
     dev[0].request("SET ext_eapol_frame_io 1")
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412", wait_connect=False)
@@ -1882,6 +2003,7 @@ def test_ap_wpa2_psk_drop_first_msg_4(dev, apdev):
         # case, this exception can be uncommented here.
         #raise Exception("Unexpected disconnection")
 
+@remote_compatible
 def test_ap_wpa2_psk_disable_enable(dev, apdev):
     """WPA2-PSK AP getting disabled and re-enabled"""
     ssid = "test-wpa2-psk"
@@ -1889,7 +2011,7 @@ def test_ap_wpa2_psk_disable_enable(dev, apdev):
     psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
     params = hostapd.wpa2_params(ssid=ssid)
     params['wpa_psk'] = psk
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, raw_psk=psk, scan_freq="2412")
 
     for i in range(2):
@@ -1899,12 +2021,13 @@ def test_ap_wpa2_psk_disable_enable(dev, apdev):
         dev[0].wait_connected()
         hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_ap_wpa2_psk_incorrect_passphrase(dev, apdev):
     """WPA2-PSK AP and station using incorrect passphrase"""
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk="incorrect passphrase", scan_freq="2412",
                    wait_connect=False)
     ev = hapd.wait_event(["AP-STA-POSSIBLE-PSK-MISMATCH"], timeout=10)
@@ -1918,13 +2041,14 @@ def test_ap_wpa2_psk_incorrect_passphrase(dev, apdev):
 
     dev[0].wait_connected(timeout=20)
 
+@remote_compatible
 def test_ap_wpa_ie_parsing(dev, apdev):
     """WPA IE parsing"""
     skip_with_fips(dev[0])
     ssid = "test-wpa-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa_params(ssid=ssid, passphrase=passphrase)
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     id = dev[0].connect(ssid, psk=passphrase, scan_freq="2412",
                         only_add_network=True)
 
@@ -1960,6 +2084,7 @@ def test_ap_wpa_ie_parsing(dev, apdev):
             if ev is None:
                 raise Exception("Association rejection not reported")
             dev[0].request("DISCONNECT")
+            dev[0].dump_monitor()
         finally:
             dev[0].request("VENDOR_ELEM_REMOVE 13 *")
 
@@ -1973,9 +2098,11 @@ def test_ap_wpa_ie_parsing(dev, apdev):
             dev[0].select_network(id)
             dev[0].wait_connected()
             dev[0].request("DISCONNECT")
+            dev[0].dump_monitor()
         finally:
             dev[0].request("VENDOR_ELEM_REMOVE 13 *")
 
+@remote_compatible
 def test_ap_wpa2_psk_no_random(dev, apdev):
     """WPA2-PSK AP and no random numbers available"""
     ssid = "test-wpa2-psk"
@@ -1983,7 +2110,7 @@ def test_ap_wpa2_psk_no_random(dev, apdev):
     psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
     params = hostapd.wpa2_params(ssid=ssid)
     params['wpa_psk'] = psk
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     with fail_test(hapd, 1, "wpa_gmk_to_gtk"):
         id = dev[0].connect(ssid, raw_psk=psk, scan_freq="2412",
                             wait_connect=False)
@@ -1994,6 +2121,7 @@ def test_ap_wpa2_psk_no_random(dev, apdev):
         dev[0].select_network(id, freq=2412)
         dev[0].wait_connected()
 
+@remote_compatible
 def test_rsn_ie_proto_psk_sta(dev, apdev):
     """RSN element protocol testing for PSK cases on STA side"""
     bssid = apdev[0]['bssid']
@@ -2002,7 +2130,7 @@ def test_rsn_ie_proto_psk_sta(dev, apdev):
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     # This is the RSN element used normally by hostapd
     params['own_ie_override'] = '30140100000fac040100000fac040100000fac020c00'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     if "FAIL" not in hapd.request("SET own_ie_override qwerty"):
         raise Exception("Invalid own_ie_override value accepted")
     id = dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
@@ -2033,17 +2161,12 @@ def test_rsn_ie_proto_psk_sta(dev, apdev):
         dev[0].select_network(id, freq=2412)
         dev[0].wait_connected()
 
+@remote_compatible
 def test_ap_cli_order(dev, apdev):
     ssid = "test-rsn-setup"
     passphrase = 'zzzzzzzz'
-    ifname = apdev[0]['ifname']
 
-    hapd_global = hostapd.HostapdGlobal()
-    hapd_global.remove(ifname)
-    hapd_global.add(ifname)
-
-    hapd = hostapd.Hostapd(ifname)
-    hapd.set_defaults()
+    hapd = hostapd.add_ap(apdev[0], {}, no_enable=True)
     hapd.set('ssid', ssid)
     hapd.set('wpa_passphrase', passphrase)
     hapd.set('rsn_pairwise', 'CCMP')
@@ -2063,3 +2186,52 @@ def test_ap_cli_order(dev, apdev):
         raise Exception("AP startup failed")
 
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
+
+def set_test_assoc_ie(dev, ie):
+    if "OK" not in dev.request("TEST_ASSOC_IE " + ie):
+        raise Exception("Could not set TEST_ASSOC_IE")
+
+@remote_compatible
+def test_ap_wpa2_psk_assoc_rsn(dev, apdev):
+    """WPA2-PSK AP and association request RSN IE differences"""
+    ssid = "test-wpa2-psk"
+    passphrase = 'qwertyuiop'
+    params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    tests = [ ("Normal wpa_supplicant assoc req RSN IE",
+               "30140100000fac040100000fac040100000fac020000"),
+              ("RSN IE without RSN Capabilities",
+               "30120100000fac040100000fac040100000fac02") ]
+    for title, ie in tests:
+        logger.info(title)
+        set_test_assoc_ie(dev[0], ie)
+        dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    tests = [ ("WPA IE instead of RSN IE and only RSN enabled on AP",
+               "dd160050f20101000050f20201000050f20201000050f202", 40),
+              ("Empty RSN IE", "3000", 40),
+              ("RSN IE with truncated Version", "300101", 40),
+              ("RSN IE with only Version", "30020100", 43) ]
+    for title, ie, status in tests:
+        logger.info(title)
+        set_test_assoc_ie(dev[0], ie)
+        dev[0].connect(ssid, psk=passphrase, scan_freq="2412",
+                       wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-EVENT-ASSOC-REJECT"])
+        if ev is None:
+            raise Exception("Association rejection not reported")
+        if "status_code=" + str(status) not in ev:
+            raise Exception("Unexpected status code: " + ev)
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].dump_monitor()
+
+def test_ap_wpa_psk_rsn_pairwise(dev, apdev):
+    """WPA-PSK AP and only rsn_pairwise set"""
+    params = { "ssid": "wpapsk", "wpa": "1", "wpa_key_mgmt": "WPA-PSK",
+               "rsn_pairwise": "TKIP", "wpa_passphrase": "1234567890" }
+    hapd = hostapd.add_ap(apdev[0], params)
+    dev[0].connect("wpapsk", psk="1234567890", proto="WPA", pairwise="TKIP",
+                   scan_freq="2412")
index 67604b2..3119a98 100644 (file)
@@ -4,8 +4,8 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import time
-import subprocess
 import logging
 logger = logging.getLogger()
 
@@ -21,7 +21,8 @@ def check_qos_map(ap, hapd, dev, sta, dscp, tid, ap_tid=None):
     wt = Wlantest()
     wt.clear_sta_counters(bssid, sta)
     hwsim_utils.test_connectivity(dev, hapd, dscp=dscp, config=False)
-    time.sleep(0.02)
+    sleep_time = 0.02 if dev.hostname is None else 0.2
+    time.sleep(sleep_time)
     tx = wt.get_tx_tid(bssid, sta, tid)
     if tx == 0:
         [ tx, rx ] = wt.get_tid_counters(bssid, sta)
@@ -33,6 +34,7 @@ def check_qos_map(ap, hapd, dev, sta, dscp, tid, ap_tid=None):
         logger.info("Expected RX DSCP " + str(dscp) + " with TID " + str(ap_tid) + " but counters: " + str(rx))
         raise Exception("No AP->STA data frame using the expected TID")
 
+@remote_compatible
 def test_ap_qosmap(dev, apdev):
     """QoS mapping"""
     drv_flags = dev[0].get_driver_status_field("capa.flags")
@@ -41,12 +43,13 @@ def test_ap_qosmap(dev, apdev):
     ssid = "test-qosmap"
     params = { "ssid": ssid }
     params['qos_map_set'] = '53,2,22,6,8,15,0,7,255,255,16,31,32,39,255,255,40,47,48,55'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
     time.sleep(0.1)
     addr = dev[0].p2p_interface_addr()
     dev[0].request("DATA_TEST_CONFIG 1")
     hapd.request("DATA_TEST_CONFIG 1")
+    Wlantest.setup(hapd)
     check_qos_map(apdev[0], hapd, dev[0], addr, 53, 2)
     check_qos_map(apdev[0], hapd, dev[0], addr, 22, 6)
     check_qos_map(apdev[0], hapd, dev[0], addr, 8, 0)
@@ -72,20 +75,23 @@ def test_ap_qosmap(dev, apdev):
     dev[0].request("DATA_TEST_CONFIG 0")
     hapd.request("DATA_TEST_CONFIG 0")
 
+@remote_compatible
 def test_ap_qosmap_default(dev, apdev):
     """QoS mapping with default values"""
     ssid = "test-qosmap-default"
     params = { "ssid": ssid }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
     addr = dev[0].p2p_interface_addr()
     dev[0].request("DATA_TEST_CONFIG 1")
     hapd.request("DATA_TEST_CONFIG 1")
+    Wlantest.setup(hapd)
     for dscp in [ 0, 7, 8, 15, 16, 23, 24, 31, 32, 39, 40, 47, 48, 55, 56, 63]:
         check_qos_map(apdev[0], hapd, dev[0], addr, dscp, dscp >> 3)
     dev[0].request("DATA_TEST_CONFIG 0")
     hapd.request("DATA_TEST_CONFIG 0")
 
+@remote_compatible
 def test_ap_qosmap_default_acm(dev, apdev):
     """QoS mapping with default values and ACM=1 for VO/VI"""
     ssid = "test-qosmap-default"
@@ -110,11 +116,12 @@ def test_ap_qosmap_default_acm(dev, apdev):
                "wmm_ac_vo_cwmax": "2",
                "wmm_ac_vo_txop_limit": "47",
                "wmm_ac_vo_acm": "1"  }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
     addr = dev[0].p2p_interface_addr()
     dev[0].request("DATA_TEST_CONFIG 1")
     hapd.request("DATA_TEST_CONFIG 1")
+    Wlantest.setup(hapd)
     for dscp in [ 0, 7, 8, 15, 16, 23, 24, 31, 32, 39, 40, 47, 48, 55, 56, 63]:
         ap_tid = dscp >> 3
         tid = ap_tid
@@ -125,11 +132,12 @@ def test_ap_qosmap_default_acm(dev, apdev):
     dev[0].request("DATA_TEST_CONFIG 0")
     hapd.request("DATA_TEST_CONFIG 0")
 
+@remote_compatible
 def test_ap_qosmap_invalid(dev, apdev):
     """QoS mapping ctrl_iface error handling"""
     ssid = "test-qosmap"
     params = { "ssid": ssid }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     if "FAIL" not in hapd.request("SEND_QOS_MAP_CONF 00:11:22:33:44:55"):
         raise Exception("Unexpected SEND_QOS_MAP_CONF success")
     if "FAIL" not in hapd.request("SET_QOS_MAP_SET "):
index f41e272..6f8b8d9 100644 (file)
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import time
-import subprocess
 import logging
 logger = logging.getLogger()
 
 import hwsim_utils
 import hostapd
+from wpasupplicant import WpaSupplicant
 
+@remote_compatible
 def test_ap_roam_open(dev, apdev):
     """Roam between two open APs"""
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    hapd0 = hostapd.add_ap(apdev[0], { "ssid": "test-open" })
     dev[0].connect("test-open", key_mgmt="NONE")
     hwsim_utils.test_connectivity(dev[0], hapd0)
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], { "ssid": "test-open" })
+    hapd1 = hostapd.add_ap(apdev[1], { "ssid": "test-open" })
     dev[0].scan(type="ONLY")
     dev[0].roam(apdev[1]['bssid'])
     hwsim_utils.test_connectivity(dev[0], hapd1)
     dev[0].roam(apdev[0]['bssid'])
     hwsim_utils.test_connectivity(dev[0], hapd0)
 
+@remote_compatible
+def test_ap_roam_open_failed(dev, apdev):
+    """Roam failure due to rejected authentication"""
+    hapd0 = hostapd.add_ap(apdev[0], { "ssid": "test-open" })
+    dev[0].connect("test-open", key_mgmt="NONE", scan_freq="2412")
+    hwsim_utils.test_connectivity(dev[0], hapd0)
+    params = { "ssid": "test-open", "max_num_sta" : "0" }
+    hapd1 = hostapd.add_ap(apdev[1], params)
+    bssid = hapd1.own_addr()
+
+    dev[0].scan_for_bss(bssid, freq=2412)
+    dev[0].dump_monitor()
+    if "OK" not in dev[0].request("ROAM " + bssid):
+        raise Exception("ROAM failed")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-AUTH-REJECT"], 1)
+    if not ev:
+        raise Exception("CTRL-EVENT-AUTH-REJECT was not seen")
+
+    dev[0].wait_connected(timeout=5)
+    hwsim_utils.test_connectivity(dev[0], hapd0)
+
+@remote_compatible
 def test_ap_roam_wpa2_psk(dev, apdev):
     """Roam between two WPA2-PSK APs"""
     params = hostapd.wpa2_params(ssid="test-wpa2-psk", passphrase="12345678")
-    hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd0 = hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wpa2-psk", psk="12345678")
     hwsim_utils.test_connectivity(dev[0], hapd0)
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
     dev[0].scan(type="ONLY")
     dev[0].roam(apdev[1]['bssid'])
     hwsim_utils.test_connectivity(dev[0], hapd1)
     dev[0].roam(apdev[0]['bssid'])
     hwsim_utils.test_connectivity(dev[0], hapd0)
 
+def get_blacklist(dev):
+    return dev.request("BLACKLIST").splitlines()
+
+def test_ap_reconnect_auth_timeout(dev, apdev, params):
+    """Reconnect to 2nd AP and authentication times out"""
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    wpas.interface_add("wlan5",
+                       drv_params="force_connect_cmd=1,force_bss_selection=1")
+
+    params = hostapd.wpa2_params(ssid="test-wpa2-psk", passphrase="12345678")
+    hapd0 = hostapd.add_ap(apdev[0], params)
+    bssid0 = hapd0.own_addr()
+    hapd1 = hostapd.add_ap(apdev[1], params)
+    bssid1 = hapd1.own_addr()
+
+    wpas.scan_for_bss(bssid0, freq=2412)
+    id = wpas.connect("test-wpa2-psk", psk="12345678", scan_freq="2412")
+    hwsim_utils.test_connectivity(wpas, hapd0)
+
+    wpas.request("BLACKLIST " + bssid0)
+
+    wpas.scan_for_bss(bssid1, freq=2412)
+    wpas.request("DISCONNECT")
+    if "OK" not in wpas.request("SET ignore_auth_resp 1"):
+        raise Exception("SET ignore_auth_resp failed")
+    if "OK" not in wpas.request("ENABLE_NETWORK " + str(id)):
+        raise Exception("ENABLE_NETWORK failed")
+    if "OK" not in wpas.request("SELECT_NETWORK " + str(id)):
+        raise Exception("SELECT_NETWORK failed")
+
+    logger.info("Wait ~10s for auth timeout...")
+    time.sleep(10)
+    ev = wpas.wait_event(["CTRL-EVENT-SCAN-STARTED"], 12)
+    if not ev:
+        raise Exception("CTRL-EVENT-SCAN-STARTED not seen");
+
+    b = get_blacklist(wpas)
+    if '00:00:00:00:00:00' in b:
+        raise Exception("Unexpected blacklist contents: " + str(b))
+    if bssid1 not in b:
+        raise Exception("Unexpected blacklist contents: " + str(b))
+
+def test_ap_roam_with_reassoc_auth_timeout(dev, apdev, params):
+    """Roam using reassoc between two APs and authentication times out"""
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    wpas.interface_add("wlan5",
+                       drv_params="force_connect_cmd=1,force_bss_selection=1")
+
+    params = hostapd.wpa2_params(ssid="test-wpa2-psk", passphrase="12345678")
+    hapd0 = hostapd.add_ap(apdev[0], params)
+    bssid0 = hapd0.own_addr()
+
+    id = wpas.connect("test-wpa2-psk", psk="12345678", scan_freq="2412")
+    hwsim_utils.test_connectivity(wpas, hapd0)
+
+    hapd1 = hostapd.add_ap(apdev[1], params)
+    bssid1 = hapd1.own_addr()
+    wpas.scan_for_bss(bssid1, freq=2412)
+
+    if "OK" not in wpas.request("SET_NETWORK " + str(id) + " bssid " + bssid1):
+        raise Exception("SET_NETWORK failed")
+    if "OK" not in wpas.request("SET ignore_auth_resp 1"):
+        raise Exception("SET ignore_auth_resp failed")
+    if "OK" not in wpas.request("REASSOCIATE"):
+        raise Exception("REASSOCIATE failed")
+
+    logger.info("Wait ~10s for auth timeout...")
+    time.sleep(10)
+    ev = wpas.wait_event(["CTRL-EVENT-SCAN-STARTED"], 12)
+    if not ev:
+        raise Exception("CTRL-EVENT-SCAN-STARTED not seen");
+
+    b = get_blacklist(wpas)
+    if bssid0 in b:
+        raise Exception("Unexpected blacklist contents: " + str(b))
+
+def test_ap_roam_wpa2_psk_failed(dev, apdev, params):
+    """Roam failure with WPA2-PSK AP due to wrong passphrase"""
+    params = hostapd.wpa2_params(ssid="test-wpa2-psk", passphrase="12345678")
+    hapd0 = hostapd.add_ap(apdev[0], params)
+    id = dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412")
+    hwsim_utils.test_connectivity(dev[0], hapd0)
+    params['wpa_passphrase'] = "22345678"
+    hapd1 = hostapd.add_ap(apdev[1], params)
+    bssid = hapd1.own_addr()
+    dev[0].scan_for_bss(bssid, freq=2412)
+
+    dev[0].dump_monitor()
+    if "OK" not in dev[0].request("ROAM " + bssid):
+        raise Exception("ROAM failed")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-SSID-TEMP-DISABLED",
+                            "CTRL-EVENT-CONNECTED"], 5)
+    if "CTRL-EVENT-CONNECTED" in ev:
+        raise Exception("Got unexpected CTRL-EVENT-CONNECTED")
+    if "CTRL-EVENT-SSID-TEMP-DISABLED" not in ev:
+        raise Exception("CTRL-EVENT-SSID-TEMP-DISABLED not seen")
+
+    if "OK" not in dev[0].request("SELECT_NETWORK id=" + str(id)):
+        raise Exception("SELECT_NETWORK failed")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-SSID-REENABLED"], 3)
+    if not ev:
+        raise Exception("CTRL-EVENT-SSID-REENABLED not seen")
+
+    dev[0].wait_connected(timeout=5)
+    hwsim_utils.test_connectivity(dev[0], hapd0)
+
+@remote_compatible
 def test_ap_reassociation_to_same_bss(dev, apdev):
     """Reassociate to the same BSS"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-open" })
     dev[0].connect("test-open", key_mgmt="NONE")
 
     dev[0].request("REASSOCIATE")
@@ -50,10 +184,17 @@ def test_ap_reassociation_to_same_bss(dev, apdev):
     dev[0].wait_connected(timeout=10, error="Reattach timed out")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+    # Wait for previous scan results to expire to trigger new scan
+    time.sleep(5)
+    dev[0].request("REATTACH")
+    dev[0].wait_connected(timeout=10, error="Reattach timed out")
+    hwsim_utils.test_connectivity(dev[0], hapd)
+
+@remote_compatible
 def test_ap_roam_set_bssid(dev, apdev):
     """Roam control"""
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
-    hostapd.add_ap(apdev[1]['ifname'], { "ssid": "test-open" })
+    hostapd.add_ap(apdev[0], { "ssid": "test-open" })
+    hostapd.add_ap(apdev[1], { "ssid": "test-open" })
     id = dev[0].connect("test-open", key_mgmt="NONE", bssid=apdev[1]['bssid'],
                         scan_freq="2412")
     if dev[0].get_status_field('bssid') != apdev[1]['bssid']:
@@ -65,3 +206,24 @@ def test_ap_roam_set_bssid(dev, apdev):
     dev[0].set_network(id, "bssid", "")
     dev[0].set_network(id, "bssid", apdev[0]['bssid'])
     dev[0].set_network(id, "bssid", apdev[1]['bssid'])
+
+@remote_compatible
+def test_ap_roam_wpa2_psk_race(dev, apdev):
+    """Roam between two WPA2-PSK APs and try to hit a disconnection race"""
+    params = hostapd.wpa2_params(ssid="test-wpa2-psk", passphrase="12345678")
+    hapd0 = hostapd.add_ap(apdev[0], params)
+    dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412")
+    hwsim_utils.test_connectivity(dev[0], hapd0)
+
+    params['channel'] = '2'
+    hapd1 = hostapd.add_ap(apdev[1], params)
+    dev[0].scan_for_bss(apdev[1]['bssid'], freq=2417)
+    dev[0].roam(apdev[1]['bssid'])
+    hwsim_utils.test_connectivity(dev[0], hapd1)
+    dev[0].roam(apdev[0]['bssid'])
+    hwsim_utils.test_connectivity(dev[0], hapd0)
+    # Wait at least two seconds to trigger the previous issue with the
+    # disconnection callback.
+    for i in range(3):
+        time.sleep(0.8)
+        hwsim_utils.test_connectivity(dev[0], hapd0)
index bcfa3cc..5b6ee9c 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import time
 import logging
 logger = logging.getLogger()
@@ -15,10 +16,11 @@ from hostapd import Hostapd
 import hostapd
 from utils import HwsimSkip, skip_with_fips
 from wlantest import Wlantest
+from test_ap_vht import vht_supported
 
-def start_ap_wpa2_psk(ifname):
+def start_ap_wpa2_psk(ap):
     params = hostapd.wpa2_params(ssid="test-wpa2-psk", passphrase="12345678")
-    return hostapd.add_ap(ifname, params)
+    return hostapd.add_ap(ap, params)
 
 def connectivity(dev, hapd):
     hwsim_utils.test_connectivity_sta(dev[0], dev[1])
@@ -55,7 +57,8 @@ def connect_2sta_open(dev, hapd, scan_freq="2412"):
     dev[1].connect("test-open", key_mgmt="NONE", scan_freq=scan_freq)
     connectivity(dev, hapd)
 
-def wlantest_setup():
+def wlantest_setup(hapd):
+    Wlantest.setup(hapd)
     wt = Wlantest()
     wt.flush()
     wt.add_passphrase("12345678")
@@ -85,7 +88,7 @@ def tdls_check_dl(sta0, sta1, bssid, addr0, addr1):
 
 def tdls_check_ap(sta0, sta1, bssid, addr0, addr1):
     wt = Wlantest()
-    wt.tdls_clear(bssid, addr0, addr1);
+    wt.tdls_clear(bssid, addr0, addr1)
     hwsim_utils.test_connectivity_sta(sta0, sta1)
     [dl,inv_dl,ap,inv_ap] = wlantest_tdls_packet_counters(bssid, addr0, addr1)
     if dl > 0:
@@ -102,16 +105,15 @@ def check_connectivity(sta0, sta1, hapd):
     hwsim_utils.test_connectivity(sta0, hapd)
     hwsim_utils.test_connectivity(sta1, hapd)
 
-def setup_tdls(sta0, sta1, ap, reverse=False, expect_fail=False):
+def setup_tdls(sta0, sta1, hapd, reverse=False, expect_fail=False):
     logger.info("Setup TDLS")
-    hapd = hostapd.Hostapd(ap['ifname'])
     check_connectivity(sta0, sta1, hapd)
-    bssid = ap['bssid']
+    bssid = hapd.own_addr()
     addr0 = sta0.p2p_interface_addr()
     addr1 = sta1.p2p_interface_addr()
     wt = Wlantest()
-    wt.tdls_clear(bssid, addr0, addr1);
-    wt.tdls_clear(bssid, addr1, addr0);
+    wt.tdls_clear(bssid, addr0, addr1)
+    wt.tdls_clear(bssid, addr1, addr0)
     sta0.tdls_setup(addr1)
     time.sleep(1)
     if expect_fail:
@@ -120,17 +122,16 @@ def setup_tdls(sta0, sta1, ap, reverse=False, expect_fail=False):
     if reverse:
         addr1 = sta0.p2p_interface_addr()
         addr0 = sta1.p2p_interface_addr()
-    conf = wt.get_tdls_counter("setup_conf_ok", bssid, addr0, addr1);
+    conf = wt.get_tdls_counter("setup_conf_ok", bssid, addr0, addr1)
     if conf == 0:
         raise Exception("No TDLS Setup Confirm (success) seen")
     tdls_check_dl(sta0, sta1, bssid, addr0, addr1)
     check_connectivity(sta0, sta1, hapd)
 
-def teardown_tdls(sta0, sta1, ap, responder=False, wildcard=False):
+def teardown_tdls(sta0, sta1, hapd, responder=False, wildcard=False):
     logger.info("Teardown TDLS")
-    hapd = hostapd.Hostapd(ap['ifname'])
     check_connectivity(sta0, sta1, hapd)
-    bssid = ap['bssid']
+    bssid = hapd.own_addr()
     addr0 = sta0.p2p_interface_addr()
     addr1 = sta1.p2p_interface_addr()
     if responder:
@@ -141,7 +142,7 @@ def teardown_tdls(sta0, sta1, ap, responder=False, wildcard=False):
         sta0.tdls_teardown(addr1)
     time.sleep(1)
     wt = Wlantest()
-    teardown = wt.get_tdls_counter("teardown", bssid, addr0, addr1);
+    teardown = wt.get_tdls_counter("teardown", bssid, addr0, addr1)
     if teardown == 0:
         raise Exception("No TDLS Setup Teardown seen")
     tdls_check_ap(sta0, sta1, bssid, addr0, addr1)
@@ -163,96 +164,97 @@ def check_tdls_link(sta0, sta1, connected=True):
         if connected:
             raise Exception("Expected TDLS link status to be connected")
 
+@remote_compatible
 def test_ap_tdls_discovery(dev, apdev):
     """WPA2-PSK AP and two stations using TDLS discovery"""
-    hapd = start_ap_wpa2_psk(apdev[0]['ifname'])
-    wlantest_setup()
+    hapd = start_ap_wpa2_psk(apdev[0])
+    wlantest_setup(hapd)
     connect_2sta_wpa2_psk(dev, hapd)
     dev[0].request("TDLS_DISCOVER " + dev[1].p2p_interface_addr())
     time.sleep(0.2)
 
 def test_ap_wpa2_tdls(dev, apdev):
     """WPA2-PSK AP and two stations using TDLS"""
-    hapd = start_ap_wpa2_psk(apdev[0]['ifname'])
-    wlantest_setup()
+    hapd = start_ap_wpa2_psk(apdev[0])
+    wlantest_setup(hapd)
     connect_2sta_wpa2_psk(dev, hapd)
-    setup_tdls(dev[0], dev[1], apdev[0])
-    teardown_tdls(dev[0], dev[1], apdev[0])
-    setup_tdls(dev[1], dev[0], apdev[0])
-    #teardown_tdls(dev[0], dev[1], apdev[0])
+    setup_tdls(dev[0], dev[1], hapd)
+    teardown_tdls(dev[0], dev[1], hapd)
+    setup_tdls(dev[1], dev[0], hapd)
+    #teardown_tdls(dev[0], dev[1], hapd)
 
 def test_ap_wpa2_tdls_concurrent_init(dev, apdev):
     """Concurrent TDLS setup initiation"""
-    hapd = start_ap_wpa2_psk(apdev[0]['ifname'])
-    wlantest_setup()
+    hapd = start_ap_wpa2_psk(apdev[0])
+    wlantest_setup(hapd)
     connect_2sta_wpa2_psk(dev, hapd)
     dev[0].request("SET tdls_testing 0x80")
-    setup_tdls(dev[1], dev[0], apdev[0], reverse=True)
+    setup_tdls(dev[1], dev[0], hapd, reverse=True)
 
 def test_ap_wpa2_tdls_concurrent_init2(dev, apdev):
     """Concurrent TDLS setup initiation (reverse)"""
-    hapd = start_ap_wpa2_psk(apdev[0]['ifname'])
-    wlantest_setup()
+    hapd = start_ap_wpa2_psk(apdev[0])
+    wlantest_setup(hapd)
     connect_2sta_wpa2_psk(dev, hapd)
     dev[1].request("SET tdls_testing 0x80")
-    setup_tdls(dev[0], dev[1], apdev[0])
+    setup_tdls(dev[0], dev[1], hapd)
 
 def test_ap_wpa2_tdls_decline_resp(dev, apdev):
     """Decline TDLS Setup Response"""
-    hapd = start_ap_wpa2_psk(apdev[0]['ifname'])
-    wlantest_setup()
+    hapd = start_ap_wpa2_psk(apdev[0])
+    wlantest_setup(hapd)
     connect_2sta_wpa2_psk(dev, hapd)
     dev[1].request("SET tdls_testing 0x200")
-    setup_tdls(dev[1], dev[0], apdev[0], expect_fail=True)
+    setup_tdls(dev[1], dev[0], hapd, expect_fail=True)
 
 def test_ap_wpa2_tdls_long_lifetime(dev, apdev):
     """TDLS with long TPK lifetime"""
-    hapd = start_ap_wpa2_psk(apdev[0]['ifname'])
-    wlantest_setup()
+    hapd = start_ap_wpa2_psk(apdev[0])
+    wlantest_setup(hapd)
     connect_2sta_wpa2_psk(dev, hapd)
     dev[1].request("SET tdls_testing 0x40")
-    setup_tdls(dev[1], dev[0], apdev[0])
+    setup_tdls(dev[1], dev[0], hapd)
 
 def test_ap_wpa2_tdls_long_frame(dev, apdev):
     """TDLS with long setup/teardown frames"""
-    hapd = start_ap_wpa2_psk(apdev[0]['ifname'])
-    wlantest_setup()
+    hapd = start_ap_wpa2_psk(apdev[0])
+    wlantest_setup(hapd)
     connect_2sta_wpa2_psk(dev, hapd)
     dev[0].request("SET tdls_testing 0x1")
     dev[1].request("SET tdls_testing 0x1")
-    setup_tdls(dev[1], dev[0], apdev[0])
-    teardown_tdls(dev[1], dev[0], apdev[0])
-    setup_tdls(dev[0], dev[1], apdev[0])
+    setup_tdls(dev[1], dev[0], hapd)
+    teardown_tdls(dev[1], dev[0], hapd)
+    setup_tdls(dev[0], dev[1], hapd)
 
 def test_ap_wpa2_tdls_reneg(dev, apdev):
     """Renegotiate TDLS link"""
-    hapd = start_ap_wpa2_psk(apdev[0]['ifname'])
-    wlantest_setup()
+    hapd = start_ap_wpa2_psk(apdev[0])
+    wlantest_setup(hapd)
     connect_2sta_wpa2_psk(dev, hapd)
-    setup_tdls(dev[1], dev[0], apdev[0])
-    setup_tdls(dev[0], dev[1], apdev[0])
+    setup_tdls(dev[1], dev[0], hapd)
+    setup_tdls(dev[0], dev[1], hapd)
 
 def test_ap_wpa2_tdls_wrong_lifetime_resp(dev, apdev):
     """Incorrect TPK lifetime in TDLS Setup Response"""
-    hapd = start_ap_wpa2_psk(apdev[0]['ifname'])
-    wlantest_setup()
+    hapd = start_ap_wpa2_psk(apdev[0])
+    wlantest_setup(hapd)
     connect_2sta_wpa2_psk(dev, hapd)
     dev[1].request("SET tdls_testing 0x10")
-    setup_tdls(dev[0], dev[1], apdev[0], expect_fail=True)
+    setup_tdls(dev[0], dev[1], hapd, expect_fail=True)
 
 def test_ap_wpa2_tdls_diff_rsnie(dev, apdev):
     """TDLS with different RSN IEs"""
-    hapd = start_ap_wpa2_psk(apdev[0]['ifname'])
-    wlantest_setup()
+    hapd = start_ap_wpa2_psk(apdev[0])
+    wlantest_setup(hapd)
     connect_2sta_wpa2_psk(dev, hapd)
     dev[1].request("SET tdls_testing 0x2")
-    setup_tdls(dev[1], dev[0], apdev[0])
-    teardown_tdls(dev[1], dev[0], apdev[0])
+    setup_tdls(dev[1], dev[0], hapd)
+    teardown_tdls(dev[1], dev[0], hapd)
 
 def test_ap_wpa2_tdls_wrong_tpk_m2_mic(dev, apdev):
     """Incorrect MIC in TDLS Setup Response"""
-    hapd = start_ap_wpa2_psk(apdev[0]['ifname'])
-    wlantest_setup()
+    hapd = start_ap_wpa2_psk(apdev[0])
+    wlantest_setup(hapd)
     connect_2sta_wpa2_psk(dev, hapd)
     dev[0].request("SET tdls_testing 0x800")
     addr0 = dev[0].p2p_interface_addr()
@@ -261,8 +263,8 @@ def test_ap_wpa2_tdls_wrong_tpk_m2_mic(dev, apdev):
 
 def test_ap_wpa2_tdls_wrong_tpk_m3_mic(dev, apdev):
     """Incorrect MIC in TDLS Setup Confirm"""
-    hapd = start_ap_wpa2_psk(apdev[0]['ifname'])
-    wlantest_setup()
+    hapd = start_ap_wpa2_psk(apdev[0])
+    wlantest_setup(hapd)
     connect_2sta_wpa2_psk(dev, hapd)
     dev[1].request("SET tdls_testing 0x800")
     addr0 = dev[0].p2p_interface_addr()
@@ -272,46 +274,46 @@ def test_ap_wpa2_tdls_wrong_tpk_m3_mic(dev, apdev):
 def test_ap_wpa_tdls(dev, apdev):
     """WPA-PSK AP and two stations using TDLS"""
     skip_with_fips(dev[0])
-    hapd = hostapd.add_ap(apdev[0]['ifname'],
+    hapd = hostapd.add_ap(apdev[0],
                           hostapd.wpa_params(ssid="test-wpa-psk",
                                              passphrase="12345678"))
-    wlantest_setup()
+    wlantest_setup(hapd)
     connect_2sta_wpa_psk(dev, hapd)
-    setup_tdls(dev[0], dev[1], apdev[0])
-    teardown_tdls(dev[0], dev[1], apdev[0])
-    setup_tdls(dev[1], dev[0], apdev[0])
+    setup_tdls(dev[0], dev[1], hapd)
+    teardown_tdls(dev[0], dev[1], hapd)
+    setup_tdls(dev[1], dev[0], hapd)
 
 def test_ap_wpa_mixed_tdls(dev, apdev):
     """WPA+WPA2-PSK AP and two stations using TDLS"""
     skip_with_fips(dev[0])
-    hapd = hostapd.add_ap(apdev[0]['ifname'],
+    hapd = hostapd.add_ap(apdev[0],
                           hostapd.wpa_mixed_params(ssid="test-wpa-mixed-psk",
                                                    passphrase="12345678"))
-    wlantest_setup()
+    wlantest_setup(hapd)
     connect_2sta_wpa_psk_mixed(dev, hapd)
-    setup_tdls(dev[0], dev[1], apdev[0])
-    teardown_tdls(dev[0], dev[1], apdev[0])
-    setup_tdls(dev[1], dev[0], apdev[0])
+    setup_tdls(dev[0], dev[1], hapd)
+    teardown_tdls(dev[0], dev[1], hapd)
+    setup_tdls(dev[1], dev[0], hapd)
 
 def test_ap_wep_tdls(dev, apdev):
     """WEP AP and two stations using TDLS"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'],
+    hapd = hostapd.add_ap(apdev[0],
                           { "ssid": "test-wep", "wep_key0": '"hello"' })
-    wlantest_setup()
+    wlantest_setup(hapd)
     connect_2sta_wep(dev, hapd)
-    setup_tdls(dev[0], dev[1], apdev[0])
-    teardown_tdls(dev[0], dev[1], apdev[0])
-    setup_tdls(dev[1], dev[0], apdev[0])
+    setup_tdls(dev[0], dev[1], hapd)
+    teardown_tdls(dev[0], dev[1], hapd)
+    setup_tdls(dev[1], dev[0], hapd)
 
 def test_ap_open_tdls(dev, apdev):
     """Open AP and two stations using TDLS"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
-    wlantest_setup()
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-open" })
+    wlantest_setup(hapd)
     connect_2sta_open(dev, hapd)
-    setup_tdls(dev[0], dev[1], apdev[0])
-    teardown_tdls(dev[0], dev[1], apdev[0])
-    setup_tdls(dev[1], dev[0], apdev[0])
-    teardown_tdls(dev[1], dev[0], apdev[0], wildcard=True)
+    setup_tdls(dev[0], dev[1], hapd)
+    teardown_tdls(dev[0], dev[1], hapd)
+    setup_tdls(dev[1], dev[0], hapd)
+    teardown_tdls(dev[1], dev[0], hapd, wildcard=True)
 
 def test_ap_wpa2_tdls_bssid_mismatch(dev, apdev):
     """TDLS failure due to BSSID mismatch"""
@@ -320,9 +322,9 @@ def test_ap_wpa2_tdls_bssid_mismatch(dev, apdev):
         passphrase = "12345678"
         params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
         params['bridge'] = 'ap-br0'
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-        hostapd.add_ap(apdev[1]['ifname'], params)
-        wlantest_setup()
+        hapd = hostapd.add_ap(apdev[0], params)
+        hostapd.add_ap(apdev[1], params)
+        wlantest_setup(hapd)
         subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
         subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
         dev[0].connect(ssid, psk=passphrase, scan_freq="2412",
@@ -343,11 +345,11 @@ def test_ap_wpa2_tdls_bssid_mismatch(dev, apdev):
 
 def test_ap_wpa2_tdls_responder_teardown(dev, apdev):
     """TDLS teardown from responder with WPA2-PSK AP"""
-    hapd = start_ap_wpa2_psk(apdev[0]['ifname'])
-    wlantest_setup()
+    hapd = start_ap_wpa2_psk(apdev[0])
+    wlantest_setup(hapd)
     connect_2sta_wpa2_psk(dev, hapd)
-    setup_tdls(dev[0], dev[1], apdev[0])
-    teardown_tdls(dev[0], dev[1], apdev[0], responder=True)
+    setup_tdls(dev[0], dev[1], hapd)
+    teardown_tdls(dev[0], dev[1], hapd, responder=True)
 
 def test_ap_open_tdls_vht(dev, apdev):
     """Open AP and two stations using TDLS"""
@@ -361,14 +363,158 @@ def test_ap_open_tdls_vht(dev, apdev):
                "vht_capab": "",
                "vht_oper_chwidth": "0",
                "vht_oper_centr_freq_seg0_idx": "0" }
+    hapd = None
+    try:
+        hapd = hostapd.add_ap(apdev[0], params)
+        wlantest_setup(hapd)
+        connect_2sta_open(dev, hapd, scan_freq="5180")
+        setup_tdls(dev[0], dev[1], hapd)
+        teardown_tdls(dev[0], dev[1], hapd)
+        setup_tdls(dev[1], dev[0], hapd)
+        teardown_tdls(dev[1], dev[0], hapd, wildcard=True)
+    finally:
+        dev[0].request("DISCONNECT")
+        dev[1].request("DISCONNECT")
+        if hapd:
+            hapd.request("DISABLE")
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        dev[0].flush_scan_cache()
+        dev[1].flush_scan_cache()
+
+def test_ap_open_tdls_vht80(dev, apdev):
+    """Open AP and two stations using TDLS with VHT 80"""
+    params = { "ssid": "test-open",
+               "country_code": "US",
+               "hw_mode": "a",
+               "channel": "36",
+               "ht_capab": "[HT40+]",
+               "ieee80211n": "1",
+               "ieee80211ac": "1",
+               "vht_capab": "",
+               "vht_oper_chwidth": "1",
+               "vht_oper_centr_freq_seg0_idx": "42" }
+    try:
+        hapd = None
+        hapd = hostapd.add_ap(apdev[0], params)
+        wlantest_setup(hapd)
+        connect_2sta_open(dev, hapd, scan_freq="5180")
+        sig = dev[0].request("SIGNAL_POLL").splitlines()
+        if "WIDTH=80 MHz" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
+        setup_tdls(dev[0], dev[1], hapd)
+        for i in range(10):
+            check_connectivity(dev[0], dev[1], hapd)
+        for i in range(2):
+            cmd = subprocess.Popen(['iw', dev[0].ifname, 'station', 'dump'],
+                                   stdout=subprocess.PIPE)
+            res = cmd.stdout.read()
+            cmd.stdout.close()
+            logger.info("Station dump on dev[%d]:\n%s" % (i, res))
+    except Exception, e:
+        if isinstance(e, Exception) and str(e) == "AP startup failed":
+            if not vht_supported():
+                raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
+        raise
+    finally:
+        dev[0].request("DISCONNECT")
+        dev[1].request("DISCONNECT")
+        if hapd:
+            hapd.request("DISABLE")
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        dev[0].flush_scan_cache()
+        dev[1].flush_scan_cache()
+
+def test_ap_open_tdls_vht80plus80(dev, apdev):
+    """Open AP and two stations using TDLS with VHT 80+80"""
+    params = { "ssid": "test-open",
+               "country_code": "US",
+               "hw_mode": "a",
+               "channel": "36",
+               "ht_capab": "[HT40+]",
+               "ieee80211n": "1",
+               "ieee80211ac": "1",
+               "vht_capab": "",
+               "vht_oper_chwidth": "3",
+               "vht_oper_centr_freq_seg0_idx": "42",
+               "vht_oper_centr_freq_seg1_idx": "155" }
     try:
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-        wlantest_setup()
+        hapd = None
+        hapd = hostapd.add_ap(apdev[0], params)
+        wlantest_setup(hapd)
         connect_2sta_open(dev, hapd, scan_freq="5180")
-        setup_tdls(dev[0], dev[1], apdev[0])
-        teardown_tdls(dev[0], dev[1], apdev[0])
-        setup_tdls(dev[1], dev[0], apdev[0])
-        teardown_tdls(dev[1], dev[0], apdev[0], wildcard=True)
+        sig = dev[0].request("SIGNAL_POLL").splitlines()
+        if "FREQUENCY=5180" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
+        if "WIDTH=80+80 MHz" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
+        if "CENTER_FRQ1=5210" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(3): " + str(sig))
+        if "CENTER_FRQ2=5775" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(4): " + str(sig))
+        setup_tdls(dev[0], dev[1], hapd)
+        for i in range(10):
+            check_connectivity(dev[0], dev[1], hapd)
+        for i in range(2):
+            cmd = subprocess.Popen(['iw', dev[0].ifname, 'station', 'dump'],
+                                   stdout=subprocess.PIPE)
+            res = cmd.stdout.read()
+            cmd.stdout.close()
+            logger.info("Station dump on dev[%d]:\n%s" % (i, res))
+    except Exception, e:
+        if isinstance(e, Exception) and str(e) == "AP startup failed":
+            if not vht_supported():
+                raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
+        raise
+    finally:
+        dev[0].request("DISCONNECT")
+        dev[1].request("DISCONNECT")
+        if hapd:
+            hapd.request("DISABLE")
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        dev[0].flush_scan_cache()
+        dev[1].flush_scan_cache()
+
+def test_ap_open_tdls_vht160(dev, apdev):
+    """Open AP and two stations using TDLS with VHT 160"""
+    params = { "ssid": "test-open",
+               "country_code": "ZA",
+               "hw_mode": "a",
+               "channel": "104",
+               "ht_capab": "[HT40-]",
+               "ieee80211n": "1",
+               "ieee80211ac": "1",
+               "vht_oper_chwidth": "2",
+               "vht_oper_centr_freq_seg0_idx": "114" }
+    try:
+        hapd = None
+        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
+        ev = hapd.wait_event(["AP-ENABLED"], timeout=2)
+        if not ev:
+            cmd = subprocess.Popen(["iw", "reg", "get"], stdout=subprocess.PIPE)
+            reg = cmd.stdout.readlines()
+            for r in reg:
+                if "5490" in r and "DFS" in r:
+                    raise HwsimSkip("ZA regulatory rule did not have DFS requirement removed")
+            raise Exception("AP setup timed out")
+        wlantest_setup(hapd)
+        connect_2sta_open(dev, hapd, scan_freq="5520")
+        sig = dev[0].request("SIGNAL_POLL").splitlines()
+        if "WIDTH=160 MHz" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
+        setup_tdls(dev[0], dev[1], hapd)
+        for i in range(10):
+            check_connectivity(dev[0], dev[1], hapd)
+        for i in range(2):
+            cmd = subprocess.Popen(['iw', dev[0].ifname, 'station', 'dump'],
+                                   stdout=subprocess.PIPE)
+            res = cmd.stdout.read()
+            cmd.stdout.close()
+            logger.info("Station dump on dev[%d]:\n%s" % (i, res))
+    except Exception, e:
+        if isinstance(e, Exception) and str(e) == "AP startup failed":
+            if not vht_supported():
+                raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
+        raise
     finally:
         dev[0].request("DISCONNECT")
         dev[1].request("DISCONNECT")
@@ -384,9 +530,10 @@ def test_tdls_chan_switch(dev, apdev):
     if flags & 0x800000000 == 0:
         raise HwsimSkip("Driver does not support TDLS channel switching")
 
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-open" })
+    wlantest_setup(hapd)
     connect_2sta_open(dev, hapd)
-    setup_tdls(dev[0], dev[1], apdev[0])
+    setup_tdls(dev[0], dev[1], hapd)
     if "OK" not in dev[0].request("TDLS_CHAN_SWITCH " + dev[1].own_addr() + " 81 2462"):
         raise Exception("Failed to enable TDLS channel switching")
     if "OK" not in dev[0].request("TDLS_CANCEL_CHAN_SWITCH " + dev[1].own_addr()):
@@ -396,13 +543,13 @@ def test_tdls_chan_switch(dev, apdev):
 
 def test_ap_tdls_link_status(dev, apdev):
     """Check TDLS link status between two stations"""
-    hapd = start_ap_wpa2_psk(apdev[0]['ifname'])
-    wlantest_setup()
+    hapd = start_ap_wpa2_psk(apdev[0])
+    wlantest_setup(hapd)
     connect_2sta_wpa2_psk(dev, hapd)
     check_tdls_link(dev[0], dev[1], connected=False)
-    setup_tdls(dev[0], dev[1], apdev[0])
+    setup_tdls(dev[0], dev[1], hapd)
     check_tdls_link(dev[0], dev[1], connected=True)
-    teardown_tdls(dev[0], dev[1], apdev[0])
+    teardown_tdls(dev[0], dev[1], hapd)
     check_tdls_link(dev[0], dev[1], connected=False)
     if "FAIL" not in dev[0].request("TDLS_LINK_STATUS foo"):
         raise Exception("Unexpected TDLS_LINK_STATUS response for invalid argument")
index 5ca2b60..75664a4 100644 (file)
@@ -25,7 +25,7 @@ def _test_ap_track_sta(dev, apdev):
                "hw_mode": "g",
                "channel": "6",
                "track_sta_max_num": "2" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
 
     params = { "ssid": "track",
@@ -34,7 +34,7 @@ def _test_ap_track_sta(dev, apdev):
                "channel": "40",
                "track_sta_max_num": "100",
                "track_sta_max_age": "1" }
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd2 = hostapd.add_ap(apdev[1], params)
     bssid2 = apdev[1]['bssid']
 
     for i in range(2):
@@ -94,7 +94,7 @@ def _test_ap_track_sta_no_probe_resp(dev, apdev):
                "channel": "6",
                "beacon_int": "10000",
                "no_probe_resp_if_seen_on": apdev[1]['ifname'] }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
 
     params = { "ssid": "track",
@@ -102,7 +102,7 @@ def _test_ap_track_sta_no_probe_resp(dev, apdev):
                "hw_mode": "a",
                "channel": "40",
                "track_sta_max_num": "100" }
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd2 = hostapd.add_ap(apdev[1], params)
     bssid2 = apdev[1]['bssid']
 
     dev[0].scan_for_bss(bssid2, freq=5200, force_scan=True)
@@ -127,7 +127,7 @@ def _test_ap_track_sta_no_auth(dev, apdev):
                "channel": "6",
                "track_sta_max_num": "100",
                "no_auth_if_seen_on": apdev[1]['ifname'] }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
 
     params = { "ssid": "track",
@@ -135,7 +135,7 @@ def _test_ap_track_sta_no_auth(dev, apdev):
                "hw_mode": "a",
                "channel": "40",
                "track_sta_max_num": "100" }
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd2 = hostapd.add_ap(apdev[1], params)
     bssid2 = apdev[1]['bssid']
 
     dev[0].scan_for_bss(bssid, freq=2437, force_scan=True)
@@ -174,7 +174,7 @@ def _test_ap_track_sta_no_auth_passive(dev, apdev):
                "hw_mode": "g",
                "channel": "6",
                "no_auth_if_seen_on": apdev[1]['ifname'] }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
 
     params = { "ssid": "track",
@@ -184,7 +184,7 @@ def _test_ap_track_sta_no_auth_passive(dev, apdev):
                "interworking": "1",
                "venue_name": "eng:Venue",
                "track_sta_max_num": "100" }
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd2 = hostapd.add_ap(apdev[1], params)
     bssid2 = apdev[1]['bssid']
 
     dev[0].scan_for_bss(bssid, freq=2437, force_scan=True)
@@ -230,7 +230,7 @@ def _test_ap_track_sta_force_5ghz(dev, apdev):
                "channel": "6",
                "no_probe_resp_if_seen_on": apdev[1]['ifname'],
                "no_auth_if_seen_on": apdev[1]['ifname'] }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
 
     params = { "ssid": "track",
@@ -238,7 +238,7 @@ def _test_ap_track_sta_force_5ghz(dev, apdev):
                "hw_mode": "a",
                "channel": "40",
                "track_sta_max_num": "100" }
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd2 = hostapd.add_ap(apdev[1], params)
     bssid2 = apdev[1]['bssid']
 
     dev[0].scan_for_bss(bssid, freq=2437, force_scan=True)
@@ -263,7 +263,7 @@ def _test_ap_track_sta_force_2ghz(dev, apdev):
                "hw_mode": "g",
                "channel": "6",
                "track_sta_max_num": "100" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
 
     params = { "ssid": "track",
@@ -272,7 +272,7 @@ def _test_ap_track_sta_force_2ghz(dev, apdev):
                "channel": "40",
                "no_probe_resp_if_seen_on": apdev[0]['ifname'],
                "no_auth_if_seen_on": apdev[0]['ifname'] }
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd2 = hostapd.add_ap(apdev[1], params)
     bssid2 = apdev[1]['bssid']
 
     dev[0].scan_for_bss(bssid2, freq=5200, force_scan=True)
@@ -283,3 +283,111 @@ def _test_ap_track_sta_force_2ghz(dev, apdev):
     if freq != '2437':
         raise Exception("Unexpected operating channel")
     dev[0].request("DISCONNECT")
+
+def test_ap_track_taxonomy(dev, apdev):
+    """AP tracking STA taxonomy"""
+    try:
+        _test_ap_track_taxonomy(dev, apdev)
+    finally:
+        dev[1].request("SET p2p_disabled 0")
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        dev[0].flush_scan_cache()
+        dev[1].flush_scan_cache()
+        dev[2].flush_scan_cache()
+
+def _test_ap_track_taxonomy(dev, apdev):
+    params = { "ssid": "track",
+               "country_code": "US",
+               "hw_mode": "g",
+               "channel": "6",
+               "track_sta_max_num": "2" }
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+
+    dev[0].scan_for_bss(bssid, freq=2437, force_scan=True)
+    addr0 = dev[0].own_addr()
+    dev[0].connect("track", key_mgmt="NONE", scan_freq="2437")
+
+    dev[1].request("SET p2p_disabled 1")
+    dev[1].scan_for_bss(bssid, freq=2437, force_scan=True)
+    addr1 = dev[1].own_addr()
+    dev[1].connect("track", key_mgmt="NONE", scan_freq="2437")
+
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    wpas.interface_add("wlan5")
+    wpas.request("SET model_name track test")
+    wpas.scan_for_bss(bssid, freq=2437, force_scan=True)
+    addr = wpas.own_addr()
+    wpas.connect("track", key_mgmt="NONE", scan_freq="2437")
+
+    if "FAIL" not in hapd.request("SIGNATURE abc"):
+        raise Exception("SIGNATURE failure not reported (1)")
+    if "FAIL" not in hapd.request("SIGNATURE 22:33:44:55:66:77"):
+        raise Exception("SIGNATURE failure not reported (2)")
+
+    res = hapd.request("SIGNATURE " + addr0)
+    logger.info("sta0: " + res)
+    if not res.startswith("wifi4|probe:"):
+        raise Exception("Unexpected SIGNATURE prefix")
+    if "|assoc:" not in res:
+        raise Exception("Missing assoc info in SIGNATURE")
+    if "wps:track_test" in res:
+        raise Exception("Unexpected WPS model name")
+
+    res = hapd.request("SIGNATURE " + addr1)
+    logger.info("sta1: " + res)
+    if not res.startswith("wifi4|probe:"):
+        raise Exception("Unexpected SIGNATURE prefix")
+    if "|assoc:" not in res:
+        raise Exception("Missing assoc info in SIGNATURE")
+    if "wps:" in res:
+        raise Exception("Unexpected WPS info");
+    if ",221(0050f2,4)," in res:
+        raise Exception("Unexpected WPS IE info");
+    if ",221(506f9a,9)," in res:
+        raise Exception("Unexpected P2P IE info");
+
+    res = hapd.request("SIGNATURE " + addr)
+    logger.info("sta: " + res)
+    if not res.startswith("wifi4|probe:"):
+        raise Exception("Unexpected SIGNATURE prefix")
+    if "|assoc:" not in res:
+        raise Exception("Missing assoc info in SIGNATURE")
+    if "wps:track_test" not in res:
+        raise Exception("Missing WPS model name")
+    if ",221(0050f2,4)," not in res:
+        raise Exception("Missing WPS IE info");
+    if ",221(506f9a,9)," not in res:
+        raise Exception("Missing P2P IE info");
+
+    addr2 = dev[2].own_addr()
+    res = hapd.request("SIGNATURE " + addr2)
+    if "FAIL" not in res:
+        raise Exception("Unexpected SIGNATURE success for sta2 (1)")
+
+    for i in range(10):
+        dev[2].request("SCAN freq=2437 passive=1")
+        ev = dev[2].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10)
+        if ev is None:
+            raise Exception("Scan did not complete")
+        if dev[2].get_bss(bssid):
+            break
+
+    res = hapd.request("SIGNATURE " + addr2)
+    if "FAIL" not in res:
+        raise Exception("Unexpected SIGNATURE success for sta2 (2)")
+
+    dev[2].connect("track", key_mgmt="NONE", scan_freq="2437")
+
+    res = hapd.request("SIGNATURE " + addr2)
+    if "FAIL" not in res and len(res) > 0:
+        raise Exception("Unexpected SIGNATURE success for sta2 (3)")
+
+    dev[2].scan_for_bss(bssid, freq=2437, force_scan=True)
+
+    res = hapd.request("SIGNATURE " + addr2)
+    logger.info("sta2: " + res)
+    if not res.startswith("wifi4|probe:"):
+        raise Exception("Unexpected SIGNATURE prefix")
+    if "|assoc:" not in res:
+        raise Exception("Missing assoc info in SIGNATURE")
index d883114..9ecf8d1 100644 (file)
@@ -15,6 +15,7 @@ import hostapd
 from utils import HwsimSkip
 from test_dfs import wait_dfs_event
 from test_ap_csa import csa_supported
+from test_ap_ht import clear_scan_cache
 
 def vht_supported():
     cmd = subprocess.Popen(["iw", "reg", "get"], stdout=subprocess.PIPE)
@@ -36,14 +37,31 @@ def test_ap_vht80(dev, apdev):
                    "ieee80211ac": "1",
                    "vht_oper_chwidth": "1",
                    "vht_oper_centr_freq_seg0_idx": "42" }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
         bssid = apdev[0]['bssid']
 
         dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
         hwsim_utils.test_connectivity(dev[0], hapd)
+        sig = dev[0].request("SIGNAL_POLL").splitlines()
+        if "FREQUENCY=5180" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
+        if "WIDTH=80 MHz" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
         est = dev[0].get_bss(bssid)['est_throughput']
         if est != "390001":
             raise Exception("Unexpected BSS est_throughput: " + est)
+        status = hapd.get_status()
+        logger.info("hostapd STATUS: " + str(status))
+        if status["ieee80211n"] != "1":
+            raise Exception("Unexpected STATUS ieee80211n value")
+        if status["ieee80211ac"] != "1":
+            raise Exception("Unexpected STATUS ieee80211ac value")
+        if status["secondary_channel"] != "1":
+            raise Exception("Unexpected STATUS secondary_channel value")
+        if status["vht_oper_chwidth"] != "1":
+            raise Exception("Unexpected STATUS vht_oper_chwidth value")
+        if status["vht_oper_centr_freq_seg0_idx"] != "42":
+            raise Exception("Unexpected STATUS vht_oper_centr_freq_seg0_idx value")
     except Exception, e:
         if isinstance(e, Exception) and str(e) == "AP startup failed":
             if not vht_supported():
@@ -57,6 +75,7 @@ def test_ap_vht80(dev, apdev):
         dev[0].flush_scan_cache()
 
 def vht80_test(apdev, dev, channel, ht_capab):
+    clear_scan_cache(apdev)
     try:
         hapd = None
         params = { "ssid": "vht",
@@ -68,7 +87,7 @@ def vht80_test(apdev, dev, channel, ht_capab):
                    "ieee80211ac": "1",
                    "vht_oper_chwidth": "1",
                    "vht_oper_centr_freq_seg0_idx": "42" }
-        hapd = hostapd.add_ap(apdev['ifname'], params)
+        hapd = hostapd.add_ap(apdev, params)
         bssid = apdev['bssid']
 
         dev.connect("vht", key_mgmt="NONE", scan_freq=str(5000 + 5 * channel))
@@ -112,7 +131,7 @@ def test_ap_vht80_params(dev, apdev):
                    "vht_capab": "[MAX-MPDU-11454][RXLDPC][SHORT-GI-80][TX-STBC-2BY1][RX-STBC-1][MAX-A-MPDU-LEN-EXP0]",
                    "vht_oper_centr_freq_seg0_idx": "42",
                    "require_vht": "1" }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
 
         dev[1].connect("vht", key_mgmt="NONE", scan_freq="5180",
                        disable_vht="1", wait_connect=False)
@@ -138,6 +157,67 @@ def test_ap_vht80_params(dev, apdev):
         dev[0].flush_scan_cache()
         dev[1].flush_scan_cache()
 
+def test_ap_vht80_invalid(dev, apdev):
+    """VHT with invalid 80 MHz channel configuration (seg1)"""
+    try:
+        hapd = None
+        params = { "ssid": "vht",
+                   "country_code": "US",
+                   "hw_mode": "a",
+                   "channel": "36",
+                   "ht_capab": "[HT40+]",
+                   "ieee80211n": "1",
+                   "ieee80211ac": "1",
+                   "vht_oper_chwidth": "1",
+                   "vht_oper_centr_freq_seg0_idx": "42",
+                   "vht_oper_centr_freq_seg1_idx": "155",
+                   'ieee80211d': '1',
+                   'ieee80211h': '1' }
+        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
+        # This fails due to unexpected seg1 configuration
+        ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
+        if ev is None:
+            raise Exception("AP-DISABLED not reported")
+    except Exception, e:
+        if isinstance(e, Exception) and str(e) == "AP startup failed":
+            if not vht_supported():
+                raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
+        raise
+    finally:
+        if hapd:
+            hapd.request("DISABLE")
+        subprocess.call(['iw', 'reg', 'set', '00'])
+
+def test_ap_vht80_invalid2(dev, apdev):
+    """VHT with invalid 80 MHz channel configuration (seg0)"""
+    try:
+        hapd = None
+        params = { "ssid": "vht",
+                   "country_code": "US",
+                   "hw_mode": "a",
+                   "channel": "36",
+                   "ht_capab": "[HT40+]",
+                   "ieee80211n": "1",
+                   "ieee80211ac": "1",
+                   "vht_oper_chwidth": "1",
+                   "vht_oper_centr_freq_seg0_idx": "46",
+                   'ieee80211d': '1',
+                   'ieee80211h': '1' }
+        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
+        # This fails due to invalid seg0 configuration
+        ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
+        if ev is None:
+            raise Exception("AP-DISABLED not reported")
+    except Exception, e:
+        if isinstance(e, Exception) and str(e) == "AP startup failed":
+            if not vht_supported():
+                raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
+        raise
+    finally:
+        if hapd:
+            hapd.request("DISABLE")
+        subprocess.call(['iw', 'reg', 'set', '00'])
+
 def test_ap_vht_20(devs, apdevs):
     """VHT and 20 MHz channel"""
     dev = devs[0]
@@ -157,7 +237,7 @@ def test_ap_vht_20(devs, apdevs):
                    "supported_rates": "60 120 240 360 480 540",
                    "require_vht": "1",
                  }
-        hapd = hostapd.add_ap(ap['ifname'], params)
+        hapd = hostapd.add_ap(ap, params)
         dev.connect("test-vht20", scan_freq="5180", key_mgmt="NONE")
         hwsim_utils.test_connectivity(dev, hapd)
     finally:
@@ -184,7 +264,7 @@ def test_ap_vht_40(devs, apdevs):
                    "vht_oper_chwidth": "0",
                    "vht_oper_centr_freq_seg0_idx": "0",
                  }
-        hapd = hostapd.add_ap(ap['ifname'], params)
+        hapd = hostapd.add_ap(ap, params)
         dev.connect("test-vht40", scan_freq="5180", key_mgmt="NONE")
         hwsim_utils.test_connectivity(dev, hapd)
     finally:
@@ -208,7 +288,7 @@ def test_ap_vht_capab_not_supported(dev, apdev):
                    "vht_capab": "[MAX-MPDU-7991][MAX-MPDU-11454][VHT160][VHT160-80PLUS80][RXLDPC][SHORT-GI-80][SHORT-GI-160][TX-STBC-2BY1][RX-STBC-1][RX-STBC-12][RX-STBC-123][RX-STBC-1234][SU-BEAMFORMER][SU-BEAMFORMEE][BF-ANTENNA-2][BF-ANTENNA-3][BF-ANTENNA-4][SOUNDING-DIMENSION-2][SOUNDING-DIMENSION-3][SOUNDING-DIMENSION-4][MU-BEAMFORMER][VHT-TXOP-PS][HTC-VHT][MAX-A-MPDU-LEN-EXP0][MAX-A-MPDU-LEN-EXP7][VHT-LINK-ADAPT2][VHT-LINK-ADAPT3][RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN]",
                    "vht_oper_centr_freq_seg0_idx": "42",
                    "require_vht": "1" }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
         ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
         if ev is None:
             raise Exception("Startup failure not reported")
@@ -234,7 +314,7 @@ def test_ap_vht160(dev, apdev):
                    "vht_oper_centr_freq_seg0_idx": "50",
                    'ieee80211d': '1',
                    'ieee80211h': '1' }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
 
         ev = wait_dfs_event(hapd, "DFS-CAC-START", 5)
         if "DFS-CAC-START" not in ev:
@@ -260,7 +340,7 @@ def test_ap_vht160(dev, apdev):
                    "vht_oper_centr_freq_seg0_idx": "114",
                    'ieee80211d': '1',
                    'ieee80211h': '1' }
-        hapd2 = hostapd.add_ap(apdev[1]['ifname'], params, wait_enabled=False)
+        hapd2 = hostapd.add_ap(apdev[1], params, wait_enabled=False)
 
         ev = wait_dfs_event(hapd2, "DFS-CAC-START", 5)
         if "DFS-CAC-START" not in ev:
@@ -334,6 +414,50 @@ def test_ap_vht160(dev, apdev):
         dev[0].flush_scan_cache()
         dev[1].flush_scan_cache()
 
+def test_ap_vht160_no_dfs(dev, apdev):
+    """VHT with 160 MHz channel width and no DFS"""
+    try:
+        hapd = None
+        params = { "ssid": "vht",
+                   "country_code": "ZA",
+                   "hw_mode": "a",
+                   "channel": "104",
+                   "ht_capab": "[HT40-]",
+                   "ieee80211n": "1",
+                   "ieee80211ac": "1",
+                   "vht_oper_chwidth": "2",
+                   "vht_oper_centr_freq_seg0_idx": "114",
+                   'ieee80211d': '1',
+                   'ieee80211h': '1' }
+        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
+        ev = hapd.wait_event(["AP-ENABLED"], timeout=2)
+        if not ev:
+            cmd = subprocess.Popen(["iw", "reg", "get"], stdout=subprocess.PIPE)
+            reg = cmd.stdout.readlines()
+            for r in reg:
+                if "5490" in r and "DFS" in r:
+                    raise HwsimSkip("ZA regulatory rule did not have DFS requirement removed")
+            raise Exception("AP setup timed out")
+
+        dev[0].connect("vht", key_mgmt="NONE", scan_freq="5520")
+        hwsim_utils.test_connectivity(dev[0], hapd)
+        sig = dev[0].request("SIGNAL_POLL").splitlines()
+        if "FREQUENCY=5520" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
+        if "WIDTH=160 MHz" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
+    except Exception, e:
+        if isinstance(e, Exception) and str(e) == "AP startup failed":
+            if not vht_supported():
+                raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
+        raise
+    finally:
+        dev[0].request("DISCONNECT")
+        if hapd:
+            hapd.request("DISABLE")
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        dev[0].flush_scan_cache()
+
 def test_ap_vht80plus80(dev, apdev):
     """VHT with 80+80 MHz channel width"""
     try:
@@ -351,7 +475,7 @@ def test_ap_vht80plus80(dev, apdev):
                    "vht_oper_centr_freq_seg1_idx": "155",
                    'ieee80211d': '1',
                    'ieee80211h': '1' }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
+        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
         # This will actually fail since DFS on 80+80 is not yet supported
         ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
         # ignore result to avoid breaking the test once 80+80 DFS gets enabled
@@ -366,7 +490,7 @@ def test_ap_vht80plus80(dev, apdev):
                    "vht_oper_chwidth": "3",
                    "vht_oper_centr_freq_seg0_idx": "42",
                    "vht_oper_centr_freq_seg1_idx": "155" }
-        hapd2 = hostapd.add_ap(apdev[1]['ifname'], params, wait_enabled=False)
+        hapd2 = hostapd.add_ap(apdev[1], params, wait_enabled=False)
 
         ev = hapd2.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=5)
         if not ev:
@@ -406,6 +530,37 @@ def test_ap_vht80plus80(dev, apdev):
         dev[0].flush_scan_cache()
         dev[1].flush_scan_cache()
 
+def test_ap_vht80plus80_invalid(dev, apdev):
+    """VHT with invalid 80+80 MHz channel"""
+    try:
+        hapd = None
+        params = { "ssid": "vht",
+                   "country_code": "US",
+                   "hw_mode": "a",
+                   "channel": "36",
+                   "ht_capab": "[HT40+]",
+                   "ieee80211n": "1",
+                   "ieee80211ac": "1",
+                   "vht_oper_chwidth": "3",
+                   "vht_oper_centr_freq_seg0_idx": "42",
+                   "vht_oper_centr_freq_seg1_idx": "0",
+                   'ieee80211d': '1',
+                   'ieee80211h': '1' }
+        hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
+        # This fails due to missing(invalid) seg1 configuration
+        ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
+        if ev is None:
+            raise Exception("AP-DISABLED not reported")
+    except Exception, e:
+        if isinstance(e, Exception) and str(e) == "AP startup failed":
+            if not vht_supported():
+                raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
+        raise
+    finally:
+        if hapd:
+            hapd.request("DISABLE")
+        subprocess.call(['iw', 'reg', 'set', '00'])
+
 def test_ap_vht80_csa(dev, apdev):
     """VHT with 80 MHz channel width and CSA"""
     csa_supported(dev[0])
@@ -420,7 +575,7 @@ def test_ap_vht80_csa(dev, apdev):
                    "ieee80211ac": "1",
                    "vht_oper_chwidth": "1",
                    "vht_oper_centr_freq_seg0_idx": "155" }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
 
         dev[0].connect("vht", key_mgmt="NONE", scan_freq="5745")
         hwsim_utils.test_connectivity(dev[0], hapd)
@@ -471,7 +626,7 @@ def test_ap_vht_on_24ghz(dev, apdev):
                "vht_oper_chwidth": "0",
                "vht_oper_centr_freq_seg0_idx": "1"
     }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     try:
         if "OK" not in dev[0].request("VENDOR_ELEM_ADD 13 dd1300904c0400bf0c3240820feaff0000eaff0000"):
             raise Exception("Failed to add vendor element")
@@ -499,7 +654,7 @@ def test_prefer_vht40(dev, apdev):
                    "channel": "36",
                    "ieee80211n": "1",
                    "ht_capab": "[HT40+]" }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
         bssid = apdev[0]['bssid']
 
         params = { "ssid": "test",
@@ -513,7 +668,7 @@ def test_prefer_vht40(dev, apdev):
                    "vht_oper_chwidth": "0",
                    "vht_oper_centr_freq_seg0_idx": "0",
                  }
-        hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+        hapd2 = hostapd.add_ap(apdev[1], params)
         bssid2 = apdev[1]['bssid']
 
         dev[0].scan_for_bss(bssid, freq=5180)
@@ -535,3 +690,64 @@ def test_prefer_vht40(dev, apdev):
             hapd2.request("DISABLE")
         subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
+
+def test_ap_vht80_pwr_constraint(dev, apdev):
+    """VHT with 80 MHz channel width and local power constraint"""
+    hapd = None
+    try:
+        params = { "ssid": "vht",
+                   "country_code": "FI",
+                   "hw_mode": "a",
+                   "channel": "36",
+                   "ht_capab": "[HT40+]",
+                   "ieee80211d": "1",
+                   "local_pwr_constraint": "3",
+                   "ieee80211n": "1",
+                   "ieee80211ac": "1",
+                   "vht_oper_chwidth": "1",
+                   "vht_oper_centr_freq_seg0_idx": "42" }
+        hapd = hostapd.add_ap(apdev[0], params)
+
+        dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
+    except Exception, e:
+        if isinstance(e, Exception) and str(e) == "AP startup failed":
+            if not vht_supported():
+                raise HwsimSkip("80 MHz channel not supported in regulatory information")
+        raise
+    finally:
+        dev[0].request("DISCONNECT")
+        if hapd:
+            hapd.request("DISABLE")
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        dev[0].flush_scan_cache()
+
+def test_ap_vht_use_sta_nsts(dev, apdev):
+    """VHT with 80 MHz channel width and use_sta_nsts=1"""
+    try:
+        hapd = None
+        params = { "ssid": "vht",
+                   "country_code": "FI",
+                   "hw_mode": "a",
+                   "channel": "36",
+                   "ht_capab": "[HT40+]",
+                   "ieee80211n": "1",
+                   "ieee80211ac": "1",
+                   "vht_oper_chwidth": "1",
+                   "vht_oper_centr_freq_seg0_idx": "42",
+                   "use_sta_nsts": "1" }
+        hapd = hostapd.add_ap(apdev[0], params)
+        bssid = apdev[0]['bssid']
+
+        dev[0].connect("vht", key_mgmt="NONE", scan_freq="5180")
+        hwsim_utils.test_connectivity(dev[0], hapd)
+    except Exception, e:
+        if isinstance(e, Exception) and str(e) == "AP startup failed":
+            if not vht_supported():
+                raise HwsimSkip("80 MHz channel not supported in regulatory information")
+        raise
+    finally:
+        dev[0].request("DISCONNECT")
+        if hapd:
+            hapd.request("DISABLE")
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        dev[0].flush_scan_cache()
index 822bf99..21ddbfb 100644 (file)
@@ -6,6 +6,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import time
 import subprocess
 import logging
@@ -20,13 +21,15 @@ except ImportError:
 import hwsim_utils
 import hostapd
 from utils import iface_is_in_bridge, HwsimSkip
+import os
+from tshark import run_tshark
 
 def test_ap_vlan_open(dev, apdev):
     """AP VLAN with open network"""
     params = { "ssid": "test-vlan-open",
                "dynamic_vlan": "1",
                "accept_mac_file": "hostapd.accept" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-vlan-open", key_mgmt="NONE", scan_freq="2412")
     dev[1].connect("test-vlan-open", key_mgmt="NONE", scan_freq="2412")
@@ -41,7 +44,7 @@ def test_ap_vlan_file_open(dev, apdev):
                "dynamic_vlan": "1",
                "vlan_file": "hostapd.vlan",
                "accept_mac_file": "hostapd.accept" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-vlan-open", key_mgmt="NONE", scan_freq="2412")
     dev[1].connect("test-vlan-open", key_mgmt="NONE", scan_freq="2412")
@@ -54,9 +57,9 @@ def test_ap_vlan_wpa2(dev, apdev):
     """AP VLAN with WPA2-PSK"""
     params = hostapd.wpa2_params(ssid="test-vlan",
                                  passphrase="12345678")
-    params['dynamic_vlan'] = "1";
-    params['accept_mac_file'] = "hostapd.accept";
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    params['dynamic_vlan'] = "1"
+    params['accept_mac_file'] = "hostapd.accept"
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-vlan", psk="12345678", scan_freq="2412")
     dev[1].connect("test-vlan", psk="12345678", scan_freq="2412")
@@ -68,8 +71,8 @@ def test_ap_vlan_wpa2(dev, apdev):
 def test_ap_vlan_wpa2_radius(dev, apdev):
     """AP VLAN with WPA2-Enterprise and RADIUS attributes"""
     params = hostapd.wpa2_eap_params(ssid="test-vlan")
-    params['dynamic_vlan'] = "1";
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    params['dynamic_vlan'] = "1"
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-vlan", key_mgmt="WPA-EAP", eap="PAX",
                    identity="vlan1",
@@ -87,8 +90,45 @@ def test_ap_vlan_wpa2_radius(dev, apdev):
     hwsim_utils.test_connectivity_iface(dev[1], hapd, "brvlan2")
     hwsim_utils.test_connectivity(dev[2], hapd)
 
+def test_ap_vlan_wpa2_radius_2(dev, apdev):
+    """AP VLAN with WPA2-Enterprise and RADIUS EGRESS_VLANID attributes"""
+    params = hostapd.wpa2_eap_params(ssid="test-vlan")
+    params['dynamic_vlan'] = "1"
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].connect("test-vlan", key_mgmt="WPA-EAP", eap="PAX",
+                   identity="vlan1b",
+                   password_hex="0123456789abcdef0123456789abcdef",
+                   scan_freq="2412")
+
+    hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan1")
+
 def test_ap_vlan_wpa2_radius_id_change(dev, apdev):
     """AP VLAN with WPA2-Enterprise and RADIUS attributes changing VLANID"""
+    generic_ap_vlan_wpa2_radius_id_change(dev, apdev, False)
+
+def test_ap_vlan_tagged_wpa2_radius_id_change(dev, apdev):
+    """AP tagged VLAN with WPA2-Enterprise and RADIUS attributes changing VLANID"""
+    ifname1 = 'wlan0.1'
+    ifname2 = 'wlan0.2'
+    try:
+        # Create tagged interface for wpa_supplicant
+        subprocess.call(['ip', 'link', 'add', 'link', dev[0].ifname,
+                         'name', ifname1, 'type', 'vlan', 'id', '1'])
+        subprocess.call(['ifconfig', ifname1, 'up'])
+
+        subprocess.call(['ip', 'link', 'add', 'link', dev[0].ifname,
+                         'name', ifname2, 'type', 'vlan', 'id', '2'])
+        subprocess.call(['ifconfig', ifname2, 'up'])
+
+        generic_ap_vlan_wpa2_radius_id_change(dev, apdev, True)
+    finally:
+        subprocess.call(['ifconfig', ifname1, 'down'])
+        subprocess.call(['ifconfig', ifname2, 'down'])
+        subprocess.call(['ip', 'link', 'del', ifname1])
+        subprocess.call(['ip', 'link', 'del', ifname2])
+
+def generic_ap_vlan_wpa2_radius_id_change(dev, apdev, tagged):
     as_params = { "ssid": "as",
                   "beacon_int": "2000",
                   "radius_server_clients": "auth_serv/radius_clients.conf",
@@ -98,18 +138,24 @@ def test_ap_vlan_wpa2_radius_id_change(dev, apdev):
                   "ca_cert": "auth_serv/ca.pem",
                   "server_cert": "auth_serv/server.pem",
                   "private_key": "auth_serv/server.key" }
-    authserv = hostapd.add_ap(apdev[1]['ifname'], as_params)
+    authserv = hostapd.add_ap(apdev[1], as_params)
 
     params = hostapd.wpa2_eap_params(ssid="test-vlan")
-    params['dynamic_vlan'] = "1";
+    params['dynamic_vlan'] = "1"
     params['auth_server_port'] = "18128"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    identity = "vlan1tagged" if tagged else "vlan1"
 
     dev[0].connect("test-vlan", key_mgmt="WPA-EAP", eap="PAX",
-                   identity="vlan1",
+                   identity=identity,
                    password_hex="0123456789abcdef0123456789abcdef",
                    scan_freq="2412")
-    hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan1")
+    if tagged:
+        hwsim_utils.run_connectivity_test(dev[0], hapd, 0, ifname1="wlan0.1",
+                                          ifname2="brvlan1")
+    else:
+        hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan1")
 
     logger.info("VLAN-ID -> 2")
 
@@ -131,9 +177,13 @@ def test_ap_vlan_wpa2_radius_id_change(dev, apdev):
     sta = hapd.get_sta(dev[0].own_addr())
     if 'vlan_id' not in sta:
         raise Exception("No VLAN ID in STA info")
-    if sta['vlan_id'] != '2':
+    if (not tagged) and (sta['vlan_id'] != '2'):
         raise Exception("Unexpected VLAN ID: " + sta['vlan_id'])
-    hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan2")
+    if tagged:
+        hwsim_utils.run_connectivity_test(dev[0], hapd, 0, ifname1="wlan0.2",
+                                          ifname2="brvlan2")
+    else:
+        hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan2")
 
     logger.info("VLAN-ID -> 1")
     time.sleep(1)
@@ -156,22 +206,32 @@ def test_ap_vlan_wpa2_radius_id_change(dev, apdev):
     sta = hapd.get_sta(dev[0].own_addr())
     if 'vlan_id' not in sta:
         raise Exception("No VLAN ID in STA info")
-    if sta['vlan_id'] != '1':
+    if (not tagged) and (sta['vlan_id'] != '1'):
         raise Exception("Unexpected VLAN ID: " + sta['vlan_id'])
     time.sleep(0.2)
     try:
-        hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan1")
+        if tagged:
+            hwsim_utils.run_connectivity_test(dev[0], hapd, 0,
+                                              ifname1="wlan0.1",
+                                              ifname2="brvlan1")
+        else:
+            hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan1")
     except Exception, e:
         # It is possible for new bridge setup to not be ready immediately, so
         # try again to avoid reporting issues related to that.
         logger.info("First VLAN-ID 1 data test failed - try again")
-        hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan1")
+        if tagged:
+            hwsim_utils.run_connectivity_test(dev[0], hapd, 0,
+                                              ifname1="wlan0.1",
+                                              ifname2="brvlan1")
+        else:
+            hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan1")
 
 def test_ap_vlan_wpa2_radius_required(dev, apdev):
     """AP VLAN with WPA2-Enterprise and RADIUS attributes required"""
     params = hostapd.wpa2_eap_params(ssid="test-vlan")
-    params['dynamic_vlan'] = "2";
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    params['dynamic_vlan'] = "2"
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-vlan", key_mgmt="WPA-EAP", eap="PAX",
                    identity="vlan1",
@@ -194,7 +254,7 @@ def test_ap_vlan_tagged(dev, apdev):
                "dynamic_vlan": "1",
                "vlan_tagged_interface": "lo",
                "accept_mac_file": "hostapd.accept" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-vlan-open", key_mgmt="NONE", scan_freq="2412")
     dev[1].connect("test-vlan-open", key_mgmt="NONE", scan_freq="2412")
@@ -242,7 +302,9 @@ def ap_vlan_iface_test_and_prepare_environ():
 
 def test_ap_vlan_iface_cleanup_multibss(dev, apdev):
     """AP VLAN operation in multi-BSS multi-VLAN case"""
+    ap_vlan_iface_cleanup_multibss(dev, apdev, 'multi-bss-iface.conf')
 
+def ap_vlan_iface_cleanup_multibss(dev, apdev, cfgfile):
     # AP VLAN with WPA2-Enterprise and RADIUS attributes changing VLANID
     # check that multiple bss do not interfere with each other with respect
     # to deletion of bridge and tagged interface.
@@ -264,13 +326,10 @@ def test_ap_vlan_iface_cleanup_multibss(dev, apdev):
                       "server_cert": "auth_serv/server.pem",
                       "private_key": "auth_serv/server.key",
                       "vlan_naming": "1" }
-        authserv = hostapd.add_ap(apdev[1]['ifname'], as_params)
-
-        ifname = apdev[0]['ifname']
+        authserv = hostapd.add_ap(apdev[1], as_params)
 
         # start the actual test
-        hostapd.add_iface(ifname, 'multi-bss-iface.conf')
-        hapd = hostapd.Hostapd(ifname)
+        hapd = hostapd.add_iface(apdev[0], cfgfile)
         hapd1 = hostapd.Hostapd("wlan3-2", 1)
         hapd1.enable()
 
@@ -382,3 +441,190 @@ def test_ap_vlan_iface_cleanup_multibss(dev, apdev):
         hapd.request("DISABLE")
     finally:
         ap_vlan_iface_cleanup_multibss_cleanup()
+
+def test_ap_vlan_iface_cleanup_multibss_per_sta_vif(dev, apdev):
+    """AP VLAN operation in multi-BSS multi-VLAN case with per-sta-vif set"""
+
+    # AP VLAN with WPA2-Enterprise and RADIUS attributes changing VLANID
+    # check that multiple bss do not interfere with each other with respect
+    # to deletion of bridge and tagged interface. per_sta_vif is enabled.
+    ap_vlan_iface_cleanup_multibss(dev, apdev,
+                                   'multi-bss-iface-per_sta_vif.conf')
+
+def test_ap_vlan_without_station(dev, apdev, p):
+    """AP VLAN with WPA2-PSK and no station"""
+    try:
+        subprocess.call(['brctl', 'addbr', 'brvlan1'])
+        subprocess.call(['brctl', 'setfd', 'brvlan1', '0'])
+        subprocess.call(['ifconfig', 'brvlan1', 'up'])
+        # use a passphrase wlantest does not know, so it cannot
+        # inject decrypted frames into pcap
+        params = hostapd.wpa2_params(ssid="test-vlan",
+                                     passphrase="12345678x")
+        params['dynamic_vlan'] = "1"
+        params['vlan_file'] = 'hostapd.wlan3.vlan'
+        params['accept_mac_file'] = "hostapd.accept"
+        hapd = hostapd.add_ap(apdev[0], params)
+
+        # inject some traffic
+        sa = hapd.own_addr()
+        da = "ff:ff:ff:ff:ff:00"
+        hapd.request('DATA_TEST_CONFIG 1 ifname=brvlan1')
+        hapd.request('DATA_TEST_TX {} {} 0'.format(da, sa))
+        hapd.request('DATA_TEST_CONFIG 0')
+        time.sleep(.1)
+
+        dev[0].connect("test-vlan", psk="12345678x", scan_freq="2412")
+
+        # inject some traffic
+        sa = hapd.own_addr()
+        da = "ff:ff:ff:ff:ff:01"
+        hapd.request('DATA_TEST_CONFIG 1 ifname=brvlan1')
+        hapd.request('DATA_TEST_TX {} {} 0'.format(da, sa))
+        hapd.request('DATA_TEST_CONFIG 0')
+
+        # let the AP send couple of Beacon frames
+        time.sleep(1)
+        out = run_tshark(os.path.join(p['logdir'], "hwsim0.pcapng"),
+                         "wlan.da == ff:ff:ff:ff:ff:00",
+                         ["wlan.fc.protected"])
+
+        if out is not None:
+            lines = out.splitlines()
+            if len(lines) < 1:
+                raise Exception("first frame not observed")
+            state = 1
+            for l in lines:
+                is_protected = int(l, 16)
+                if is_protected != 1:
+                    state = 0
+            if state != 1:
+                raise Exception("Broadcast packets were not encrypted when no station was connected")
+        else:
+            raise Exception("first frame not observed")
+
+        out = run_tshark(os.path.join(p['logdir'], "hwsim0.pcapng"),
+                         "wlan.da == ff:ff:ff:ff:ff:01",
+                         ["wlan.fc.protected"])
+
+        if out is not None:
+            lines = out.splitlines()
+            if len(lines) < 1:
+                raise Exception("second frame not observed")
+            state = 1
+            for l in lines:
+                is_protected = int(l, 16)
+                if is_protected != 1:
+                    state = 0
+            if state != 1:
+                raise Exception("Broadcast packets were not encrypted when station was connected")
+        else:
+            raise Exception("second frame not observed")
+
+        dev[0].request("DISCONNECT")
+        dev[0].wait_disconnected()
+
+    finally:
+        subprocess.call(['ip', 'link', 'set', 'dev', 'brvlan1', 'down'])
+        subprocess.call(['ip', 'link', 'set', 'dev', 'wlan3.1', 'down'],
+                        stderr=open('/dev/null', 'w'))
+        subprocess.call(['brctl', 'delif', 'brvlan1', 'wlan3.1'],
+                        stderr=open('/dev/null', 'w'))
+        subprocess.call(['brctl', 'delbr', 'brvlan1'])
+
+@remote_compatible
+def test_ap_open_per_sta_vif(dev, apdev):
+    """AP VLAN with open network"""
+    params = { "ssid": "test-vlan-open",
+               "per_sta_vif": "1" }
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].connect("test-vlan-open", key_mgmt="NONE", scan_freq="2412")
+    hwsim_utils.test_connectivity_iface(dev[0], hapd,
+                                        apdev[0]['ifname'] + ".4096")
+
+@remote_compatible
+def test_ap_vlan_open_per_sta_vif(dev, apdev):
+    """AP VLAN (dynamic) with open network"""
+    params = { "ssid": "test-vlan-open",
+               "per_sta_vif": "1",
+               "dynamic_vlan": "1" }
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].connect("test-vlan-open", key_mgmt="NONE", scan_freq="2412")
+    hwsim_utils.test_connectivity_iface(dev[0], hapd,
+                                        apdev[0]['ifname'] + ".4096")
+
+def test_ap_vlan_wpa2_radius_tagged(dev, apdev):
+    """AP VLAN with WPA2-Enterprise and RADIUS EGRESS_VLANID attributes"""
+    ifname = 'wlan0.1'
+    try:
+        params = hostapd.wpa2_eap_params(ssid="test-vlan")
+        params['dynamic_vlan'] = "1"
+        params["vlan_naming"] = "1"
+        hapd = hostapd.add_ap(apdev[0], params)
+
+        dev[0].connect("test-vlan", key_mgmt="WPA-EAP", eap="PAX",
+                       identity="vlan1tagged",
+                       password_hex="0123456789abcdef0123456789abcdef",
+                       scan_freq="2412")
+
+        # Create tagged interface for wpa_supplicant
+        subprocess.call(['ip', 'link', 'add', 'link', dev[0].ifname,
+                         'name', ifname, 'type', 'vlan', 'id', '1'])
+        subprocess.call(['ifconfig', ifname, 'up'])
+
+        hwsim_utils.run_connectivity_test(dev[0], hapd, 0, ifname1=ifname,
+                                          ifname2="brvlan1")
+    finally:
+        subprocess.call(['ifconfig', ifname, 'down'])
+        subprocess.call(['ip', 'link', 'del', ifname])
+
+def test_ap_vlan_wpa2_radius_mixed(dev, apdev):
+    """AP VLAN with WPA2-Enterprise and tagged+untagged VLANs"""
+    ifname = 'wlan0.1'
+    try:
+        params = hostapd.wpa2_eap_params(ssid="test-vlan")
+        params['dynamic_vlan'] = "1"
+        params["vlan_naming"] = "1"
+        hapd = hostapd.add_ap(apdev[0], params)
+
+        dev[0].connect("test-vlan", key_mgmt="WPA-EAP", eap="PAX",
+                       identity="vlan12mixed",
+                       password_hex="0123456789abcdef0123456789abcdef",
+                       scan_freq="2412")
+
+        # Add tagged VLAN interface to wpa_supplicant interface for testing
+        subprocess.call(['ip', 'link', 'add', 'link', dev[0].ifname,
+                         'name', ifname, 'type', 'vlan', 'id', '1'])
+        subprocess.call(['ifconfig', ifname, 'up'])
+
+        logger.info("Test connectivity in untagged VLAN 2")
+        hwsim_utils.run_connectivity_test(dev[0], hapd, 0,
+                                          ifname1=dev[0].ifname,
+                                          ifname2="brvlan2")
+        logger.info("Test connectivity in tagged VLAN 1")
+        hwsim_utils.run_connectivity_test(dev[0], hapd, 0, ifname1=ifname,
+                                          ifname2="brvlan1")
+    finally:
+        subprocess.call(['ifconfig', ifname, 'down'])
+        subprocess.call(['ip', 'link', 'del', ifname])
+
+def test_ap_vlan_reconnect(dev, apdev):
+    """AP VLAN with WPA2-PSK connect, disconnect, connect"""
+    params = hostapd.wpa2_params(ssid="test-vlan",
+                                 passphrase="12345678")
+    params['dynamic_vlan'] = "1"
+    params['accept_mac_file'] = "hostapd.accept"
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    logger.info("connect sta")
+    dev[0].connect("test-vlan", psk="12345678", scan_freq="2412")
+    hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan1")
+    logger.info("disconnect sta")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected(timeout=10)
+    time.sleep(1)
+    logger.info("reconnect sta")
+    dev[0].connect("test-vlan", psk="12345678", scan_freq="2412")
+    hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan1")
index 1561792..fcbbb8c 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import base64
 import binascii
 from Crypto.Cipher import AES
@@ -29,19 +30,21 @@ import hwsim_utils
 import hostapd
 from wpasupplicant import WpaSupplicant
 from utils import HwsimSkip, alloc_fail, fail_test, skip_with_fips
+from utils import wait_fail_trigger
+from test_ap_eap import int_eap_server_params
 
 def wps_start_ap(apdev, ssid="test-wps-conf"):
     params = { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                "wpa_passphrase": "12345678", "wpa": "2",
                "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP" }
-    return hostapd.add_ap(apdev['ifname'], params)
+    return hostapd.add_ap(apdev, params)
 
+@remote_compatible
 def test_ap_wps_init(dev, apdev):
     """Initial AP configuration with first WPS Enrollee"""
     ssid = "test-wps"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
     logger.info("WPS provisioning step")
     hapd.request("WPS_PBC")
     if "PBC Status: Active" not in hapd.request("WPS_GET_STATUS"):
@@ -96,9 +99,8 @@ def test_ap_wps_init_2ap_pbc(dev, apdev):
     """Initial two-radio AP configuration with first WPS PBC Enrollee"""
     ssid = "test-wps"
     params = { "ssid": ssid, "eap_server": "1", "wps_state": "1" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hostapd.add_ap(apdev[1]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
+    hostapd.add_ap(apdev[1], params)
     logger.info("WPS provisioning step")
     hapd.request("WPS_PBC")
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412", force_scan=True)
@@ -133,9 +135,8 @@ def test_ap_wps_init_2ap_pin(dev, apdev):
     """Initial two-radio AP configuration with first WPS PIN Enrollee"""
     ssid = "test-wps"
     params = { "ssid": ssid, "eap_server": "1", "wps_state": "1" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hostapd.add_ap(apdev[1]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
+    hostapd.add_ap(apdev[1], params)
     logger.info("WPS provisioning step")
     pin = dev[0].wps_read_pin()
     hapd.request("WPS_PIN any " + pin)
@@ -160,12 +161,12 @@ def test_ap_wps_init_2ap_pin(dev, apdev):
     if "[WPS-AUTH]" in bss['flags']:
         raise Exception("WPS-AUTH flag not cleared from AP2")
 
+@remote_compatible
 def test_ap_wps_init_through_wps_config(dev, apdev):
     """Initial AP configuration using wps_config command"""
     ssid = "test-wps-init-config"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
     if "FAIL" in hapd.request("WPS_CONFIG " + ssid.encode("hex") + " WPA2PSK CCMP " + "12345678".encode("hex")):
         raise Exception("WPS_CONFIG command failed")
     ev = hapd.wait_event(["WPS-NEW-AP-SETTINGS"], timeout=5)
@@ -179,13 +180,13 @@ def test_ap_wps_init_through_wps_config(dev, apdev):
     dev[0].connect(ssid, psk="12345678", scan_freq="2412", proto="WPA2",
                    pairwise="CCMP", group="CCMP")
 
+@remote_compatible
 def test_ap_wps_init_through_wps_config_2(dev, apdev):
     """AP configuration using wps_config and wps_cred_processing=2"""
     ssid = "test-wps-init-config"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "1",
-                     "wps_cred_processing": "2" })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "1",
+                          "wps_cred_processing": "2" })
     if "FAIL" in hapd.request("WPS_CONFIG " + ssid.encode("hex") + " WPA2PSK CCMP " + "12345678".encode("hex")):
         raise Exception("WPS_CONFIG command failed")
     ev = hapd.wait_event(["WPS-NEW-AP-SETTINGS"], timeout=5)
@@ -194,23 +195,22 @@ def test_ap_wps_init_through_wps_config_2(dev, apdev):
     if "100e" not in ev:
         raise Exception("WPS-NEW-AP-SETTINGS did not include Credential")
 
+@remote_compatible
 def test_ap_wps_invalid_wps_config_passphrase(dev, apdev):
     """AP configuration using wps_config command with invalid passphrase"""
     ssid = "test-wps-init-config"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
     if "FAIL" not in hapd.request("WPS_CONFIG " + ssid.encode("hex") + " WPA2PSK CCMP " + "1234567".encode("hex")):
         raise Exception("Invalid WPS_CONFIG command accepted")
 
 def test_ap_wps_conf(dev, apdev):
     """WPS PBC provisioning with configured AP"""
     ssid = "test-wps-conf"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                          "wpa_passphrase": "12345678", "wpa": "2",
+                          "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
     logger.info("WPS provisioning step")
     hapd.request("WPS_PBC")
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
@@ -242,7 +242,7 @@ def test_ap_wps_conf_5ghz(dev, apdev):
                    "wpa_passphrase": "12345678", "wpa": "2",
                    "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
                    "country_code": "FI", "hw_mode": "a", "channel": "36" }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
         logger.info("WPS provisioning step")
         hapd.request("WPS_PBC")
         dev[0].scan_for_bss(apdev[0]['bssid'], freq="5180")
@@ -268,7 +268,7 @@ def test_ap_wps_conf_chan14(dev, apdev):
                    "wpa_passphrase": "12345678", "wpa": "2",
                    "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
                    "country_code": "JP", "hw_mode": "b", "channel": "14" }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
         logger.info("WPS provisioning step")
         hapd.request("WPS_PBC")
         dev[0].request("WPS_PBC")
@@ -284,14 +284,14 @@ def test_ap_wps_conf_chan14(dev, apdev):
         subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
+@remote_compatible
 def test_ap_wps_twice(dev, apdev):
     """WPS provisioning with twice to change passphrase"""
     ssid = "test-wps-twice"
     params = { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                "wpa_passphrase": "12345678", "wpa": "2",
                "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     logger.info("WPS provisioning step")
     hapd.request("WPS_PBC")
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
@@ -301,11 +301,9 @@ def test_ap_wps_twice(dev, apdev):
     dev[0].request("DISCONNECT")
 
     logger.info("Restart AP with different passphrase and re-run WPS")
-    hapd_global = hostapd.HostapdGlobal()
-    hapd_global.remove(apdev[0]['ifname'])
+    hostapd.remove_bss(apdev[0])
     params['wpa_passphrase'] = 'another passphrase'
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     logger.info("WPS provisioning step")
     hapd.request("WPS_PBC")
     dev[0].dump_monitor()
@@ -315,14 +313,14 @@ def test_ap_wps_twice(dev, apdev):
     if len(networks) > 1:
         raise Exception("Unexpected duplicated network block present")
 
+@remote_compatible
 def test_ap_wps_incorrect_pin(dev, apdev):
     """WPS PIN provisioning with incorrect PIN"""
     ssid = "test-wps-incorrect-pin"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                          "wpa_passphrase": "12345678", "wpa": "2",
+                          "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
 
     logger.info("WPS provisioning attempt 1")
     hapd.request("WPS_PIN any 12345670")
@@ -358,14 +356,14 @@ def test_ap_wps_incorrect_pin(dev, apdev):
         raise Exception("PIN error detected on incorrect message")
     dev[0].wait_disconnected(timeout=10)
 
+@remote_compatible
 def test_ap_wps_conf_pin(dev, apdev):
     """WPS PIN provisioning with configured AP"""
     ssid = "test-wps-conf-pin"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "2",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
     logger.info("WPS provisioning step")
     pin = dev[0].wps_read_pin()
     hapd.request("WPS_PIN any " + pin)
@@ -397,14 +395,71 @@ def test_ap_wps_conf_pin(dev, apdev):
     hapd.request("WPS_PIN any " + pin)
     dev[1].wait_connected(timeout=30)
 
+def test_ap_wps_conf_pin_mixed_mode(dev, apdev):
+    """WPS PIN provisioning with configured AP (WPA+WPA2)"""
+    ssid = "test-wps-conf-pin-mixed"
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "3",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
+                            "wpa_pairwise": "TKIP" })
+
+    logger.info("WPS provisioning step")
+    pin = dev[0].wps_read_pin()
+    hapd.request("WPS_PIN any " + pin)
+    dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
+    dev[0].dump_monitor()
+    dev[0].request("WPS_PIN %s %s" % (apdev[0]['bssid'], pin))
+    dev[0].wait_connected(timeout=30)
+    status = dev[0].get_status()
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+    if status['pairwise_cipher'] != 'CCMP' or status['group_cipher'] != 'TKIP' or status['key_mgmt'] != 'WPA2-PSK':
+        raise Exception("Unexpected encryption/key_mgmt configuration: pairwise=%s group=%s key_mgmt=%s" % (status['pairwise_cipher'], status['group_cipher'], status['key_mgmt']))
+
+    logger.info("WPS provisioning step (auth_types=0x1b)")
+    if "OK" not in dev[0].request("SET wps_force_auth_types 0x1b"):
+        raise Exception("Failed to set wps_force_auth_types 0x1b")
+    pin = dev[0].wps_read_pin()
+    hapd.request("WPS_PIN any " + pin)
+    dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
+    dev[0].dump_monitor()
+    dev[0].request("WPS_PIN %s %s" % (apdev[0]['bssid'], pin))
+    dev[0].wait_connected(timeout=30)
+    status = dev[0].get_status()
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+    if status['pairwise_cipher'] != 'CCMP' or status['group_cipher'] != 'TKIP' or status['key_mgmt'] != 'WPA2-PSK':
+        raise Exception("Unexpected encryption/key_mgmt configuration: pairwise=%s group=%s key_mgmt=%s" % (status['pairwise_cipher'], status['group_cipher'], status['key_mgmt']))
+
+    logger.info("WPS provisioning step (auth_types=0 encr_types=0)")
+    if "OK" not in dev[0].request("SET wps_force_auth_types 0"):
+        raise Exception("Failed to set wps_force_auth_types 0")
+    if "OK" not in dev[0].request("SET wps_force_encr_types 0"):
+        raise Exception("Failed to set wps_force_encr_types 0")
+    pin = dev[0].wps_read_pin()
+    hapd.request("WPS_PIN any " + pin)
+    dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
+    dev[0].dump_monitor()
+    dev[0].request("WPS_PIN %s %s" % (apdev[0]['bssid'], pin))
+    dev[0].wait_connected(timeout=30)
+    status = dev[0].get_status()
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+    if status['pairwise_cipher'] != 'CCMP' or status['group_cipher'] != 'TKIP' or status['key_mgmt'] != 'WPA2-PSK':
+        raise Exception("Unexpected encryption/key_mgmt configuration: pairwise=%s group=%s key_mgmt=%s" % (status['pairwise_cipher'], status['group_cipher'], status['key_mgmt']))
+
+    dev[0].request("SET wps_force_auth_types ")
+    dev[0].request("SET wps_force_encr_types ")
+
+@remote_compatible
 def test_ap_wps_conf_pin_v1(dev, apdev):
     """WPS PIN provisioning with configured WPS v1.0 AP"""
     ssid = "test-wps-conf-pin-v1"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "2",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
     logger.info("WPS provisioning step")
     pin = dev[0].wps_read_pin()
     hapd.request("SET wps_version_number 0x10")
@@ -423,14 +478,14 @@ def test_ap_wps_conf_pin_v1(dev, apdev):
     dev[0].wait_connected(timeout=30)
     hapd.request("SET wps_version_number 0x20")
 
+@remote_compatible
 def test_ap_wps_conf_pin_2sta(dev, apdev):
     """Two stations trying to use WPS PIN at the same time"""
     ssid = "test-wps-conf-pin2"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "2",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
     logger.info("WPS provisioning step")
     pin = "12345670"
     pin2 = "55554444"
@@ -445,14 +500,14 @@ def test_ap_wps_conf_pin_2sta(dev, apdev):
     dev[0].wait_connected(timeout=30)
     dev[1].wait_connected(timeout=30)
 
+@remote_compatible
 def test_ap_wps_conf_pin_timeout(dev, apdev):
     """WPS PIN provisioning with configured AP timing out PIN"""
     ssid = "test-wps-conf-pin"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "2",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
     addr = dev[0].p2p_interface_addr()
     pin = dev[0].wps_read_pin()
     if "FAIL" not in hapd.request("WPS_PIN "):
@@ -477,7 +532,7 @@ def test_ap_wps_reg_connect(dev, apdev):
     """WPS registrar using AP PIN to connect"""
     ssid = "test-wps-reg-ap-pin"
     appin = "12345670"
-    hostapd.add_ap(apdev[0]['ifname'],
+    hostapd.add_ap(apdev[0],
                    { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                      "wpa_passphrase": "12345678", "wpa": "2",
                      "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
@@ -500,7 +555,7 @@ def test_ap_wps_reg_connect_mixed_mode(dev, apdev):
     """WPS registrar using AP PIN to connect (WPA+WPA2)"""
     ssid = "test-wps-reg-ap-pin"
     appin = "12345670"
-    hostapd.add_ap(apdev[0]['ifname'],
+    hostapd.add_ap(apdev[0],
                    { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                      "wpa_passphrase": "12345678", "wpa": "3",
                      "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
@@ -535,12 +590,12 @@ def test_ap_wps_reg_override_ap_settings(dev, apdev):
         f.write(data)
     ssid = "test-wps-reg-ap-pin"
     appin = "12345670"
-    hostapd.add_ap(apdev[0]['ifname'],
+    hostapd.add_ap(apdev[0],
                    { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                      "wpa_passphrase": "12345678", "wpa": "2",
                      "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
                      "ap_pin": appin, "ap_settings": ap_settings })
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], { "ssid": "test" })
+    hapd2 = hostapd.add_ap(apdev[1], { "ssid": "test" })
     dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412)
     dev[0].scan_for_bss(apdev[1]['bssid'], freq=2412)
     dev[0].wps_reg(apdev[0]['bssid'], appin)
@@ -563,17 +618,16 @@ def test_ap_wps_random_ap_pin(dev, apdev):
     """WPS registrar using random AP PIN"""
     ssid = "test-wps-reg-random-ap-pin"
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
-                     "device_name": "Wireless AP", "manufacturer": "Company",
-                     "model_name": "WAP", "model_number": "123",
-                     "serial_number": "12345", "device_type": "6-0050F204-1",
-                     "os_version": "01020300",
-                     "config_methods": "label push_button",
-                     "uuid": ap_uuid, "upnp_iface": "lo" })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    params = { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+               "wpa_passphrase": "12345678", "wpa": "2",
+               "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
+               "device_name": "Wireless AP", "manufacturer": "Company",
+               "model_name": "WAP", "model_number": "123",
+               "serial_number": "12345", "device_type": "6-0050F204-1",
+               "os_version": "01020300",
+               "config_methods": "label push_button",
+               "uuid": ap_uuid, "upnp_iface": "lo" }
+    hapd = hostapd.add_ap(apdev[0], params)
     appin = hapd.request("WPS_AP_PIN random")
     if "FAIL" in appin:
         raise Exception("Could not generate random AP PIN")
@@ -615,8 +669,7 @@ def test_ap_wps_random_ap_pin(dev, apdev):
     check_wps_reg_failure(dev[1], apdev[0], appin)
 
     with fail_test(hapd, 1, "os_get_random;wps_generate_pin"):
-        if "FAIL" in hapd.request("WPS_AP_PIN random 1"):
-            raise Exception("Failed to generate PIN during OOM")
+        hapd.request("WPS_AP_PIN random 1")
         hapd.request("WPS_AP_PIN disable")
 
     with alloc_fail(hapd, 1, "upnp_wps_set_ap_pin"):
@@ -627,7 +680,7 @@ def test_ap_wps_reg_config(dev, apdev):
     """WPS registrar configuring an AP using AP PIN"""
     ssid = "test-wps-init-ap-pin"
     appin = "12345670"
-    hostapd.add_ap(apdev[0]['ifname'],
+    hostapd.add_ap(apdev[0],
                    { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                      "ap_pin": appin})
     logger.info("WPS configuration step")
@@ -666,7 +719,7 @@ def test_ap_wps_reg_config_ext_processing(dev, apdev):
     appin = "12345670"
     params = { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                "wps_cred_processing": "1", "ap_pin": appin}
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412)
     new_ssid = "wps-new-ssid"
     new_passphrase = "1234567890"
@@ -690,7 +743,7 @@ def test_ap_wps_reg_config_tkip(dev, apdev):
     skip_with_fips(dev[0])
     ssid = "test-wps-init-ap"
     appin = "12345670"
-    hostapd.add_ap(apdev[0]['ifname'],
+    hostapd.add_ap(apdev[0],
                    { "ssid": ssid, "eap_server": "1", "wps_state": "1",
                      "ap_pin": appin})
     logger.info("WPS configuration step")
@@ -721,11 +774,11 @@ def test_ap_wps_setup_locked(dev, apdev):
     """WPS registrar locking up AP setup on AP PIN failures"""
     ssid = "test-wps-incorrect-ap-pin"
     appin = "12345670"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
-                     "ap_pin": appin})
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "2",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
+                            "ap_pin": appin})
     new_ssid = "wps-new-ssid-test"
     new_passphrase = "1234567890"
 
@@ -758,7 +811,6 @@ def test_ap_wps_setup_locked(dev, apdev):
         logger.info("BSS: " + str(bss))
         raise Exception("AP Setup Locked not indicated in scan results")
 
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
     status = hapd.request("WPS_GET_STATUS")
     if "Last WPS result: Failed" not in status:
         raise Exception("WPS failure result not shown correctly")
@@ -769,7 +821,6 @@ def test_ap_wps_setup_locked(dev, apdev):
     dev[0].dump_monitor()
     logger.info("WPS provisioning step")
     pin = dev[0].wps_read_pin()
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
     hapd.request("WPS_PIN any " + pin)
     dev[0].request("WPS_PIN %s %s" % (apdev[0]['bssid'], pin))
     ev = dev[0].wait_event(["WPS-SUCCESS"], timeout=30)
@@ -788,11 +839,11 @@ def test_ap_wps_setup_locked_timeout(dev, apdev):
     """WPS re-enabling AP PIN after timeout"""
     ssid = "test-wps-incorrect-ap-pin"
     appin = "12345670"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
-                     "ap_pin": appin})
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "2",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
+                            "ap_pin": appin})
     new_ssid = "wps-new-ssid-test"
     new_passphrase = "1234567890"
 
@@ -818,7 +869,6 @@ def test_ap_wps_setup_locked_timeout(dev, apdev):
         time.sleep(0.1)
     if not ap_setup_locked:
         raise Exception("AP setup was not locked")
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
     ev = hapd.wait_event(["WPS-AP-SETUP-UNLOCKED"], timeout=80)
     if ev is None:
         raise Exception("AP PIN did not get unlocked on 60 second timeout")
@@ -831,7 +881,7 @@ def test_ap_wps_setup_locked_2(dev, apdev):
                "wpa_passphrase": "12345678", "wpa": "2",
                "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
                "ap_pin": appin, "ap_setup_locked": "2" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     new_ssid = "wps-new-ssid-test"
     new_passphrase = "1234567890"
 
@@ -861,21 +911,20 @@ def test_ap_wps_setup_locked_2(dev, apdev):
     dev[0].request("WPS_CANCEL")
     dev[0].wait_disconnected()
 
+@remote_compatible
 def test_ap_wps_pbc_overlap_2ap(dev, apdev):
     """WPS PBC session overlap with two active APs"""
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": "wps1", "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
-                     "wps_independent": "1"})
-    hostapd.add_ap(apdev[1]['ifname'],
-                   { "ssid": "wps2", "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "123456789", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
-                     "wps_independent": "1"})
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    params = { "ssid": "wps1", "eap_server": "1", "wps_state": "2",
+               "wpa_passphrase": "12345678", "wpa": "2",
+               "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
+               "wps_independent": "1"}
+    hapd = hostapd.add_ap(apdev[0], params)
+    params = { "ssid": "wps2", "eap_server": "1", "wps_state": "2",
+               "wpa_passphrase": "123456789", "wpa": "2",
+               "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
+               "wps_independent": "1"}
+    hapd2 = hostapd.add_ap(apdev[1], params)
     hapd.request("WPS_PBC")
-    hapd2 = hostapd.Hostapd(apdev[1]['ifname'])
     hapd2.request("WPS_PBC")
     logger.info("WPS provisioning step")
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412", force_scan=True)
@@ -888,14 +937,14 @@ def test_ap_wps_pbc_overlap_2ap(dev, apdev):
     hapd2.request("DISABLE")
     dev[0].flush_scan_cache()
 
+@remote_compatible
 def test_ap_wps_pbc_overlap_2sta(dev, apdev):
     """WPS PBC session overlap with two active STAs"""
     ssid = "test-wps-pbc-overlap"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "2",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
     logger.info("WPS provisioning step")
     hapd.request("WPS_PBC")
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
@@ -926,15 +975,15 @@ def test_ap_wps_pbc_overlap_2sta(dev, apdev):
     dev[0].flush_scan_cache()
     dev[1].flush_scan_cache()
 
+@remote_compatible
 def test_ap_wps_cancel(dev, apdev):
     """WPS AP cancelling enabled config method"""
     ssid = "test-wps-ap-cancel"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP" })
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "2",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP" })
     bssid = apdev[0]['bssid']
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
 
     logger.info("Verify PBC enable/cancel")
     hapd.request("WPS_PBC")
@@ -977,7 +1026,7 @@ def _test_ap_wps_er_add_enrollee(dev, apdev):
     ssid = "wps-er-add-enrollee"
     ap_pin = "12345670"
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    hostapd.add_ap(apdev[0]['ifname'],
+    hostapd.add_ap(apdev[0],
                    { "ssid": ssid, "eap_server": "1", "wps_state": "1",
                      "device_name": "Wireless AP", "manufacturer": "Company",
                      "model_name": "WAP", "model_number": "123",
@@ -1110,7 +1159,7 @@ def _test_ap_wps_er_add_enrollee_uuid(dev, apdev):
     ssid = "wps-er-add-enrollee"
     ap_pin = "12345670"
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    hostapd.add_ap(apdev[0]['ifname'],
+    hostapd.add_ap(apdev[0],
                    { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                      "wpa_passphrase": "12345678", "wpa": "2",
                      "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
@@ -1195,13 +1244,14 @@ def test_ap_wps_er_multi_add_enrollee(dev, apdev):
     try:
         _test_ap_wps_er_multi_add_enrollee(dev, apdev)
     finally:
-        dev[0].request("WPS_ER_STOP")
+        for i in range(2):
+            dev[i].request("WPS_ER_STOP")
 
 def _test_ap_wps_er_multi_add_enrollee(dev, apdev):
     ssid = "wps-er-add-enrollee"
     ap_pin = "12345670"
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    hostapd.add_ap(apdev[0]['ifname'],
+    hostapd.add_ap(apdev[0],
                    { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                      "wpa_passphrase": "12345678", "wpa": "2",
                      "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
@@ -1216,13 +1266,16 @@ def _test_ap_wps_er_multi_add_enrollee(dev, apdev):
     for i in range(2):
         dev[i].scan_for_bss(apdev[0]['bssid'], freq=2412)
         dev[i].wps_reg(apdev[0]['bssid'], ap_pin)
+    for i in range(2):
         dev[i].request("WPS_ER_START ifname=lo")
     for i in range(2):
         ev = dev[i].wait_event(["WPS-ER-AP-ADD"], timeout=15)
         if ev is None:
             raise Exception("AP discovery timed out")
         dev[i].dump_monitor()
+    for i in range(2):
         dev[i].request("WPS_ER_LEARN " + ap_uuid + " " + ap_pin)
+    for i in range(2):
         ev = dev[i].wait_event(["WPS-ER-AP-SETTINGS"], timeout=15)
         if ev is None:
             raise Exception("AP learn timed out")
@@ -1258,7 +1311,7 @@ def _test_ap_wps_er_add_enrollee_pbc(dev, apdev):
     ssid = "wps-er-add-enrollee-pbc"
     ap_pin = "12345670"
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    hostapd.add_ap(apdev[0]['ifname'],
+    hostapd.add_ap(apdev[0],
                    { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                      "wpa_passphrase": "12345678", "wpa": "2",
                      "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
@@ -1329,7 +1382,7 @@ def _test_ap_wps_er_pbc_overlap(dev, apdev):
     ssid = "wps-er-add-enrollee-pbc"
     ap_pin = "12345670"
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    hostapd.add_ap(apdev[0]['ifname'],
+    hostapd.add_ap(apdev[0],
                    { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                      "wpa_passphrase": "12345678", "wpa": "2",
                      "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
@@ -1404,7 +1457,7 @@ def _test_ap_wps_er_v10_add_enrollee_pin(dev, apdev):
     ssid = "wps-er-add-enrollee-pbc"
     ap_pin = "12345670"
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    hostapd.add_ap(apdev[0]['ifname'],
+    hostapd.add_ap(apdev[0],
                    { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                      "wpa_passphrase": "12345678", "wpa": "2",
                      "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
@@ -1447,6 +1500,7 @@ def _test_ap_wps_er_v10_add_enrollee_pin(dev, apdev):
     if ev is None:
         raise Exception("WPS ER did not report success")
 
+@remote_compatible
 def test_ap_wps_er_config_ap(dev, apdev):
     """WPS ER configuring AP over UPnP"""
     try:
@@ -1458,7 +1512,7 @@ def _test_ap_wps_er_config_ap(dev, apdev):
     ssid = "wps-er-ap-config"
     ap_pin = "12345670"
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    hostapd.add_ap(apdev[0]['ifname'],
+    hostapd.add_ap(apdev[0],
                    { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                      "wpa_passphrase": "12345678", "wpa": "2",
                      "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
@@ -1501,6 +1555,7 @@ def _test_ap_wps_er_config_ap(dev, apdev):
     if "OK" not in dev[0].request("WPS_ER_STOP"):
         raise Exception("WPS_ER_STOP failed")
 
+@remote_compatible
 def test_ap_wps_er_cache_ap_settings(dev, apdev):
     """WPS ER caching AP settings"""
     try:
@@ -1521,7 +1576,7 @@ def _test_ap_wps_er_cache_ap_settings(dev, apdev):
                "os_version": "01020300",
                "config_methods": "label push_button",
                "ap_pin": ap_pin, "uuid": ap_uuid, "upnp_iface": "lo" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412)
     dev[0].wps_reg(apdev[0]['bssid'], ap_pin)
     id = int(dev[0].list_networks()[0]['id'])
@@ -1553,7 +1608,7 @@ def _test_ap_wps_er_cache_ap_settings(dev, apdev):
         if ev is None:
             raise Exception("AP removal or disconnection timed out")
 
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     for i in range(2):
         ev = dev[0].wait_event([ "WPS-ER-AP-ADD", "CTRL-EVENT-CONNECTED" ],
                                timeout=15)
@@ -1600,7 +1655,7 @@ def _test_ap_wps_er_cache_ap_settings_oom(dev, apdev):
                "os_version": "01020300",
                "config_methods": "label push_button",
                "ap_pin": ap_pin, "uuid": ap_uuid, "upnp_iface": "lo" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412)
     dev[0].wps_reg(apdev[0]['bssid'], ap_pin)
     id = int(dev[0].list_networks()[0]['id'])
@@ -1633,7 +1688,7 @@ def _test_ap_wps_er_cache_ap_settings_oom(dev, apdev):
             if ev is None:
                 raise Exception("AP removal or disconnection timed out")
 
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
         for i in range(2):
             ev = dev[0].wait_event([ "WPS-ER-AP-ADD", "CTRL-EVENT-CONNECTED" ],
                                    timeout=15)
@@ -1662,7 +1717,7 @@ def _test_ap_wps_er_cache_ap_settings_oom2(dev, apdev):
                "os_version": "01020300",
                "config_methods": "label push_button",
                "ap_pin": ap_pin, "uuid": ap_uuid, "upnp_iface": "lo" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412)
     dev[0].wps_reg(apdev[0]['bssid'], ap_pin)
     id = int(dev[0].list_networks()[0]['id'])
@@ -1695,7 +1750,7 @@ def _test_ap_wps_er_cache_ap_settings_oom2(dev, apdev):
             if ev is None:
                 raise Exception("AP removal or disconnection timed out")
 
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
         for i in range(2):
             ev = dev[0].wait_event([ "WPS-ER-AP-ADD", "CTRL-EVENT-CONNECTED" ],
                                    timeout=15)
@@ -1724,7 +1779,7 @@ def _test_ap_wps_er_subscribe_oom(dev, apdev):
                "os_version": "01020300",
                "config_methods": "label push_button",
                "ap_pin": ap_pin, "uuid": ap_uuid, "upnp_iface": "lo" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412)
     dev[0].wps_reg(apdev[0]['bssid'], ap_pin)
     id = int(dev[0].list_networks()[0]['id'])
@@ -1763,7 +1818,7 @@ def _test_ap_wps_er_set_sel_reg_oom(dev, apdev):
                "os_version": "01020300",
                "config_methods": "label push_button",
                "ap_pin": ap_pin, "uuid": ap_uuid, "upnp_iface": "lo" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412)
     dev[0].wps_reg(apdev[0]['bssid'], ap_pin)
 
@@ -1794,6 +1849,7 @@ def _test_ap_wps_er_set_sel_reg_oom(dev, apdev):
 
     dev[0].request("WPS_ER_STOP")
 
+@remote_compatible
 def test_ap_wps_er_learn_oom(dev, apdev):
     """WPS ER learn OOM"""
     try:
@@ -1814,7 +1870,7 @@ def _test_ap_wps_er_learn_oom(dev, apdev):
                "os_version": "01020300",
                "config_methods": "label push_button",
                "ap_pin": ap_pin, "uuid": ap_uuid, "upnp_iface": "lo" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412)
     dev[0].wps_reg(apdev[0]['bssid'], ap_pin)
 
@@ -1848,13 +1904,12 @@ def test_ap_wps_fragmentation(dev, apdev):
     """WPS with fragmentation in EAP-WSC and mixed mode WPA+WPA2"""
     ssid = "test-wps-fragmentation"
     appin = "12345670"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "3",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
-                     "wpa_pairwise": "TKIP", "ap_pin": appin,
-                     "fragment_size": "50" })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "3",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
+                            "wpa_pairwise": "TKIP", "ap_pin": appin,
+                            "fragment_size": "50" })
     logger.info("WPS provisioning step (PBC)")
     hapd.request("WPS_PBC")
     dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412)
@@ -1897,14 +1952,14 @@ def test_ap_wps_fragmentation(dev, apdev):
     if status['key_mgmt'] != 'WPA2-PSK':
         raise Exception("Unexpected key_mgmt")
 
+@remote_compatible
 def test_ap_wps_new_version_sta(dev, apdev):
     """WPS compatibility with new version number on the station"""
     ssid = "test-wps-ver"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP" })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "2",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP" })
     logger.info("WPS provisioning step")
     hapd.request("WPS_PBC")
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
@@ -1914,14 +1969,14 @@ def test_ap_wps_new_version_sta(dev, apdev):
     dev[0].request("WPS_PBC " + apdev[0]['bssid'])
     dev[0].wait_connected(timeout=30)
 
+@remote_compatible
 def test_ap_wps_new_version_ap(dev, apdev):
     """WPS compatibility with new version number on the AP"""
     ssid = "test-wps-ver"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP" })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "2",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP" })
     logger.info("WPS provisioning step")
     if "FAIL" in hapd.request("SET wps_version_number 0x43"):
         raise Exception("Failed to enable test functionality")
@@ -1932,13 +1987,13 @@ def test_ap_wps_new_version_ap(dev, apdev):
     dev[0].wait_connected(timeout=30)
     hapd.request("SET wps_version_number 0x20")
 
+@remote_compatible
 def test_ap_wps_check_pin(dev, apdev):
     """Verify PIN checking through control interface"""
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": "wps", "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP" })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": "wps", "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "2",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP" })
     for t in [ ("12345670", "12345670"),
                ("12345678", "FAIL-CHECKSUM"),
                ("12345", "FAIL"),
@@ -1968,10 +2023,9 @@ def test_ap_wps_wep_config(dev, apdev):
     """WPS 2.0 AP rejecting WEP configuration"""
     ssid = "test-wps-config"
     appin = "12345670"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "ap_pin": appin})
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "ap_pin": appin})
     dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412)
     dev[0].wps_reg(apdev[0]['bssid'], appin, "wps-new-ssid-wep", "OPEN", "WEP",
                    "hello", no_wait=True)
@@ -1991,10 +2045,9 @@ def test_ap_wps_wep_config(dev, apdev):
 def test_ap_wps_wep_enroll(dev, apdev):
     """WPS 2.0 STA rejecting WEP configuration"""
     ssid = "test-wps-wep"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "skip_cred_build": "1", "extra_cred": "wps-wep-cred" })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    params = { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+               "skip_cred_build": "1", "extra_cred": "wps-wep-cred" }
+    hapd = hostapd.add_ap(apdev[0], params)
     hapd.request("WPS_PBC")
     dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412)
     dev[0].request("WPS_PBC " + apdev[0]['bssid'])
@@ -2004,6 +2057,7 @@ def test_ap_wps_wep_enroll(dev, apdev):
     if "msg=12" not in ev or "reason=2 (WEP Prohibited)" not in ev:
         raise Exception("Unexpected WPS-FAIL event: " + ev)
 
+@remote_compatible
 def test_ap_wps_ie_fragmentation(dev, apdev):
     """WPS AP using fragmented WPS IE"""
     ssid = "test-wps-ie-fragmentation"
@@ -2015,8 +2069,7 @@ def test_ap_wps_ie_fragmentation(dev, apdev):
                "model_name": "1234567890abcdef1234567890abcdef",
                "model_number": "1234567890abcdef1234567890abcdef",
                "serial_number": "1234567890abcdef1234567890abcdef" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     hapd.request("WPS_PBC")
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
     dev[0].request("WPS_PBC " + apdev[0]['bssid'])
@@ -2061,6 +2114,7 @@ def test_ap_wps_per_station_psk(dev, apdev):
     except:
         pass
 
+    hapd = None
     try:
         with open(pskfile, "w") as f:
             f.write("# WPA PSKs\n")
@@ -2069,7 +2123,7 @@ def test_ap_wps_per_station_psk(dev, apdev):
                    "wpa": "2", "wpa_key_mgmt": "WPA-PSK",
                    "rsn_pairwise": "CCMP", "ap_pin": appin,
                    "wpa_psk_file": pskfile }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
 
         logger.info("First enrollee")
         hapd.request("WPS_PBC")
@@ -2113,6 +2167,14 @@ def test_ap_wps_per_station_psk(dev, apdev):
             raise Exception("Same PSK recorded for sta0(enrollee) and sta0(reg)")
     finally:
         os.remove(pskfile)
+        if hapd:
+            dev[0].request("DISCONNECT")
+            dev[1].request("DISCONNECT")
+            dev[2].request("DISCONNECT")
+            hapd.disable()
+            dev[0].flush_scan_cache()
+            dev[1].flush_scan_cache()
+            dev[2].flush_scan_cache()
 
 def test_ap_wps_per_station_psk_failure(dev, apdev):
     """WPS PBC provisioning with per-station PSK (file not writable)"""
@@ -2135,7 +2197,7 @@ def test_ap_wps_per_station_psk_failure(dev, apdev):
                    "wpa": "2", "wpa_key_mgmt": "WPA-PSK",
                    "rsn_pairwise": "CCMP", "ap_pin": appin,
                    "wpa_psk_file": pskfile }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
         if "FAIL" in hapd.request("SET wpa_psk_file /tmp/does/not/exists/ap_wps_per_enrollee_psk_failure.psk_file"):
             raise Exception("Failed to set wpa_psk_file")
 
@@ -2168,12 +2230,11 @@ def test_ap_wps_pin_request_file(dev, apdev):
     pinfile = "/tmp/ap_wps_pin_request_file.log"
     if os.path.exists(pinfile):
         os.remove(pinfile)
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wps_pin_requests": pinfile,
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wps_pin_requests": pinfile,
+                            "wpa_passphrase": "12345678", "wpa": "2",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
     uuid = dev[0].get_status_field("uuid")
     pin = dev[0].wps_read_pin()
     try:
@@ -2215,8 +2276,7 @@ def test_ap_wps_auto_setup_with_config_file(dev, apdev):
             f.write("ssid=wps\n")
             f.write("eap_server=1\n")
             f.write("wps_state=1\n")
-        hostapd.add_bss('phy3', ifname, conffile)
-        hapd = hostapd.Hostapd(ifname)
+        hapd = hostapd.add_bss(apdev[0], ifname, conffile)
         hapd.request("WPS_PBC")
         dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
         dev[0].request("WPS_PBC " + apdev[0]['bssid'])
@@ -2246,7 +2306,7 @@ def test_ap_wps_pbc_timeout(dev, apdev, params):
     if not params['long']:
         raise HwsimSkip("Skip test case with long duration due to --long not specified")
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    hapd = add_ssdp_ap(apdev[0]['ifname'], ap_uuid)
+    hapd = add_ssdp_ap(apdev[0], ap_uuid)
 
     location = ssdp_get_location(ap_uuid)
     urls = upnp_get_urls(location)
@@ -2350,7 +2410,7 @@ VFi5hrLk
     if ev is None:
         raise Exception("WPS-TIMEOUT not reported")
 
-def add_ssdp_ap(ifname, ap_uuid):
+def add_ssdp_ap(ap, ap_uuid):
     ssid = "wps-ssdp"
     ap_pin = "12345670"
     params = { "ssid": ssid, "eap_server": "1", "wps_state": "2",
@@ -2367,7 +2427,7 @@ def add_ssdp_ap(ifname, ap_uuid):
                "model_description": "Wireless Access Point",
                "model_url": "http://www.example.com/model/",
                "upc": "123456789012" }
-    return hostapd.add_ap(ifname, params)
+    return hostapd.add_ap(ap, params)
 
 def ssdp_send(msg, no_recv=False):
     socket.setdefaulttimeout(1)
@@ -2393,7 +2453,7 @@ def ssdp_send_msearch(st, no_recv=False):
 def test_ap_wps_ssdp_msearch(dev, apdev):
     """WPS AP and SSDP M-SEARCH messages"""
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    add_ssdp_ap(apdev[0]['ifname'], ap_uuid)
+    add_ssdp_ap(apdev[0], ap_uuid)
 
     msg = '\r\n'.join([
             'M-SEARCH * HTTP/1.1',
@@ -2417,7 +2477,7 @@ def test_ap_wps_ssdp_msearch(dev, apdev):
     ssdp_send_msearch("upnp:rootdevice")
     ssdp_send_msearch("uuid:" + ap_uuid)
     ssdp_send_msearch("urn:schemas-wifialliance-org:service:WFAWLANConfig:1")
-    ssdp_send_msearch("urn:schemas-wifialliance-org:device:WFADevice:1");
+    ssdp_send_msearch("urn:schemas-wifialliance-org:device:WFADevice:1")
 
     msg = '\r\n'.join([
             'M-SEARCH * HTTP/1.1',
@@ -2431,7 +2491,7 @@ def test_ap_wps_ssdp_msearch(dev, apdev):
 def test_ap_wps_ssdp_invalid_msearch(dev, apdev):
     """WPS AP and invalid SSDP M-SEARCH messages"""
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    add_ssdp_ap(apdev[0]['ifname'], ap_uuid)
+    add_ssdp_ap(apdev[0], ap_uuid)
 
     socket.setdefaulttimeout(1)
     sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
@@ -2603,7 +2663,7 @@ def test_ap_wps_ssdp_invalid_msearch(dev, apdev):
 def test_ap_wps_ssdp_burst(dev, apdev):
     """WPS AP and SSDP burst"""
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    add_ssdp_ap(apdev[0]['ifname'], ap_uuid)
+    add_ssdp_ap(apdev[0], ap_uuid)
 
     msg = '\r\n'.join([
             'M-SEARCH * HTTP/1.1',
@@ -2657,7 +2717,7 @@ def ssdp_get_location(uuid):
     return location
 
 def upnp_get_urls(location):
-    conn = urllib.urlopen(location)
+    conn = urllib.urlopen(location, proxies={})
     tree = ET.parse(conn)
     root = tree.getroot()
     urn = '{urn:schemas-upnp-org:device-1-0}'
@@ -2668,7 +2728,9 @@ def upnp_get_urls(location):
     res['event_sub_url'] = urlparse.urljoin(location, service.find(urn + 'eventSubURL').text)
     return res
 
-def upnp_soap_action(conn, path, action, include_soap_action=True, soap_action_override=None):
+def upnp_soap_action(conn, path, action, include_soap_action=True,
+                     soap_action_override=None, newmsg=None, neweventtype=None,
+                     neweventmac=None):
     soapns = 'http://schemas.xmlsoap.org/soap/envelope/'
     wpsns = 'urn:schemas-wifialliance-org:service:WFAWLANConfig:1'
     ET.register_namespace('soapenv', soapns)
@@ -2678,6 +2740,15 @@ def upnp_soap_action(conn, path, action, include_soap_action=True, soap_action_o
     root = ET.Element("{%s}Envelope" % soapns, attrib=attrib)
     body = ET.SubElement(root, "{%s}Body" % soapns)
     act = ET.SubElement(body, "{%s}%s" % (wpsns, action))
+    if newmsg:
+        msg = ET.SubElement(act, "NewMessage")
+        msg.text = base64.b64encode(newmsg)
+    if neweventtype:
+        msg = ET.SubElement(act, "NewWLANEventType")
+        msg.text = neweventtype
+    if neweventmac:
+        msg = ET.SubElement(act, "NewWLANEventMAC")
+        msg.text = neweventmac
     tree = ET.ElementTree(root)
     soap = StringIO.StringIO()
     tree.write(soap, xml_declaration=True, encoding='utf-8')
@@ -2693,15 +2764,16 @@ def upnp_soap_action(conn, path, action, include_soap_action=True, soap_action_o
 def test_ap_wps_upnp(dev, apdev):
     """WPS AP and UPnP operations"""
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    add_ssdp_ap(apdev[0]['ifname'], ap_uuid)
+    add_ssdp_ap(apdev[0], ap_uuid)
 
     location = ssdp_get_location(ap_uuid)
     urls = upnp_get_urls(location)
 
-    conn = urllib.urlopen(urls['scpd_url'])
+    conn = urllib.urlopen(urls['scpd_url'], proxies={})
     scpd = conn.read()
 
-    conn = urllib.urlopen(urlparse.urljoin(location, "unknown.html"))
+    conn = urllib.urlopen(urlparse.urljoin(location, "unknown.html"),
+                          proxies={})
     if conn.getcode() != 404:
         raise Exception("Unexpected HTTP response to GET unknown URL")
 
@@ -2775,7 +2847,7 @@ def test_ap_wps_upnp(dev, apdev):
 def test_ap_wps_upnp_subscribe(dev, apdev):
     """WPS AP and UPnP event subscription"""
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    hapd = add_ssdp_ap(apdev[0]['ifname'], ap_uuid)
+    hapd = add_ssdp_ap(apdev[0], ap_uuid)
 
     location = ssdp_get_location(ap_uuid)
     urls = upnp_get_urls(location)
@@ -3123,7 +3195,7 @@ def test_ap_wps_upnp_subscribe(dev, apdev):
 def test_ap_wps_upnp_subscribe_events(dev, apdev):
     """WPS AP and UPnP event subscription and many events"""
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    hapd = add_ssdp_ap(apdev[0]['ifname'], ap_uuid)
+    hapd = add_ssdp_ap(apdev[0], ap_uuid)
 
     location = ssdp_get_location(ap_uuid)
     urls = upnp_get_urls(location)
@@ -3190,7 +3262,7 @@ def test_ap_wps_upnp_subscribe_events(dev, apdev):
 def test_ap_wps_upnp_http_proto(dev, apdev):
     """WPS AP and UPnP/HTTP protocol testing"""
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    add_ssdp_ap(apdev[0]['ifname'], ap_uuid)
+    add_ssdp_ap(apdev[0], ap_uuid)
 
     location = ssdp_get_location(ap_uuid)
 
@@ -3289,7 +3361,7 @@ def test_ap_wps_upnp_http_proto(dev, apdev):
 def test_ap_wps_upnp_http_proto_chunked(dev, apdev):
     """WPS AP and UPnP/HTTP protocol testing for chunked encoding"""
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    add_ssdp_ap(apdev[0]['ifname'], ap_uuid)
+    add_ssdp_ap(apdev[0], ap_uuid)
 
     location = ssdp_get_location(ap_uuid)
 
@@ -3349,11 +3421,11 @@ def test_ap_wps_upnp_http_proto_chunked(dev, apdev):
         pass
     conn.close()
 
+@remote_compatible
 def test_ap_wps_disabled(dev, apdev):
     """WPS operations while WPS is disabled"""
     ssid = "test-wps-disabled"
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": ssid })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], { "ssid": ssid })
     if "FAIL" not in hapd.request("WPS_PBC"):
         raise Exception("WPS_PBC succeeded unexpectedly")
     if "FAIL" not in hapd.request("WPS_CANCEL"):
@@ -3362,10 +3434,9 @@ def test_ap_wps_disabled(dev, apdev):
 def test_ap_wps_mixed_cred(dev, apdev):
     """WPS 2.0 STA merging mixed mode WPA/WPA2 credentials"""
     ssid = "test-wps-wep"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "skip_cred_build": "1", "extra_cred": "wps-mixed-cred" })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    params = { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+               "skip_cred_build": "1", "extra_cred": "wps-mixed-cred" }
+    hapd = hostapd.add_ap(apdev[0], params)
     hapd.request("WPS_PBC")
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
     dev[0].request("WPS_PBC " + apdev[0]['bssid'])
@@ -3383,16 +3454,16 @@ def test_ap_wps_mixed_cred(dev, apdev):
     if pairwise != "CCMP TKIP" and pairwise != "CCMP GCMP TKIP":
         raise Exception("Unexpected merged pairwise field value: " + pairwise)
 
+@remote_compatible
 def test_ap_wps_while_connected(dev, apdev):
     """WPS PBC provisioning while connected to another AP"""
     ssid = "test-wps-conf"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "2",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
 
-    hostapd.add_ap(apdev[1]['ifname'], { "ssid": "open" })
+    hostapd.add_ap(apdev[1], { "ssid": "open" })
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
 
     logger.info("WPS provisioning step")
@@ -3404,16 +3475,16 @@ def test_ap_wps_while_connected(dev, apdev):
     if status['bssid'] != apdev[0]['bssid']:
         raise Exception("Unexpected BSSID")
 
+@remote_compatible
 def test_ap_wps_while_connected_no_autoconnect(dev, apdev):
     """WPS PBC provisioning while connected to another AP and STA_AUTOCONNECT disabled"""
     ssid = "test-wps-conf"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "2",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
 
-    hostapd.add_ap(apdev[1]['ifname'], { "ssid": "open" })
+    hostapd.add_ap(apdev[1], { "ssid": "open" })
 
     try:
         dev[0].request("STA_AUTOCONNECT 0")
@@ -3430,10 +3501,11 @@ def test_ap_wps_while_connected_no_autoconnect(dev, apdev):
     finally:
         dev[0].request("STA_AUTOCONNECT 1")
 
+@remote_compatible
 def test_ap_wps_from_event(dev, apdev):
     """WPS PBC event on AP to enable PBC"""
     ssid = "test-wps-conf"
-    hapd = hostapd.add_ap(apdev[0]['ifname'],
+    hapd = hostapd.add_ap(apdev[0],
                           { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                             "wpa_passphrase": "12345678", "wpa": "2",
                             "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
@@ -3456,7 +3528,7 @@ def test_ap_wps_from_event(dev, apdev):
 def test_ap_wps_ap_scan_2(dev, apdev):
     """AP_SCAN 2 for WPS"""
     ssid = "test-wps-conf"
-    hapd = hostapd.add_ap(apdev[0]['ifname'],
+    hapd = hostapd.add_ap(apdev[0],
                           { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                             "wpa_passphrase": "12345678", "wpa": "2",
                             "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
@@ -3464,29 +3536,33 @@ def test_ap_wps_ap_scan_2(dev, apdev):
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
+    wpas.dump_monitor()
 
     if "OK" not in wpas.request("AP_SCAN 2"):
         raise Exception("Failed to set AP_SCAN 2")
 
     wpas.flush_scan_cache()
     wpas.scan_for_bss(apdev[0]['bssid'], freq="2412")
+    wpas.dump_monitor()
     wpas.request("WPS_PBC " + apdev[0]['bssid'])
     ev = wpas.wait_event(["WPS-SUCCESS"], timeout=15)
     if ev is None:
         raise Exception("WPS-SUCCESS event timed out")
     wpas.wait_connected(timeout=30)
+    wpas.dump_monitor()
     wpas.request("DISCONNECT")
     wpas.request("BSS_FLUSH 0")
     wpas.dump_monitor()
     wpas.request("REASSOCIATE")
     wpas.wait_connected(timeout=30)
+    wpas.dump_monitor()
 
+@remote_compatible
 def test_ap_wps_eapol_workaround(dev, apdev):
     """EAPOL workaround code path for 802.1X header length mismatch"""
     ssid = "test-wps"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
     bssid = apdev[0]['bssid']
     hapd.request("SET ext_eapol_frame_io 1")
     dev[0].request("SET ext_eapol_frame_io 1")
@@ -3504,13 +3580,13 @@ def test_ap_wps_eapol_workaround(dev, apdev):
 def test_ap_wps_iteration(dev, apdev):
     """WPS PIN and iterate through APs without selected registrar"""
     ssid = "test-wps-conf"
-    hapd = hostapd.add_ap(apdev[0]['ifname'],
+    hapd = hostapd.add_ap(apdev[0],
                           { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                             "wpa_passphrase": "12345678", "wpa": "2",
                             "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
 
     ssid2 = "test-wps-conf2"
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'],
+    hapd2 = hostapd.add_ap(apdev[1],
                            { "ssid": ssid2, "eap_server": "1", "wps_state": "2",
                              "wpa_passphrase": "12345678", "wpa": "2",
                              "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
@@ -3546,7 +3622,7 @@ def test_ap_wps_iteration(dev, apdev):
 def test_ap_wps_iteration_error(dev, apdev):
     """WPS AP iteration on no Selected Registrar and error case with an AP"""
     ssid = "test-wps-conf-pin"
-    hapd = hostapd.add_ap(apdev[0]['ifname'],
+    hapd = hostapd.add_ap(apdev[0],
                           { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                             "wpa_passphrase": "12345678", "wpa": "2",
                             "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
@@ -3572,7 +3648,7 @@ def test_ap_wps_iteration_error(dev, apdev):
     # a case with an incorrectly behaving WPS AP.
 
     # Start the real target AP and activate registrar on it.
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'],
+    hapd2 = hostapd.add_ap(apdev[1],
                           { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                             "wpa_passphrase": "12345678", "wpa": "2",
                             "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
@@ -3588,14 +3664,14 @@ def test_ap_wps_iteration_error(dev, apdev):
         raise Exception("No WPS-CRED-RECEIVED for the second AP")
     dev[0].wait_connected(timeout=15)
 
+@remote_compatible
 def test_ap_wps_priority(dev, apdev):
     """WPS PIN provisioning with configured AP and wps_priority"""
     ssid = "test-wps-conf-pin"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "2",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
     logger.info("WPS provisioning step")
     pin = dev[0].wps_read_pin()
     hapd.request("WPS_PIN any " + pin)
@@ -3612,13 +3688,14 @@ def test_ap_wps_priority(dev, apdev):
     finally:
         dev[0].request("SET wps_priority 0")
 
+@remote_compatible
 def test_ap_wps_and_non_wps(dev, apdev):
     """WPS and non-WPS AP in single hostapd process"""
     params = { "ssid": "wps", "eap_server": "1", "wps_state": "1" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     params = { "ssid": "no wps" }
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd2 = hostapd.add_ap(apdev[1], params)
 
     appin = hapd.request("WPS_AP_PIN random")
     if "FAIL" in appin:
@@ -3635,7 +3712,7 @@ def test_ap_wps_init_oom(dev, apdev):
     """Initial AP configuration and OOM during PSK generation"""
     ssid = "test-wps"
     params = { "ssid": ssid, "eap_server": "1", "wps_state": "1" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     with alloc_fail(hapd, 1, "base64_encode;wps_build_cred"):
         pin = dev[0].wps_read_pin()
@@ -3647,6 +3724,7 @@ def test_ap_wps_init_oom(dev, apdev):
     hapd.request("WPS_PIN any " + pin)
     dev[0].wait_connected(timeout=30)
 
+@remote_compatible
 def test_ap_wps_er_oom(dev, apdev):
     """WPS ER OOM in XML processing"""
     try:
@@ -3660,7 +3738,7 @@ def _test_ap_wps_er_oom(dev, apdev):
     ssid = "wps-er-ap-config"
     ap_pin = "12345670"
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    hostapd.add_ap(apdev[0]['ifname'],
+    hostapd.add_ap(apdev[0],
                    { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                      "wpa_passphrase": "12345678", "wpa": "2",
                      "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
@@ -3695,6 +3773,7 @@ def _test_ap_wps_er_oom(dev, apdev):
         if ev is None:
             raise Exception("Enrollee discovery timed out")
 
+@remote_compatible
 def test_ap_wps_er_init_oom(dev, apdev):
     """WPS ER and OOM during init"""
     try:
@@ -3712,13 +3791,14 @@ def _test_ap_wps_er_init_oom(dev, apdev):
     with alloc_fail(dev[0], 2, "http_server_init"):
         if "FAIL" not in dev[0].request("WPS_ER_START ifname=lo"):
             raise Exception("WPS_ER_START succeeded during OOM")
-    with alloc_fail(dev[0], 1, "eloop_register_sock;wps_er_ssdp_init"):
+    with alloc_fail(dev[0], 1, "eloop_sock_table_add_sock;?eloop_register_sock;wps_er_ssdp_init"):
         if "FAIL" not in dev[0].request("WPS_ER_START ifname=lo"):
             raise Exception("WPS_ER_START succeeded during OOM")
     with fail_test(dev[0], 1, "os_get_random;wps_er_init"):
         if "FAIL" not in dev[0].request("WPS_ER_START ifname=lo"):
             raise Exception("WPS_ER_START succeeded during os_get_random failure")
 
+@remote_compatible
 def test_ap_wps_er_init_fail(dev, apdev):
     """WPS ER init failure"""
     if "FAIL" not in dev[0].request("WPS_ER_START ifname=does-not-exist"):
@@ -3744,11 +3824,10 @@ def test_ap_wps_wpa_cli_action(dev, apdev, test_params):
              stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
 
     ssid = "test-wps-conf"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+                            "wpa_passphrase": "12345678", "wpa": "2",
+                            "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"})
 
     prg = os.path.join(test_params['logdir'],
                        'alt-wpa_supplicant/wpa_supplicant/wpa_cli')
@@ -4339,6 +4418,7 @@ RGV2aWNlIEEQSQAGADcqAAEg
     for i in range(20):
         socks[i] = socket.socket(socket.AF_INET, socket.SOCK_STREAM,
                                  socket.IPPROTO_TCP)
+        socks[i].settimeout(10)
         socks[i].connect(addr)
     for i in range(20):
         socks[i].send("GET / HTTP/1.1\r\n\r\n")
@@ -4358,7 +4438,7 @@ RGV2aWNlIEEQSQAGADcqAAEg
     logger.info("OOM in HTTP server")
     for func in [ "http_request_init", "httpread_create",
                   "eloop_register_timeout;httpread_create",
-                  "eloop_register_sock;httpread_create",
+                  "eloop_sock_table_add_sock;?eloop_register_sock;httpread_create",
                   "httpread_hdr_analyze" ]:
         with alloc_fail(dev[0], 1, func):
             sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM,
@@ -4528,7 +4608,7 @@ def _test_ap_wps_er_http_proto_subscribe_oom(dev, apdev):
     tests = [ (1, "http_client_url_parse"),
               (1, "wpabuf_alloc;wps_er_subscribe"),
               (1, "http_client_addr"),
-              (1, "eloop_register_sock;http_client_addr"),
+              (1, "eloop_sock_table_add_sock;?eloop_register_sock;http_client_addr"),
               (1, "eloop_register_timeout;http_client_addr") ]
     for count,func in tests:
         with alloc_fail(dev[0], count, func):
@@ -4680,7 +4760,7 @@ def test_ap_wps_http_timeout(dev, apdev):
 
 def _test_ap_wps_http_timeout(dev, apdev):
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    add_ssdp_ap(apdev[0]['ifname'], ap_uuid)
+    add_ssdp_ap(apdev[0], ap_uuid)
 
     location = ssdp_get_location(ap_uuid)
     url = urlparse.urlparse(location)
@@ -4776,7 +4856,7 @@ def test_ap_wps_init_oom(dev, apdev):
     appin = "12345670"
     params = { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                "ap_pin": appin }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     pin = dev[0].wps_read_pin()
 
     with alloc_fail(hapd, 1, "wps_init"):
@@ -4818,11 +4898,12 @@ def test_ap_wps_init_oom(dev, apdev):
 
     dev[0].flush_scan_cache()
 
+@remote_compatible
 def test_ap_wps_invalid_assoc_req_elem(dev, apdev):
     """WPS and invalid IE in Association Request frame"""
     ssid = "test-wps"
     params = { "ssid": ssid, "eap_server": "1", "wps_state": "2" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     pin = "12345670"
     hapd.request("WPS_PIN any " + pin)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
@@ -4843,7 +4924,7 @@ def test_ap_wps_pbc_pin_mismatch(dev, apdev):
     """WPS PBC/PIN mismatch"""
     ssid = "test-wps"
     params = { "ssid": ssid, "eap_server": "1", "wps_state": "2" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     hapd.request("SET wps_version_number 0x10")
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
     hapd.request("WPS_PBC")
@@ -4857,14 +4938,15 @@ def test_ap_wps_pbc_pin_mismatch(dev, apdev):
     hapd.request("WPS_CANCEL")
     dev[0].flush_scan_cache()
 
+@remote_compatible
 def test_ap_wps_ie_invalid(dev, apdev):
     """WPS PIN attempt with AP that has invalid WSC IE"""
     ssid = "test-wps"
     params = { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                "vendor_elements": "dd050050f20410" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     params = { 'ssid': "another", "vendor_elements": "dd050050f20410" }
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
     pin = dev[0].wps_read_pin()
     dev[0].request("WPS_PIN %s %s" % (apdev[0]['bssid'], pin))
@@ -4873,13 +4955,14 @@ def test_ap_wps_ie_invalid(dev, apdev):
         raise Exception("Scan did not complete")
     dev[0].request("WPS_CANCEL")
 
+@remote_compatible
 def test_ap_wps_scan_prio_order(dev, apdev):
     """WPS scan priority ordering"""
     ssid = "test-wps"
     params = { "ssid": ssid, "eap_server": "1", "wps_state": "2" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     params = { 'ssid': "another", "vendor_elements": "dd050050f20410" }
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
     dev[0].scan_for_bss(apdev[1]['bssid'], freq="2412")
     pin = dev[0].wps_read_pin()
@@ -4893,7 +4976,7 @@ def test_ap_wps_probe_req_ie_oom(dev, apdev):
     """WPS ProbeReq IE OOM"""
     ssid = "test-wps"
     params = { "ssid": ssid, "eap_server": "1", "wps_state": "2" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     pin = dev[0].wps_read_pin()
     hapd.request("WPS_PIN any " + pin)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
@@ -4903,6 +4986,7 @@ def test_ap_wps_probe_req_ie_oom(dev, apdev):
         if ev is None:
             raise Exception("Association not seen")
     dev[0].request("WPS_CANCEL")
+    dev[0].wait_disconnected()
 
     with alloc_fail(dev[0], 1, "wps_ie_encapsulate"):
         dev[0].request("WPS_PIN %s %s" % (apdev[0]['bssid'], pin))
@@ -4910,12 +4994,17 @@ def test_ap_wps_probe_req_ie_oom(dev, apdev):
         if ev is None:
             raise Exception("Association not seen")
     dev[0].request("WPS_CANCEL")
+    hapd.disable()
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+    time.sleep(0.2)
+    dev[0].flush_scan_cache()
 
 def test_ap_wps_assoc_req_ie_oom(dev, apdev):
     """WPS AssocReq IE OOM"""
     ssid = "test-wps"
     params = { "ssid": ssid, "eap_server": "1", "wps_state": "2" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     pin = dev[0].wps_read_pin()
     hapd.request("WPS_PIN any " + pin)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
@@ -4930,7 +5019,7 @@ def test_ap_wps_assoc_resp_ie_oom(dev, apdev):
     """WPS AssocResp IE OOM"""
     ssid = "test-wps"
     params = { "ssid": ssid, "eap_server": "1", "wps_state": "2" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     pin = dev[0].wps_read_pin()
     hapd.request("WPS_PIN any " + pin)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
@@ -4941,13 +5030,14 @@ def test_ap_wps_assoc_resp_ie_oom(dev, apdev):
             raise Exception("Association not seen")
     dev[0].request("WPS_CANCEL")
 
+@remote_compatible
 def test_ap_wps_bss_info_errors(dev, apdev):
     """WPS BSS info errors"""
     params = { "ssid": "1",
                "vendor_elements": "dd0e0050f20410440001ff101100010a" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     params = { 'ssid': "2", "vendor_elements": "dd050050f20410" }
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
     dev[0].scan_for_bss(apdev[1]['bssid'], freq="2412")
     bss = dev[0].get_bss(apdev[0]['bssid'])
@@ -4989,17 +5079,20 @@ def wps_run_pbc_fail(apdev, dev):
     hapd = wps_start_ap(apdev)
     wps_run_pbc_fail_ap(apdev, dev, hapd)
 
+@remote_compatible
 def test_ap_wps_pk_oom(dev, apdev):
     """WPS and public key OOM"""
     with alloc_fail(dev[0], 1, "wps_build_public_key"):
         wps_run_pbc_fail(apdev[0], dev[0])
 
+@remote_compatible
 def test_ap_wps_pk_oom_ap(dev, apdev):
     """WPS and public key OOM on AP"""
     hapd = wps_start_ap(apdev[0])
     with alloc_fail(hapd, 1, "wps_build_public_key"):
         wps_run_pbc_fail_ap(apdev[0], dev[0], hapd)
 
+@remote_compatible
 def test_ap_wps_encr_oom_ap(dev, apdev):
     """WPS and encrypted settings decryption OOM on AP"""
     hapd = wps_start_ap(apdev[0])
@@ -5014,32 +5107,38 @@ def test_ap_wps_encr_oom_ap(dev, apdev):
         dev[0].request("WPS_CANCEL")
     dev[0].wait_disconnected()
 
+@remote_compatible
 def test_ap_wps_encr_no_random_ap(dev, apdev):
     """WPS and no random data available for encryption on AP"""
     hapd = wps_start_ap(apdev[0])
     with fail_test(hapd, 1, "os_get_random;wps_build_encr_settings"):
         wps_run_pbc_fail_ap(apdev[0], dev[0], hapd)
 
+@remote_compatible
 def test_ap_wps_e_hash_no_random_sta(dev, apdev):
     """WPS and no random data available for e-hash on STA"""
     with fail_test(dev[0], 1, "os_get_random;wps_build_e_hash"):
         wps_run_pbc_fail(apdev[0], dev[0])
 
+@remote_compatible
 def test_ap_wps_m1_no_random(dev, apdev):
     """WPS and no random for M1 on STA"""
     with fail_test(dev[0], 1, "os_get_random;wps_build_m1"):
         wps_run_pbc_fail(apdev[0], dev[0])
 
+@remote_compatible
 def test_ap_wps_m1_oom(dev, apdev):
     """WPS and OOM for M1 on STA"""
     with alloc_fail(dev[0], 1, "wps_build_m1"):
         wps_run_pbc_fail(apdev[0], dev[0])
 
+@remote_compatible
 def test_ap_wps_m3_oom(dev, apdev):
     """WPS and OOM for M3 on STA"""
     with alloc_fail(dev[0], 1, "wps_build_m3"):
         wps_run_pbc_fail(apdev[0], dev[0])
 
+@remote_compatible
 def test_ap_wps_m5_oom(dev, apdev):
     """WPS and OOM for M5 on STA"""
     hapd = wps_start_ap(apdev[0])
@@ -5055,12 +5154,14 @@ def test_ap_wps_m5_oom(dev, apdev):
             dev[0].wait_disconnected()
     dev[0].flush_scan_cache()
 
+@remote_compatible
 def test_ap_wps_m5_no_random(dev, apdev):
     """WPS and no random for M5 on STA"""
     with fail_test(dev[0], 1,
                    "os_get_random;wps_build_encr_settings;wps_build_m5"):
         wps_run_pbc_fail(apdev[0], dev[0])
 
+@remote_compatible
 def test_ap_wps_m7_oom(dev, apdev):
     """WPS and OOM for M7 on STA"""
     hapd = wps_start_ap(apdev[0])
@@ -5076,12 +5177,14 @@ def test_ap_wps_m7_oom(dev, apdev):
             dev[0].wait_disconnected()
     dev[0].flush_scan_cache()
 
+@remote_compatible
 def test_ap_wps_m7_no_random(dev, apdev):
     """WPS and no random for M7 on STA"""
     with fail_test(dev[0], 1,
                    "os_get_random;wps_build_encr_settings;wps_build_m7"):
         wps_run_pbc_fail(apdev[0], dev[0])
 
+@remote_compatible
 def test_ap_wps_wsc_done_oom(dev, apdev):
     """WPS and OOM for WSC_Done on STA"""
     with alloc_fail(dev[0], 1, "wps_build_wsc_done"):
@@ -5105,7 +5208,7 @@ def test_ap_wps_random_psk_fail(dev, apdev):
                    "wpa": "2", "wpa_key_mgmt": "WPA-PSK",
                    "rsn_pairwise": "CCMP", "ap_pin": appin,
                    "wpa_psk_file": pskfile }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
 
         dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
         with fail_test(hapd, 1, "os_get_random;wps_build_cred_network_key"):
@@ -5160,7 +5263,7 @@ def wps_start_ext(apdev, dev, pbc=False, pin=None):
     params = { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                "wpa_passphrase": "12345678", "wpa": "2",
                "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"}
-    hapd = hostapd.add_ap(apdev['ifname'], params)
+    hapd = hostapd.add_ap(apdev, params)
 
     if pbc:
         hapd.request("WPS_PBC")
@@ -5743,6 +5846,7 @@ def test_ap_wps_m4_msg_type_m2d(dev, apdev):
     """WPS and M4 but Message Type M2D"""
     wps_m4_but_other(dev[0], apdev[0], "M4/M2D", "06")
 
+@remote_compatible
 def test_ap_wps_config_methods(dev, apdev):
     """WPS configuration method parsing"""
     ssid = "test-wps-conf"
@@ -5750,17 +5854,17 @@ def test_ap_wps_config_methods(dev, apdev):
                "wpa_passphrase": "12345678", "wpa": "2",
                "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
                "config_methods": "ethernet display ext_nfc_token int_nfc_token physical_display physical_push_button" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     params = { "ssid": ssid, "eap_server": "1", "wps_state": "2",
                "wpa_passphrase": "12345678", "wpa": "2",
                "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
                "config_methods": "display push_button" }
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd2 = hostapd.add_ap(apdev[1], params)
 
 def test_ap_wps_set_selected_registrar_proto(dev, apdev):
     """WPS UPnP SetSelectedRegistrar protocol testing"""
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    hapd = add_ssdp_ap(apdev[0]['ifname'], ap_uuid)
+    hapd = add_ssdp_ap(apdev[0], ap_uuid)
 
     location = ssdp_get_location(ap_uuid)
     urls = upnp_get_urls(location)
@@ -5818,7 +5922,7 @@ def test_ap_wps_set_selected_registrar_proto(dev, apdev):
 def test_ap_wps_adv_oom(dev, apdev):
     """WPS AP and advertisement OOM"""
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    hapd = add_ssdp_ap(apdev[0]['ifname'], ap_uuid)
+    hapd = add_ssdp_ap(apdev[0], ap_uuid)
 
     with alloc_fail(hapd, 1, "=msearchreply_state_machine_start"):
         ssdp_send_msearch("urn:schemas-wifialliance-org:service:WFAWLANConfig:1",
@@ -7563,7 +7667,7 @@ def wps_start_ext_reg(apdev, dev):
                "wpa_passphrase": "12345678", "wpa": "2",
                "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
                "ap_pin": appin }
-    hapd = hostapd.add_ap(apdev['ifname'], params)
+    hapd = hostapd.add_ap(apdev, params)
 
     dev.scan_for_bss(bssid, freq="2412")
     hapd.request("SET ext_eapol_frame_io 1")
@@ -7680,10 +7784,12 @@ def test_wps_ext_ap_settings_success(dev, apdev):
     ap_settings += build_wsc_attr(ATTR_MAC_ADDR, binascii.unhexlify(apdev[0]['bssid'].replace(':', '')))
     wps_run_ap_settings_proto(dev, apdev, ap_settings, True)
 
+@remote_compatible
 def test_wps_ext_ap_settings_missing(dev, apdev):
     """WPS and AP Settings: missing"""
     wps_run_ap_settings_proto(dev, apdev, None, False)
 
+@remote_compatible
 def test_wps_ext_ap_settings_mac_addr_mismatch(dev, apdev):
     """WPS and AP Settings: MAC Address mismatch"""
     ap_settings = build_wsc_attr(ATTR_NETWORK_INDEX, '\x01')
@@ -7694,6 +7800,7 @@ def test_wps_ext_ap_settings_mac_addr_mismatch(dev, apdev):
     ap_settings += build_wsc_attr(ATTR_MAC_ADDR, '\x00\x00\x00\x00\x00\x00')
     wps_run_ap_settings_proto(dev, apdev, ap_settings, True)
 
+@remote_compatible
 def test_wps_ext_ap_settings_mac_addr_missing(dev, apdev):
     """WPS and AP Settings: missing MAC Address"""
     ap_settings = build_wsc_attr(ATTR_NETWORK_INDEX, '\x01')
@@ -7703,6 +7810,7 @@ def test_wps_ext_ap_settings_mac_addr_missing(dev, apdev):
     ap_settings += build_wsc_attr(ATTR_NETWORK_KEY, '')
     wps_run_ap_settings_proto(dev, apdev, ap_settings, False)
 
+@remote_compatible
 def test_wps_ext_ap_settings_reject_encr_type(dev, apdev):
     """WPS and AP Settings: reject Encr Type"""
     ap_settings = build_wsc_attr(ATTR_NETWORK_INDEX, '\x01')
@@ -7713,6 +7821,7 @@ def test_wps_ext_ap_settings_reject_encr_type(dev, apdev):
     ap_settings += build_wsc_attr(ATTR_MAC_ADDR, binascii.unhexlify(apdev[0]['bssid'].replace(':', '')))
     wps_run_ap_settings_proto(dev, apdev, ap_settings, False)
 
+@remote_compatible
 def test_wps_ext_ap_settings_m2d(dev, apdev):
     """WPS and AP Settings: M2D"""
     addr,bssid,hapd = wps_start_ext_reg(apdev[0], dev[0])
@@ -7750,6 +7859,7 @@ def wps_wait_ap_nack(hapd, dev, e_nonce, r_nonce):
     send_wsc_msg(hapd, dev.own_addr(), nack)
     dev.wait_disconnected()
 
+@remote_compatible
 def test_wps_ext_m3_missing_e_hash1(dev, apdev):
     """WPS proto: M3 missing E-Hash1"""
     pin = "12345670"
@@ -7794,6 +7904,7 @@ def test_wps_ext_m3_missing_e_hash1(dev, apdev):
 
     wps_wait_ap_nack(hapd, dev[0], e_nonce, r_nonce)
 
+@remote_compatible
 def test_wps_ext_m3_missing_e_hash2(dev, apdev):
     """WPS proto: M3 missing E-Hash2"""
     pin = "12345670"
@@ -7838,6 +7949,7 @@ def test_wps_ext_m3_missing_e_hash2(dev, apdev):
 
     wps_wait_ap_nack(hapd, dev[0], e_nonce, r_nonce)
 
+@remote_compatible
 def test_wps_ext_m5_missing_e_snonce1(dev, apdev):
     """WPS proto: M5 missing E-SNonce1"""
     pin = "12345670"
@@ -7897,6 +8009,7 @@ def test_wps_ext_m5_missing_e_snonce1(dev, apdev):
 
     wps_wait_ap_nack(hapd, dev[0], e_nonce, r_nonce)
 
+@remote_compatible
 def test_wps_ext_m5_e_snonce1_mismatch(dev, apdev):
     """WPS proto: M5 E-SNonce1 mismatch"""
     pin = "12345670"
@@ -8028,6 +8141,7 @@ def test_wps_ext_m7_missing_e_snonce2(dev, apdev):
 
     wps_wait_ap_nack(hapd, dev[0], e_nonce, r_nonce)
 
+@remote_compatible
 def test_wps_ext_m7_e_snonce2_mismatch(dev, apdev):
     """WPS proto: M7 E-SNonce2 mismatch"""
     pin = "12345670"
@@ -8100,6 +8214,7 @@ def test_wps_ext_m7_e_snonce2_mismatch(dev, apdev):
 
     wps_wait_ap_nack(hapd, dev[0], e_nonce, r_nonce)
 
+@remote_compatible
 def test_wps_ext_m1_pubkey_oom(dev, apdev):
     """WPS proto: M1 PubKey OOM"""
     pin = "12345670"
@@ -8130,6 +8245,7 @@ def wps_wait_eap_failure(hapd, dev):
         raise Exception("EAP-Failure not reported")
     dev.wait_disconnected()
 
+@remote_compatible
 def test_wps_ext_m3_m1(dev, apdev):
     """WPS proto: M3 replaced with M1"""
     pin = "12345670"
@@ -8174,6 +8290,7 @@ def test_wps_ext_m3_m1(dev, apdev):
 
     wps_wait_eap_failure(hapd, dev[0])
 
+@remote_compatible
 def test_wps_ext_m5_m3(dev, apdev):
     """WPS proto: M5 replaced with M3"""
     pin = "12345670"
@@ -8232,6 +8349,7 @@ def test_wps_ext_m5_m3(dev, apdev):
 
     wps_wait_ap_nack(hapd, dev[0], e_nonce, r_nonce)
 
+@remote_compatible
 def test_wps_ext_m3_m2(dev, apdev):
     """WPS proto: M3 replaced with M2"""
     pin = "12345670"
@@ -8274,6 +8392,7 @@ def test_wps_ext_m3_m2(dev, apdev):
 
     wps_wait_eap_failure(hapd, dev[0])
 
+@remote_compatible
 def test_wps_ext_m3_m5(dev, apdev):
     """WPS proto: M3 replaced with M5"""
     pin = "12345670"
@@ -8318,6 +8437,7 @@ def test_wps_ext_m3_m5(dev, apdev):
 
     wps_wait_ap_nack(hapd, dev[0], e_nonce, r_nonce)
 
+@remote_compatible
 def test_wps_ext_m3_m7(dev, apdev):
     """WPS proto: M3 replaced with M7"""
     pin = "12345670"
@@ -8362,6 +8482,7 @@ def test_wps_ext_m3_m7(dev, apdev):
 
     wps_wait_ap_nack(hapd, dev[0], e_nonce, r_nonce)
 
+@remote_compatible
 def test_wps_ext_m3_done(dev, apdev):
     """WPS proto: M3 replaced with WSC_Done"""
     pin = "12345670"
@@ -8403,6 +8524,7 @@ def test_wps_ext_m3_done(dev, apdev):
 
     wps_wait_eap_failure(hapd, dev[0])
 
+@remote_compatible
 def test_wps_ext_m2_nack_invalid(dev, apdev):
     """WPS proto: M2 followed by invalid NACK"""
     pin = "12345670"
@@ -8441,6 +8563,7 @@ def test_wps_ext_m2_nack_invalid(dev, apdev):
 
     wps_wait_eap_failure(hapd, dev[0])
 
+@remote_compatible
 def test_wps_ext_m2_nack_no_msg_type(dev, apdev):
     """WPS proto: M2 followed by NACK without Msg Type"""
     pin = "12345670"
@@ -8479,6 +8602,7 @@ def test_wps_ext_m2_nack_no_msg_type(dev, apdev):
 
     wps_wait_eap_failure(hapd, dev[0])
 
+@remote_compatible
 def test_wps_ext_m2_nack_invalid_msg_type(dev, apdev):
     """WPS proto: M2 followed by NACK with invalid Msg Type"""
     pin = "12345670"
@@ -8517,6 +8641,7 @@ def test_wps_ext_m2_nack_invalid_msg_type(dev, apdev):
 
     wps_wait_eap_failure(hapd, dev[0])
 
+@remote_compatible
 def test_wps_ext_m2_nack_e_nonce_mismatch(dev, apdev):
     """WPS proto: M2 followed by NACK with e-nonce mismatch"""
     pin = "12345670"
@@ -8555,6 +8680,7 @@ def test_wps_ext_m2_nack_e_nonce_mismatch(dev, apdev):
 
     wps_wait_eap_failure(hapd, dev[0])
 
+@remote_compatible
 def test_wps_ext_m2_nack_no_config_error(dev, apdev):
     """WPS proto: M2 followed by NACK without Config Error"""
     pin = "12345670"
@@ -8593,6 +8719,7 @@ def test_wps_ext_m2_nack_no_config_error(dev, apdev):
 
     wps_wait_eap_failure(hapd, dev[0])
 
+@remote_compatible
 def test_wps_ext_m2_ack_invalid(dev, apdev):
     """WPS proto: M2 followed by invalid ACK"""
     pin = "12345670"
@@ -8631,6 +8758,7 @@ def test_wps_ext_m2_ack_invalid(dev, apdev):
 
     wps_wait_eap_failure(hapd, dev[0])
 
+@remote_compatible
 def test_wps_ext_m2_ack(dev, apdev):
     """WPS proto: M2 followed by ACK"""
     pin = "12345670"
@@ -8668,6 +8796,7 @@ def test_wps_ext_m2_ack(dev, apdev):
 
     wps_wait_eap_failure(hapd, dev[0])
 
+@remote_compatible
 def test_wps_ext_m2_ack_no_msg_type(dev, apdev):
     """WPS proto: M2 followed by ACK missing Msg Type"""
     pin = "12345670"
@@ -8706,6 +8835,7 @@ def test_wps_ext_m2_ack_no_msg_type(dev, apdev):
 
     wps_wait_eap_failure(hapd, dev[0])
 
+@remote_compatible
 def test_wps_ext_m2_ack_invalid_msg_type(dev, apdev):
     """WPS proto: M2 followed by ACK with invalid Msg Type"""
     pin = "12345670"
@@ -8744,6 +8874,7 @@ def test_wps_ext_m2_ack_invalid_msg_type(dev, apdev):
 
     wps_wait_eap_failure(hapd, dev[0])
 
+@remote_compatible
 def test_wps_ext_m2_ack_e_nonce_mismatch(dev, apdev):
     """WPS proto: M2 followed by ACK with e-nonce mismatch"""
     pin = "12345670"
@@ -8782,6 +8913,7 @@ def test_wps_ext_m2_ack_e_nonce_mismatch(dev, apdev):
 
     wps_wait_eap_failure(hapd, dev[0])
 
+@remote_compatible
 def test_wps_ext_m1_invalid(dev, apdev):
     """WPS proto: M1 failing parsing"""
     pin = "12345670"
@@ -8893,6 +9025,7 @@ def wps_ext_wsc_done(dev, apdev):
     msg, m8_attrs, raw_m8_attrs = recv_wsc_msg(hapd, WSC_MSG, WPS_M8)
     return hapd, msg, e_nonce, r_nonce
 
+@remote_compatible
 def test_wps_ext_wsc_done_invalid(dev, apdev):
     """WPS proto: invalid WSC_Done"""
     hapd, msg, e_nonce, r_nonce = wps_ext_wsc_done(dev, apdev)
@@ -8904,6 +9037,7 @@ def test_wps_ext_wsc_done_invalid(dev, apdev):
 
     wps_wait_eap_failure(hapd, dev[0])
 
+@remote_compatible
 def test_wps_ext_wsc_done_no_msg_type(dev, apdev):
     """WPS proto: invalid WSC_Done"""
     hapd, msg, e_nonce, r_nonce = wps_ext_wsc_done(dev, apdev)
@@ -8918,6 +9052,7 @@ def test_wps_ext_wsc_done_no_msg_type(dev, apdev):
 
     wps_wait_eap_failure(hapd, dev[0])
 
+@remote_compatible
 def test_wps_ext_wsc_done_wrong_msg_type(dev, apdev):
     """WPS proto: WSC_Done with wrong Msg Type"""
     hapd, msg, e_nonce, r_nonce = wps_ext_wsc_done(dev, apdev)
@@ -8932,6 +9067,7 @@ def test_wps_ext_wsc_done_wrong_msg_type(dev, apdev):
 
     wps_wait_eap_failure(hapd, dev[0])
 
+@remote_compatible
 def test_wps_ext_wsc_done_no_e_nonce(dev, apdev):
     """WPS proto: WSC_Done without e_nonce"""
     hapd, msg, e_nonce, r_nonce = wps_ext_wsc_done(dev, apdev)
@@ -8960,6 +9096,7 @@ def test_wps_ext_wsc_done_no_r_nonce(dev, apdev):
 
     wps_wait_eap_failure(hapd, dev[0])
 
+@remote_compatible
 def test_wps_ext_m7_no_encr_settings(dev, apdev):
     """WPS proto: M7 without Encr Settings"""
     pin = "12345670"
@@ -9032,6 +9169,7 @@ def test_wps_ext_m7_no_encr_settings(dev, apdev):
 
     wps_wait_ap_nack(hapd, dev[0], e_nonce, r_nonce)
 
+@remote_compatible
 def test_wps_ext_m1_workaround(dev, apdev):
     """WPS proto: M1 Manufacturer/Model workaround"""
     pin = "12345670"
@@ -9058,9 +9196,435 @@ def test_wps_ext_m1_workaround(dev, apdev):
     logger.debug("Receive M2 from AP")
     msg, m2_attrs, raw_m2_attrs = recv_wsc_msg(hapd, WSC_MSG, WPS_M2)
 
+@remote_compatible
 def test_ap_wps_disable_enable(dev, apdev):
     """WPS and DISABLE/ENABLE AP"""
     hapd = wps_start_ap(apdev[0])
     hapd.disable()
     hapd.enable()
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
+
+def test_ap_wps_upnp_web_oom(dev, apdev, params):
+    """hostapd WPS UPnP web OOM"""
+    ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
+    hapd = add_ssdp_ap(apdev[0], ap_uuid)
+
+    location = ssdp_get_location(ap_uuid)
+    url = urlparse.urlparse(location)
+    urls = upnp_get_urls(location)
+    eventurl = urlparse.urlparse(urls['event_sub_url'])
+    ctrlurl = urlparse.urlparse(urls['control_url'])
+
+    conn = httplib.HTTPConnection(url.netloc)
+    with alloc_fail(hapd, 1, "web_connection_parse_get"):
+        conn.request("GET", "/wps_device.xml")
+        try:
+            resp = conn.getresponse()
+        except:
+            pass
+
+    conn = httplib.HTTPConnection(url.netloc)
+    conn.request("GET", "/unknown")
+    resp = conn.getresponse()
+    if resp.status != 404:
+        raise Exception("Unexpected HTTP result for unknown URL: %d" + resp.status)
+
+    with alloc_fail(hapd, 1, "web_connection_parse_get"):
+        conn.request("GET", "/unknown")
+        try:
+            resp = conn.getresponse()
+            print resp.status
+        except:
+            pass
+
+    conn = httplib.HTTPConnection(url.netloc)
+    conn.request("GET", "/wps_device.xml")
+    resp = conn.getresponse()
+    if resp.status != 200:
+        raise Exception("GET /wps_device.xml failed")
+
+    conn = httplib.HTTPConnection(url.netloc)
+    resp = upnp_soap_action(conn, ctrlurl.path, "GetDeviceInfo")
+    if resp.status != 200:
+        raise Exception("GetDeviceInfo failed")
+
+    with alloc_fail(hapd, 1, "web_process_get_device_info"):
+        conn = httplib.HTTPConnection(url.netloc)
+        resp = upnp_soap_action(conn, ctrlurl.path, "GetDeviceInfo")
+        if resp.status != 500:
+            raise Exception("Internal error not reported from GetDeviceInfo OOM")
+
+    with alloc_fail(hapd, 1, "wps_build_m1;web_process_get_device_info"):
+        conn = httplib.HTTPConnection(url.netloc)
+        resp = upnp_soap_action(conn, ctrlurl.path, "GetDeviceInfo")
+        if resp.status != 500:
+            raise Exception("Internal error not reported from GetDeviceInfo OOM")
+
+    with alloc_fail(hapd, 1, "wpabuf_alloc;web_connection_send_reply"):
+        conn = httplib.HTTPConnection(url.netloc)
+        try:
+            resp = upnp_soap_action(conn, ctrlurl.path, "GetDeviceInfo")
+        except:
+            pass
+
+    conn = httplib.HTTPConnection(url.netloc)
+    resp = upnp_soap_action(conn, ctrlurl.path, "GetDeviceInfo")
+    if resp.status != 200:
+        raise Exception("GetDeviceInfo failed")
+
+    # No NewWLANEventType in PutWLANResponse NewMessage
+    conn = httplib.HTTPConnection(url.netloc)
+    resp = upnp_soap_action(conn, ctrlurl.path, "PutWLANResponse", newmsg="foo")
+    if resp.status != 600:
+        raise Exception("Unexpected HTTP response: %d" % resp.status)
+
+    # No NewWLANEventMAC in PutWLANResponse NewMessage
+    conn = httplib.HTTPConnection(url.netloc)
+    resp = upnp_soap_action(conn, ctrlurl.path, "PutWLANResponse",
+                            newmsg="foo", neweventtype="1")
+    if resp.status != 600:
+        raise Exception("Unexpected HTTP response: %d" % resp.status)
+
+    # Invalid NewWLANEventMAC in PutWLANResponse NewMessage
+    conn = httplib.HTTPConnection(url.netloc)
+    resp = upnp_soap_action(conn, ctrlurl.path, "PutWLANResponse",
+                            newmsg="foo", neweventtype="1",
+                            neweventmac="foo")
+    if resp.status != 600:
+        raise Exception("Unexpected HTTP response: %d" % resp.status)
+
+    # Workaround for NewWLANEventMAC in PutWLANResponse NewMessage
+    # Ignored unexpected PutWLANResponse WLANEventType 1
+    conn = httplib.HTTPConnection(url.netloc)
+    resp = upnp_soap_action(conn, ctrlurl.path, "PutWLANResponse",
+                            newmsg="foo", neweventtype="1",
+                            neweventmac="00.11.22.33.44.55")
+    if resp.status != 500:
+        raise Exception("Unexpected HTTP response: %d" % resp.status)
+
+    # PutWLANResponse NewMessage with invalid EAP message
+    conn = httplib.HTTPConnection(url.netloc)
+    resp = upnp_soap_action(conn, ctrlurl.path, "PutWLANResponse",
+                            newmsg="foo", neweventtype="2",
+                            neweventmac="00:11:22:33:44:55")
+    if resp.status != 200:
+        raise Exception("Unexpected HTTP response: %d" % resp.status)
+
+    with alloc_fail(hapd, 1, "web_connection_parse_subscribe"):
+        conn = httplib.HTTPConnection(url.netloc)
+        headers = { "callback": '<http://127.0.0.1:12345/event>',
+                    "NT": "upnp:event",
+                    "timeout": "Second-1234" }
+        conn.request("SUBSCRIBE", eventurl.path, "\r\n\r\n", headers)
+        try:
+            resp = conn.getresponse()
+        except:
+            pass
+
+    with alloc_fail(hapd, 1, "dup_binstr;web_connection_parse_subscribe"):
+        conn = httplib.HTTPConnection(url.netloc)
+        headers = { "callback": '<http://127.0.0.1:12345/event>',
+                    "NT": "upnp:event",
+                    "timeout": "Second-1234" }
+        conn.request("SUBSCRIBE", eventurl.path, "\r\n\r\n", headers)
+        resp = conn.getresponse()
+        if resp.status != 500:
+            raise Exception("Unexpected HTTP response: %d" % resp.status)
+
+    with alloc_fail(hapd, 1, "wpabuf_alloc;web_connection_parse_unsubscribe"):
+        conn = httplib.HTTPConnection(url.netloc)
+        headers = { "callback": '<http://127.0.0.1:12345/event>',
+                    "NT": "upnp:event",
+                    "timeout": "Second-1234" }
+        conn.request("UNSUBSCRIBE", eventurl.path, "\r\n\r\n", headers)
+        try:
+            resp = conn.getresponse()
+        except:
+            pass
+
+    with alloc_fail(hapd, 1, "web_connection_unimplemented"):
+        conn = httplib.HTTPConnection(url.netloc)
+        conn.request("HEAD", "/wps_device.xml")
+        try:
+            resp = conn.getresponse()
+        except:
+            pass
+
+def test_ap_wps_frag_ack_oom(dev, apdev):
+    """WPS and fragment ack OOM"""
+    dev[0].request("SET wps_fragment_size 50")
+    hapd = wps_start_ap(apdev[0])
+    with alloc_fail(hapd, 1, "eap_wsc_build_frag_ack"):
+        wps_run_pbc_fail_ap(apdev[0], dev[0], hapd)
+
+def wait_scan_stopped(dev):
+    dev.request("ABORT_SCAN")
+    for i in range(50):
+        res = dev.get_driver_status_field("scan_state")
+        if "SCAN_STARTED" not in res and "SCAN_REQUESTED" not in res:
+            break
+        logger.debug("Waiting for scan to complete")
+        time.sleep(0.1)
+
+@remote_compatible
+def test_ap_wps_eap_wsc_errors(dev, apdev):
+    """WPS and EAP-WSC error cases"""
+    ssid = "test-wps-conf-pin"
+    appin = "12345670"
+    params = { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+               "wpa_passphrase": "12345678", "wpa": "2",
+               "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
+               "fragment_size": "300", "ap_pin": appin }
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+
+    pin = dev[0].wps_read_pin()
+    hapd.request("WPS_PIN any " + pin)
+    dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
+    dev[0].dump_monitor()
+
+    dev[0].wps_reg(bssid, appin + " new_ssid=a", "new ssid", "WPA2PSK", "CCMP",
+                   "new passphrase", no_wait=True)
+    ev = dev[0].wait_event(["WPS-FAIL"], timeout=10)
+    if ev is None:
+        raise Exception("WPS-FAIL not reported")
+    dev[0].request("WPS_CANCEL")
+    dev[0].wait_disconnected()
+    wait_scan_stopped(dev[0])
+    dev[0].dump_monitor()
+
+    dev[0].wps_reg(bssid, appin, "new ssid", "FOO", "CCMP",
+                   "new passphrase", no_wait=True)
+    ev = dev[0].wait_event(["WPS-FAIL"], timeout=10)
+    if ev is None:
+        raise Exception("WPS-FAIL not reported")
+    dev[0].request("WPS_CANCEL")
+    dev[0].wait_disconnected()
+    wait_scan_stopped(dev[0])
+    dev[0].dump_monitor()
+
+    dev[0].wps_reg(bssid, appin, "new ssid", "WPA2PSK", "FOO",
+                   "new passphrase", no_wait=True)
+    ev = dev[0].wait_event(["WPS-FAIL"], timeout=10)
+    if ev is None:
+        raise Exception("WPS-FAIL not reported")
+    dev[0].request("WPS_CANCEL")
+    dev[0].wait_disconnected()
+    wait_scan_stopped(dev[0])
+    dev[0].dump_monitor()
+
+    dev[0].wps_reg(bssid, appin + "new_key=a", "new ssid", "WPA2PSK", "CCMP",
+                   "new passphrase", no_wait=True)
+    ev = dev[0].wait_event(["WPS-FAIL"], timeout=10)
+    if ev is None:
+        raise Exception("WPS-FAIL not reported")
+    dev[0].request("WPS_CANCEL")
+    dev[0].wait_disconnected()
+    wait_scan_stopped(dev[0])
+    dev[0].dump_monitor()
+
+    tests = [ "eap_wsc_init",
+              "eap_msg_alloc;eap_wsc_build_msg",
+              "wpabuf_alloc;eap_wsc_process_fragment" ]
+    for func in tests:
+        with alloc_fail(dev[0], 1, func):
+            dev[0].request("WPS_PIN %s %s" % (bssid, pin))
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("WPS_CANCEL")
+            dev[0].wait_disconnected()
+            wait_scan_stopped(dev[0])
+            dev[0].dump_monitor()
+
+    with alloc_fail(dev[0], 1, "eap_msg_alloc;eap_sm_build_expanded_nak"):
+        dev[0].wps_reg(bssid, appin + " new_ssid=a", "new ssid", "WPA2PSK",
+                       "CCMP", "new passphrase", no_wait=True)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("WPS_CANCEL")
+        dev[0].wait_disconnected()
+        wait_scan_stopped(dev[0])
+        dev[0].dump_monitor()
+
+def test_ap_wps_eap_wsc(dev, apdev):
+    """WPS and EAP-WSC in network profile"""
+    params = int_eap_server_params()
+    params["wps_state"] = "2"
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+
+    logger.info("Unexpected identity")
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="WSC", identity="WFA-SimpleConfig-Enrollee-unexpected",
+                   wait_connect=False)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+    if ev is None:
+        raise Exception("No EAP-Failure seen")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+    logger.info("No phase1 parameter")
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="WSC", identity="WFA-SimpleConfig-Enrollee-1-0",
+                   wait_connect=False)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on EAP method start")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+    if ev is None:
+        raise Exception("No EAP-Failure seen")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+    logger.info("No PIN/PBC in phase1")
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="WSC", identity="WFA-SimpleConfig-Enrollee-1-0",
+                   phase1="foo", wait_connect=False)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on EAP method start")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+    if ev is None:
+        raise Exception("No EAP-Failure seen")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+    logger.info("Invalid pkhash in phase1")
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="WSC", identity="WFA-SimpleConfig-Enrollee-1-0",
+                   phase1="foo pkhash=q pbc=1", wait_connect=False)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on EAP method start")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+    if ev is None:
+        raise Exception("No EAP-Failure seen")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+    logger.info("Zero fragment_size")
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="WSC", identity="WFA-SimpleConfig-Enrollee-1-0",
+                   fragment_size="0", phase1="pin=12345670", wait_connect=False)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on EAP method start")
+    ev = dev[0].wait_event(["WPS-M2D"], timeout=5)
+    if ev is None:
+        raise Exception("No M2D seen")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+    if ev is None:
+        raise Exception("No EAP-Failure seen")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+    logger.info("Missing new_auth")
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="WSC", identity="WFA-SimpleConfig-Enrollee-1-0",
+                   phase1="pin=12345670 new_ssid=aa", wait_connect=False)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on EAP method start")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+    if ev is None:
+        raise Exception("No EAP-Failure seen")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+    logger.info("Missing new_encr")
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="WSC", identity="WFA-SimpleConfig-Enrollee-1-0",
+                   phase1="pin=12345670 new_auth=WPA2PSK new_ssid=aa", wait_connect=False)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on EAP method start")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+    if ev is None:
+        raise Exception("No EAP-Failure seen")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+    logger.info("Missing new_key")
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="WSC", identity="WFA-SimpleConfig-Enrollee-1-0",
+                   phase1="pin=12345670 new_auth=WPA2PSK new_ssid=aa new_encr=CCMP",
+                   wait_connect=False)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on EAP method start")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+    if ev is None:
+        raise Exception("No EAP-Failure seen")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+def test_ap_wps_and_bss_limit(dev, apdev):
+    """WPS and wpa_supplicant BSS entry limit"""
+    try:
+        _test_ap_wps_and_bss_limit(dev, apdev)
+    finally:
+        dev[0].request("SET bss_max_count 200")
+        pass
+
+def _test_ap_wps_and_bss_limit(dev, apdev):
+    params = { "ssid": "test-wps", "eap_server": "1", "wps_state": "2",
+               "wpa_passphrase": "12345678", "wpa": "2",
+               "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP" }
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    params = { "ssid": "test-wps-2", "eap_server": "1", "wps_state": "2",
+               "wpa_passphrase": "1234567890", "wpa": "2",
+               "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP" }
+    hapd2 = hostapd.add_ap(apdev[1], params)
+
+    id = dev[1].add_network()
+    dev[1].set_network(id, "mode", "2")
+    dev[1].set_network_quoted(id, "ssid", "wpas-ap-no-wps")
+    dev[1].set_network_quoted(id, "psk", "12345678")
+    dev[1].set_network(id, "frequency", "2462")
+    dev[1].set_network(id, "scan_freq", "2462")
+    dev[1].set_network(id, "wps_disabled", "1")
+    dev[1].select_network(id)
+
+    id = dev[2].add_network()
+    dev[2].set_network(id, "mode", "2")
+    dev[2].set_network_quoted(id, "ssid", "wpas-ap")
+    dev[2].set_network_quoted(id, "psk", "12345678")
+    dev[2].set_network(id, "frequency", "2437")
+    dev[2].set_network(id, "scan_freq", "2437")
+    dev[2].select_network(id)
+
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    wpas.interface_add("wlan5")
+    id = wpas.add_network()
+    wpas.set_network(id, "mode", "2")
+    wpas.set_network_quoted(id, "ssid", "wpas-ap")
+    wpas.set_network_quoted(id, "psk", "12345678")
+    wpas.set_network(id, "frequency", "2437")
+    wpas.set_network(id, "scan_freq", "2437")
+    wpas.select_network(id)
+
+    dev[1].wait_connected()
+    dev[2].wait_connected()
+    wpas.wait_connected()
+    wpas.request("WPS_PIN any 12345670")
+
+    hapd.request("WPS_PBC")
+    hapd2.request("WPS_PBC")
+
+    dev[0].request("SET bss_max_count 1")
+
+    id = dev[0].add_network()
+    dev[0].set_network_quoted(id, "ssid", "testing")
+
+    id = dev[0].add_network()
+    dev[0].set_network_quoted(id, "ssid", "testing")
+    dev[0].set_network(id, "key_mgmt", "WPS")
+
+    dev[0].request("WPS_PBC")
+    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10)
+    dev[0].request("WPS_CANCEL")
+
+    id = dev[0].add_network()
+    dev[0].set_network_quoted(id, "ssid", "testing")
+    dev[0].set_network(id, "key_mgmt", "WPS")
+
+    dev[0].scan(freq="2412")
index 97d29e9..25db662 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import time
 import logging
 logger = logging.getLogger()
@@ -13,7 +14,7 @@ import hostapd
 
 def test_autoscan_periodic(dev, apdev):
     """autoscan_periodic"""
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "autoscan" })
+    hostapd.add_ap(apdev[0], { "ssid": "autoscan" })
 
     try:
         if "OK" not in dev[0].request("AUTOSCAN periodic:1"):
@@ -51,9 +52,10 @@ def test_autoscan_periodic(dev, apdev):
     finally:
         dev[0].request("AUTOSCAN ")
 
+@remote_compatible
 def test_autoscan_exponential(dev, apdev):
     """autoscan_exponential"""
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "autoscan" })
+    hostapd.add_ap(apdev[0], { "ssid": "autoscan" })
 
     try:
         if "OK" not in dev[0].request("AUTOSCAN exponential:2:10"):
index c73fdeb..0df6da7 100644 (file)
@@ -13,8 +13,8 @@ import hostapd
 
 def test_bgscan_simple(dev, apdev):
     """bgscan_simple"""
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "bgscan" })
-    hostapd.add_ap(apdev[1]['ifname'], { "ssid": "bgscan" })
+    hostapd.add_ap(apdev[0], { "ssid": "bgscan" })
+    hostapd.add_ap(apdev[1], { "ssid": "bgscan" })
 
     dev[0].connect("bgscan", key_mgmt="NONE", scan_freq="2412",
                    bgscan="simple:1:-20:2")
@@ -70,8 +70,8 @@ def test_bgscan_simple(dev, apdev):
 
 def test_bgscan_learn(dev, apdev):
     """bgscan_learn"""
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "bgscan" })
-    hostapd.add_ap(apdev[1]['ifname'], { "ssid": "bgscan" })
+    hostapd.add_ap(apdev[0], { "ssid": "bgscan" })
+    hostapd.add_ap(apdev[1], { "ssid": "bgscan" })
 
     try:
         os.remove("/tmp/test_bgscan_learn.bgscan")
index e67ad98..b212961 100644 (file)
@@ -4,17 +4,18 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 import binascii
 import os
-import subprocess
 import time
 
 import hostapd
 import hwsim_utils
 from tshark import run_tshark
 from nl80211 import *
+from wpasupplicant import WpaSupplicant
 
 def nl80211_command(dev, cmd, attr):
     res = dev.request("VENDOR ffffffff {} {}".format(nl80211_cmd[cmd],
@@ -23,9 +24,10 @@ def nl80211_command(dev, cmd, attr):
         raise Exception("nl80211 command failed")
     return binascii.unhexlify(res)
 
+@remote_compatible
 def test_cfg80211_disassociate(dev, apdev):
     """cfg80211 disassociation command"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
     ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
     if ev is None:
@@ -65,12 +67,12 @@ def nl80211_remain_on_channel(dev, ifindex, freq, duration):
 
 def test_cfg80211_tx_frame(dev, apdev, params):
     """cfg80211 offchannel TX frame command"""
-    ifindex = int(dev[0].get_driver_status_field("ifindex"))
-
-    frame = binascii.unhexlify("d000000002000000010002000000000002000000010000000409506f9a090001dd5e506f9a0902020025080401001f0502006414060500585804510b0906000200000000000b1000585804510b0102030405060708090a0b0d1d000200000000000108000000000000000000101100084465766963652041110500585804510bdd190050f204104a0001101012000200011049000600372a000120")
 
-    dev[0].request("P2P_GROUP_ADD freq=2412")
-    res = nl80211_frame(dev[0], ifindex, frame, freq=2422, duration=500,
+    dev[0].p2p_start_go(freq='2412')
+    go = WpaSupplicant(dev[0].group_ifname)
+    frame = binascii.unhexlify("d0000000020000000100" + go.own_addr().translate(None, ':') + "02000000010000000409506f9a090001dd5e506f9a0902020025080401001f0502006414060500585804510b0906000200000000000b1000585804510b0102030405060708090a0b0d1d000200000000000108000000000000000000101100084465766963652041110500585804510bdd190050f204104a0001101012000200011049000600372a000120")
+    ifindex = int(go.get_driver_status_field("ifindex"))
+    res = nl80211_frame(go, ifindex, frame, freq=2422, duration=500,
                         offchannel_tx_ok=True)
     time.sleep(0.1)
 
@@ -78,11 +80,13 @@ def test_cfg80211_tx_frame(dev, apdev, params):
     #nl80211_frame_wait_cancel(dev[0], ifindex, res[nl80211_attr['COOKIE']])
 
     # note: this Action frame ends up getting sent incorrectly on 2422 MHz
-    nl80211_frame(dev[0], ifindex, frame, freq=2412)
+    nl80211_frame(go, ifindex, frame, freq=2412)
     time.sleep(1.5)
     # note: also the Deauthenticate frame sent by the GO going down ends up
     # being transmitted incorrectly on 2422 MHz.
 
+    del go
+
     out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
                      "wlan.fc.type_subtype == 13", ["radiotap.channel.freq"])
     if out is not None:
@@ -94,9 +98,10 @@ def test_cfg80211_tx_frame(dev, apdev, params):
         if freq[1] != "2412":
             raise Exception("Second Action frame on unexpected channel: %s MHz" % freq[1])
 
+@remote_compatible
 def test_cfg80211_wep_key_idx_change(dev, apdev):
     """WEP Shared Key authentication and key index change without deauth"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'],
+    hapd = hostapd.add_ap(apdev[0],
                           { "ssid": "wep-shared-key",
                             "wep_key0": '"hello12345678"',
                             "wep_key1": '"other12345678"',
@@ -123,9 +128,10 @@ def test_cfg80211_wep_key_idx_change(dev, apdev):
     dev[0].wait_connected(timeout=10, error="Reassociation timed out")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_cfg80211_hostapd_ext_sta_remove(dev, apdev):
     """cfg80211 DEL_STATION issued externally to hostapd"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'],
+    hapd = hostapd.add_ap(apdev[0],
                           { "ssid": "open" })
     id = dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
 
index 3f4c42b..4f2bf49 100644 (file)
@@ -11,83 +11,98 @@ import time
 import hwsim_utils
 import hostapd
 from wpasupplicant import WpaSupplicant
-from test_p2p_grpform import go_neg_pin_authorized
-from test_p2p_grpform import check_grpform_results
-from test_p2p_grpform import remove_group
+from p2p_utils import *
 
 def test_connect_cmd_open(dev, apdev):
     """Open connection using cfg80211 connect command"""
     params = { "ssid": "sta-connect",
                "manage_p2p": "1",
                "allow_cross_connection": "1" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
     wpas.connect("sta-connect", key_mgmt="NONE", scan_freq="2412",
                  bg_scan_period="1")
+    wpas.dump_monitor()
     wpas.request("DISCONNECT")
+    wpas.wait_disconnected()
+    wpas.dump_monitor()
 
 def test_connect_cmd_wep(dev, apdev):
     """WEP Open System using cfg80211 connect command"""
     params = { "ssid": "sta-connect-wep", "wep_key0": '"hello"' }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
     wpas.connect("sta-connect-wep", key_mgmt="NONE", scan_freq="2412",
                  wep_key0='"hello"')
+    wpas.dump_monitor()
     hwsim_utils.test_connectivity(wpas, hapd)
     wpas.request("DISCONNECT")
+    wpas.wait_disconnected()
+    wpas.dump_monitor()
 
 def test_connect_cmd_wep_shared(dev, apdev):
     """WEP Shared key using cfg80211 connect command"""
     params = { "ssid": "sta-connect-wep", "wep_key0": '"hello"',
                "auth_algs": "2" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
     id = wpas.connect("sta-connect-wep", key_mgmt="NONE", scan_freq="2412",
                       auth_alg="SHARED", wep_key0='"hello"')
+    wpas.dump_monitor()
     hwsim_utils.test_connectivity(wpas, hapd)
     wpas.request("DISCONNECT")
     wpas.remove_network(id)
     wpas.connect("sta-connect-wep", key_mgmt="NONE", scan_freq="2412",
                  auth_alg="OPEN SHARED", wep_key0='"hello"')
+    wpas.dump_monitor()
     hwsim_utils.test_connectivity(wpas, hapd)
     wpas.request("DISCONNECT")
+    wpas.wait_disconnected()
+    wpas.dump_monitor()
 
 def test_connect_cmd_p2p_management(dev, apdev):
     """Open connection using cfg80211 connect command and AP using P2P management"""
     params = { "ssid": "sta-connect",
                "manage_p2p": "1",
                "allow_cross_connection": "0" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
     wpas.connect("sta-connect", key_mgmt="NONE", scan_freq="2412")
+    wpas.dump_monitor()
     wpas.request("DISCONNECT")
+    wpas.wait_disconnected()
+    wpas.dump_monitor()
 
 def test_connect_cmd_wpa2_psk(dev, apdev):
     """WPA2-PSK connection using cfg80211 connect command"""
     params = hostapd.wpa2_params(ssid="sta-connect", passphrase="12345678")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
     wpas.connect("sta-connect", psk="12345678", scan_freq="2412")
+    wpas.dump_monitor()
     wpas.request("DISCONNECT")
+    wpas.wait_disconnected()
+    wpas.dump_monitor()
 
 def test_connect_cmd_concurrent_grpform_while_connecting(dev, apdev):
     """Concurrent P2P group formation while connecting to an AP using cfg80211 connect command"""
     logger.info("Start connection to an infrastructure AP")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-open" })
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
     wpas.connect("test-open", key_mgmt="NONE", wait_connect=False)
+    wpas.dump_monitor()
 
     logger.info("Form a P2P group while connecting to an AP")
     wpas.request("SET p2p_no_group_iface 0")
@@ -96,15 +111,20 @@ def test_connect_cmd_concurrent_grpform_while_connecting(dev, apdev):
                                            r_dev=wpas, r_freq=2412)
     check_grpform_results(i_res, r_res)
     remove_group(dev[0], wpas)
+    wpas.dump_monitor()
 
     logger.info("Confirm AP connection after P2P group removal")
     hwsim_utils.test_connectivity(wpas, hapd)
 
+    wpas.request("DISCONNECT")
+    wpas.wait_disconnected()
+    wpas.dump_monitor()
+
 def test_connect_cmd_reject_assoc(dev, apdev):
     """Connection using cfg80211 connect command getting rejected"""
     params = { "ssid": "sta-connect",
                "require_ht": "1" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
@@ -119,10 +139,13 @@ def test_connect_cmd_reject_assoc(dev, apdev):
         if "status_code=27" not in ev:
             raise Exception("Unexpected rejection status code")
 
+    wpas.request("DISCONNECT")
+    wpas.dump_monitor()
+
 def test_connect_cmd_disconnect_event(dev, apdev):
     """Connection using cfg80211 connect command getting disconnected by the AP"""
     params = { "ssid": "sta-connect" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
@@ -138,16 +161,30 @@ def test_connect_cmd_disconnect_event(dev, apdev):
     # testing purposes. Anyway, wait some time to allow the debug log to capture
     # the following NL80211_CMD_DISCONNECT event.
     time.sleep(0.1)
+    wpas.dump_monitor()
+
+    # Clean up to avoid causing issue for following test cases
+    wpas.request("REMOVE_NETWORK all")
+    wpas.wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=2)
+    wpas.flush_scan_cache()
+    wpas.dump_monitor()
+    wpas.interface_remove("wlan5")
+    del wpas
 
 def test_connect_cmd_roam(dev, apdev):
     """cfg80211 connect command to trigger roam"""
     params = { "ssid": "sta-connect" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
     wpas.connect("sta-connect", key_mgmt="NONE", scan_freq="2412")
+    wpas.dump_monitor()
 
-    hostapd.add_ap(apdev[1]['ifname'], params)
-    wpas.scan_for_bss(apdev[1]['bssid'], freq=2412)
+    hostapd.add_ap(apdev[1], params)
+    wpas.scan_for_bss(apdev[1]['bssid'], freq=2412, force_scan=True)
     wpas.roam(apdev[1]['bssid'])
+    time.sleep(0.1)
+    wpas.request("DISCONNECT")
+    wpas.wait_disconnected()
+    wpas.dump_monitor()
index dba899e..451434d 100644 (file)
@@ -20,7 +20,9 @@ except ImportError:
 import hostapd
 from wpasupplicant import WpaSupplicant
 from utils import HwsimSkip, alloc_fail, fail_test
+from p2p_utils import *
 from test_ap_tdls import connect_2sta_open
+from test_ap_eap import check_altsubject_match_support
 
 WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1"
 WPAS_DBUS_PATH = "/fi/w1/wpa_supplicant1"
@@ -97,7 +99,7 @@ def start_ap(ap, ssid="test-wps",
                "wpa_passphrase": "12345678", "wpa": "2",
                "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
                "ap_pin": "12345670", "uuid": ap_uuid}
-    return hostapd.add_ap(ap['ifname'], params)
+    return hostapd.add_ap(ap, params)
 
 def test_dbus_getall(dev, apdev):
     """D-Bus GetAll"""
@@ -125,7 +127,7 @@ def test_dbus_getall(dev, apdev):
     if len(res) != 0:
         raise Exception("Unexpected Networks entry: " + str(res))
 
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     bssid = apdev[0]['bssid']
     dev[0].scan_for_bss(bssid, freq=2412)
     id = dev[0].add_network()
@@ -159,6 +161,27 @@ def test_dbus_getall(dev, apdev):
     if ssid != '"test"':
         raise Exception("Unexpected SSID in network entry")
 
+def test_dbus_getall_oom(dev, apdev):
+    """D-Bus GetAll wpa_config_get_all() OOM"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    id = dev[0].add_network()
+    dev[0].set_network(id, "disabled", "0")
+    dev[0].set_network_quoted(id, "ssid", "test")
+
+    res = if_obj.Get(WPAS_DBUS_IFACE, 'Networks',
+                     dbus_interface=dbus.PROPERTIES_IFACE)
+    if len(res) != 1:
+        raise Exception("Missing Networks entry: " + str(res))
+    net_obj = bus.get_object(WPAS_DBUS_SERVICE, res[0])
+    for i in range(1, 50):
+        with alloc_fail(dev[0], i, "wpa_config_get_all"):
+            try:
+                props = net_obj.GetAll(WPAS_DBUS_NETWORK,
+                                       dbus_interface=dbus.PROPERTIES_IFACE)
+            except dbus.exceptions.DBusException, e:
+                pass
+
 def dbus_get(dbus, wpas_obj, prop, expect=None, byte_arrays=False):
     val = wpas_obj.Get(WPAS_DBUS_SERVICE, prop,
                        dbus_interface=dbus.PROPERTIES_IFACE,
@@ -295,6 +318,26 @@ def test_dbus_properties(dev, apdev):
         if "InvalidArgs: invalid message format" not in str(e):
             raise Exception("Unexpected error message: " + str(e))
 
+def test_dbus_set_global_properties(dev, apdev):
+    """D-Bus Get/Set fi.w1.wpa_supplicant1 interface global properties"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+
+    props = [ ('Okc', '0', '1'), ('ModelName', '', 'blahblahblah') ]
+
+    for p in props:
+        res = if_obj.Get(WPAS_DBUS_IFACE, p[0],
+                         dbus_interface=dbus.PROPERTIES_IFACE)
+        if res != p[1]:
+            raise Exception("Unexpected " + p[0] + " value: " + str(res))
+
+        if_obj.Set(WPAS_DBUS_IFACE, p[0], p[2],
+                   dbus_interface=dbus.PROPERTIES_IFACE)
+
+        res = if_obj.Get(WPAS_DBUS_IFACE, p[0],
+                         dbus_interface=dbus.PROPERTIES_IFACE)
+        if res != p[2]:
+            raise Exception("Unexpected " + p[0] + " value after set: " + str(res))
+
 def test_dbus_invalid_method(dev, apdev):
     """D-Bus invalid method"""
     (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
@@ -397,13 +440,13 @@ def _test_dbus_get_set_wps(dev, apdev):
                        dbus_interface=dbus.PROPERTIES_IFACE)
             if if_obj.Get(WPAS_DBUS_IFACE_WPS, "ProcessCredentials",
                           dbus_interface=dbus.PROPERTIES_IFACE) != True:
-                raise Exception("Unexpected Get(ProcessCredentials) result after Set");
+                raise Exception("Unexpected Get(ProcessCredentials) result after Set")
             if_obj.Set(WPAS_DBUS_IFACE_WPS, "ProcessCredentials",
                        dbus.Boolean(0),
                        dbus_interface=dbus.PROPERTIES_IFACE)
             if if_obj.Get(WPAS_DBUS_IFACE_WPS, "ProcessCredentials",
                           dbus_interface=dbus.PROPERTIES_IFACE) != False:
-                raise Exception("Unexpected Get(ProcessCredentials) result after Set");
+                raise Exception("Unexpected Get(ProcessCredentials) result after Set")
 
             self.dbus_sets_done = True
             return False
@@ -454,10 +497,11 @@ def test_dbus_wps_oom(dev, apdev):
         if_obj.Get(WPAS_DBUS_IFACE, "State",
                    dbus_interface=dbus.PROPERTIES_IFACE)
 
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     bssid = apdev[0]['bssid']
     dev[0].scan_for_bss(bssid, freq=2412)
 
+    time.sleep(0.05)
     for i in range(1, 3):
         with alloc_fail_dbus(dev[0], i, "=wpas_dbus_getter_bsss", "Get"):
             if_obj.Get(WPAS_DBUS_IFACE, "BSSs",
@@ -469,6 +513,13 @@ def test_dbus_wps_oom(dev, apdev):
     with alloc_fail_dbus(dev[0], 1, "=wpas_dbus_getter_bss_rates", "Get"):
         bss_obj.Get(WPAS_DBUS_BSS, "Rates",
                     dbus_interface=dbus.PROPERTIES_IFACE)
+    with alloc_fail(dev[0], 1,
+                    "wpa_bss_get_bit_rates;wpas_dbus_getter_bss_rates"):
+        try:
+            bss_obj.Get(WPAS_DBUS_BSS, "Rates",
+                        dbus_interface=dbus.PROPERTIES_IFACE)
+        except dbus.exceptions.DBusException, e:
+            pass
 
     id = dev[0].add_network()
     dev[0].set_network(id, "disabled", "0")
@@ -968,7 +1019,7 @@ def test_dbus_scan(dev, apdev):
     (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
     iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
 
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
 
     class TestDbusScan(TestDbus):
         def __init__(self, bus):
@@ -1074,7 +1125,7 @@ def test_dbus_connect(dev, apdev):
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     class TestDbusConnect(TestDbus):
         def __init__(self, bus):
@@ -1177,7 +1228,7 @@ def test_dbus_connect_psk_mem(dev, apdev):
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     class TestDbusConnect(TestDbus):
         def __init__(self, bus):
@@ -1234,7 +1285,7 @@ def test_dbus_connect_oom(dev, apdev):
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     class TestDbusConnect(TestDbus):
         def __init__(self, bus):
@@ -1354,6 +1405,17 @@ def test_dbus_connect_oom(dev, apdev):
         except:
             pass
 
+    # Force regulatory update to re-fetch hw capabilities for the following
+    # test cases.
+    try:
+        dev[0].dump_monitor()
+        subprocess.call(['iw', 'reg', 'set', 'US'])
+        ev = dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=1)
+    finally:
+        dev[0].dump_monitor()
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        ev = dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=1)
+
 def test_dbus_while_not_connected(dev, apdev):
     """D-Bus invalid operations while not connected"""
     (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
@@ -1375,6 +1437,7 @@ def test_dbus_while_not_connected(dev, apdev):
 
 def test_dbus_connect_eap(dev, apdev):
     """D-Bus AddNetwork and connect to EAP network"""
+    check_altsubject_match_support(dev[0])
     (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
     iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
 
@@ -1382,7 +1445,7 @@ def test_dbus_connect_eap(dev, apdev):
     params = hostapd.radius_params()
     params["ssid"] = ssid
     params["ieee8021x"] = "1"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     class TestDbusConnect(TestDbus):
         def __init__(self, bus):
@@ -1682,6 +1745,24 @@ def test_dbus_network_oom(dev, apdev):
 
 def test_dbus_interface(dev, apdev):
     """D-Bus CreateInterface/GetInterface/RemoveInterface parameters and error cases"""
+    try:
+        _test_dbus_interface(dev, apdev)
+    finally:
+        # Need to force P2P channel list update since the 'lo' interface
+        # with driver=none ends up configuring default dualband channels.
+        dev[0].request("SET country US")
+        ev = dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=1)
+        if ev is None:
+            ev = dev[0].wait_global_event(["CTRL-EVENT-REGDOM-CHANGE"],
+                                          timeout=1)
+        dev[0].request("SET country 00")
+        ev = dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=1)
+        if ev is None:
+            ev = dev[0].wait_global_event(["CTRL-EVENT-REGDOM-CHANGE"],
+                                          timeout=1)
+        subprocess.call(['iw', 'reg', 'set', '00'])
+
+def _test_dbus_interface(dev, apdev):
     (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
     wpas = dbus.Interface(wpas_obj, WPAS_DBUS_SERVICE)
 
@@ -1882,7 +1963,7 @@ def test_dbus_tdls_invalid(dev, apdev):
     (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
     iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
 
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-open" })
     connect_2sta_open(dev, hapd)
     addr1 = dev[1].p2p_interface_addr()
 
@@ -1939,7 +2020,7 @@ def test_dbus_tdls(dev, apdev):
     (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
     iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
 
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-open" })
     connect_2sta_open(dev, hapd)
 
     addr1 = dev[1].p2p_interface_addr()
@@ -2220,7 +2301,9 @@ def _test_dbus_country(dev, apdev):
         ev = dev[0].wait_global_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=1)
         if ev is None:
             raise Exception("regdom change event not seen")
-    if "init=CORE type=WORLD" not in ev:
+    # init=CORE was previously used due to invalid db.txt data for 00. For
+    # now, allow both it and the new init=USER after fixed db.txt.
+    if "init=CORE type=WORLD" not in ev and "init=USER type=WORLD" not in ev:
         raise Exception("Unexpected event contents: " + ev)
 
 def test_dbus_scan_interval(dev, apdev):
@@ -2665,6 +2748,7 @@ def test_dbus_p2p_discovery(dev, apdev):
             TestDbus.__init__(self, bus)
             self.found = False
             self.found2 = False
+            self.found_prop = False
             self.lost = False
             self.find_stopped = False
 
@@ -2673,6 +2757,8 @@ def test_dbus_p2p_discovery(dev, apdev):
             gobject.timeout_add(15000, self.timeout)
             self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
                             "DeviceFound")
+            self.add_signal(self.deviceFoundProperties,
+                            WPAS_DBUS_IFACE_P2PDEVICE, "DeviceFoundProperties")
             self.add_signal(self.deviceLost, WPAS_DBUS_IFACE_P2PDEVICE,
                             "DeviceLost")
             self.add_signal(self.provisionDiscoveryResponseEnterPin,
@@ -2740,6 +2826,12 @@ def test_dbus_p2p_discovery(dev, apdev):
                     raise Exception("Unexpected error message for invalid RejectPeer(): " + str(e))
             self.loop.quit()
 
+        def deviceFoundProperties(self, path, properties):
+            logger.debug("deviceFoundProperties: path=%s" % path)
+            logger.debug("peer properties: " + str(properties))
+            if properties['DeviceAddress'] == a1:
+                self.found_prop = True
+
         def provisionDiscoveryResponseEnterPin(self, peer_object):
             logger.debug("provisionDiscoveryResponseEnterPin - peer=%s" % peer_object)
             p2p.Flush()
@@ -3605,6 +3697,55 @@ def test_dbus_p2p_join(dev, apdev):
 
     dev[2].p2p_stop_find()
 
+def test_dbus_p2p_invitation_received(dev, apdev):
+    """D-Bus P2P and InvitationReceived"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
+
+    form(dev[0], dev[1])
+    addr0 = dev[0].p2p_dev_addr()
+    dev[0].p2p_listen()
+    dev[0].global_request("SET persistent_reconnect 0")
+
+    if not dev[1].discover_peer(addr0, social=True):
+        raise Exception("Peer " + addr0 + " not found")
+    peer = dev[1].get_peer(addr0)
+
+    class TestDbusP2p(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.done = False
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_test)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.invitationReceived, WPAS_DBUS_IFACE_P2PDEVICE,
+                            "InvitationReceived")
+            self.loop.run()
+            return self
+
+        def invitationReceived(self, result):
+            logger.debug("invitationReceived: " + str(result))
+            self.done = True
+            self.loop.quit()
+
+        def run_test(self, *args):
+            logger.debug("run_test")
+            dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
+            cmd = "P2P_INVITE persistent=" + peer['persistent'] + " peer=" + addr0
+            dev1.global_request(cmd)
+            return False
+
+        def success(self):
+            return self.done
+
+    with TestDbusP2p(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
+
+    dev[0].p2p_stop_find()
+    dev[1].p2p_stop_find()
+
 def test_dbus_p2p_config(dev, apdev):
     """D-Bus Get/Set P2PDeviceConfig"""
     try:
@@ -4070,7 +4211,7 @@ def test_dbus_p2p_go_neg_auth(dev, apdev):
             if not dev1.discover_peer(addr0):
                 raise Exception("Peer not found")
             dev1.global_request("P2P_CONNECT " + addr0 + " 12345670 display go_intent=0")
-            ev = dev1.wait_global_event(["P2P-GROUP-STARTED"], timeout=15);
+            ev = dev1.wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
             if ev is None:
                 raise Exception("Group formation timed out")
             self.sta_group_ev = ev
@@ -4159,7 +4300,7 @@ def test_dbus_p2p_go_neg_init(dev, apdev):
             if ev is None:
                 raise Exception("Timeout while waiting for GO Neg Request")
             dev1.global_request("P2P_CONNECT " + addr0 + " 12345670 display go_intent=15")
-            ev = dev1.wait_global_event(["P2P-GROUP-STARTED"], timeout=15);
+            ev = dev1.wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
             if ev is None:
                 raise Exception("Group formation timed out")
             self.sta_group_ev = ev
@@ -4249,7 +4390,7 @@ def test_dbus_p2p_group_termination_by_go(dev, apdev):
             if ev is None:
                 raise Exception("Timeout while waiting for GO Neg Request")
             dev1.global_request("P2P_CONNECT " + addr0 + " 12345670 display go_intent=15")
-            ev = dev1.wait_global_event(["P2P-GROUP-STARTED"], timeout=15);
+            ev = dev1.wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
             if ev is None:
                 raise Exception("Group formation timed out")
             self.sta_group_ev = ev
@@ -4312,6 +4453,7 @@ def _test_dbus_p2p_group_idle_timeout(dev, apdev):
         def __init__(self, bus):
             TestDbus.__init__(self, bus)
             self.done = False
+            self.group_started = False
             self.peer_group_added = False
             self.peer_group_removed = False
 
@@ -4344,7 +4486,7 @@ def _test_dbus_p2p_group_idle_timeout(dev, apdev):
             if ev is None:
                 raise Exception("Timeout while waiting for GO Neg Request")
             dev1.global_request("P2P_CONNECT " + addr0 + " 12345670 display go_intent=15")
-            ev = dev1.wait_global_event(["P2P-GROUP-STARTED"], timeout=15);
+            ev = dev1.wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
             if ev is None:
                 raise Exception("Group formation timed out")
             self.sta_group_ev = ev
@@ -4354,6 +4496,7 @@ def _test_dbus_p2p_group_idle_timeout(dev, apdev):
 
         def groupStarted(self, properties):
             logger.debug("groupStarted: " + str(properties))
+            self.group_started = True
             g_if_obj = bus.get_object(WPAS_DBUS_SERVICE,
                                       properties['interface_object'])
             dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
@@ -4374,6 +4517,8 @@ def _test_dbus_p2p_group_idle_timeout(dev, apdev):
             logger.debug("propertiesChanged: interface_name=%s changed_properties=%s invalidated_properties=%s" % (interface_name, str(changed_properties), str(invalidated_properties)))
             if interface_name != WPAS_DBUS_P2P_PEER:
                 return
+            if not self.group_started:
+                return
             if "Groups" not in changed_properties:
                 return
             if len(changed_properties["Groups"]) > 0:
@@ -4576,7 +4721,7 @@ def test_dbus_p2p_two_groups(dev, apdev):
                 dev2 = WpaSupplicant('wlan2', '/tmp/wpas-wlan2')
                 dev2.scan_for_bss(bssid, freq=2412)
                 dev2.global_request("P2P_CONNECT " + bssid + " 12345670 join freq=2412")
-                ev = dev2.wait_global_event(["P2P-GROUP-STARTED"], timeout=15);
+                ev = dev2.wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
                 if ev is None:
                     raise Exception("Group join timed out")
                 self.dev2_group_ev = ev
@@ -4717,6 +4862,8 @@ def test_dbus_introspect(dev, apdev):
     logger.info("Initial Introspect: " + str(res))
     if res is None or "Introspectable" not in res or "GroupStarted" not in res:
         raise Exception("Unexpected initial Introspect response: " + str(res))
+    if "FastReauth" not in res or "PassiveScan" not in res:
+        raise Exception("Unexpected initial Introspect response: " + str(res))
 
     with alloc_fail(dev[0], 1, "wpa_dbus_introspect"):
         res2 = if_obj.Introspect(WPAS_DBUS_IFACE,
@@ -4819,7 +4966,7 @@ def test_dbus_connect_wpa_eap(dev, apdev):
     params = hostapd.wpa_eap_params(ssid=ssid)
     params["wpa"] = "3"
     params["rsn_pairwise"] = "CCMP"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     class TestDbusConnect(TestDbus):
         def __init__(self, bus):
@@ -4916,3 +5063,191 @@ def _test_dbus_ap_scan_2_ap_mode_scan(dev, apdev):
     dev[1].wait_disconnected()
     dev[0].request("DISCONNECT")
     dev[0].wait_disconnected()
+
+def test_dbus_expectdisconnect(dev, apdev):
+    """D-Bus ExpectDisconnect"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    wpas = dbus.Interface(wpas_obj, WPAS_DBUS_SERVICE)
+
+    params = { "ssid": "test-open" }
+    hapd = hostapd.add_ap(apdev[0], params)
+    dev[0].connect("test-open", key_mgmt="NONE", scan_freq="2412")
+
+    # This does not really verify the behavior other than by going through the
+    # code path for additional coverage.
+    wpas.ExpectDisconnect()
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+def test_dbus_save_config(dev, apdev):
+    """D-Bus SaveConfig"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+    try:
+        iface.SaveConfig()
+        raise Exception("SaveConfig() accepted unexpectedly")
+    except dbus.exceptions.DBusException, e:
+        if not str(e).startswith("fi.w1.wpa_supplicant1.UnknownError: Not allowed to update configuration"):
+            raise Exception("Unexpected error message for SaveConfig(): " + str(e))
+
+def test_dbus_vendor_elem(dev, apdev):
+    """D-Bus vendor element operations"""
+    try:
+        _test_dbus_vendor_elem(dev, apdev)
+    finally:
+        dev[0].request("VENDOR_ELEM_REMOVE 1 *")
+
+def _test_dbus_vendor_elem(dev, apdev):
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    dev[0].request("VENDOR_ELEM_REMOVE 1 *")
+
+    try:
+        ie = dbus.ByteArray("\x00\x00")
+        iface.VendorElemAdd(-1, ie)
+        raise Exception("Invalid VendorElemAdd() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e) or "Invalid ID" not in str(e):
+            raise Exception("Unexpected error message for invalid VendorElemAdd[1]: " + str(e))
+
+    try:
+        ie = dbus.ByteArray("")
+        iface.VendorElemAdd(1, ie)
+        raise Exception("Invalid VendorElemAdd() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e) or "Invalid value" not in str(e):
+            raise Exception("Unexpected error message for invalid VendorElemAdd[2]: " + str(e))
+
+    try:
+        ie = dbus.ByteArray("\x00\x01")
+        iface.VendorElemAdd(1, ie)
+        raise Exception("Invalid VendorElemAdd() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e) or "Parse error" not in str(e):
+            raise Exception("Unexpected error message for invalid VendorElemAdd[3]: " + str(e))
+
+    try:
+        iface.VendorElemGet(-1)
+        raise Exception("Invalid VendorElemGet() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e) or "Invalid ID" not in str(e):
+            raise Exception("Unexpected error message for invalid VendorElemGet[1]: " + str(e))
+
+    try:
+        iface.VendorElemGet(1)
+        raise Exception("Invalid VendorElemGet() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e) or "ID value does not exist" not in str(e):
+            raise Exception("Unexpected error message for invalid VendorElemGet[2]: " + str(e))
+
+    try:
+        ie = dbus.ByteArray("\x00\x00")
+        iface.VendorElemRem(-1, ie)
+        raise Exception("Invalid VendorElemRemove() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e) or "Invalid ID" not in str(e):
+            raise Exception("Unexpected error message for invalid VendorElemRemove[1]: " + str(e))
+
+    try:
+        ie = dbus.ByteArray("")
+        iface.VendorElemRem(1, ie)
+        raise Exception("Invalid VendorElemRemove() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e) or "Invalid value" not in str(e):
+            raise Exception("Unexpected error message for invalid VendorElemRemove[1]: " + str(e))
+
+    iface.VendorElemRem(1, "*")
+
+    ie = dbus.ByteArray("\x00\x01\x00")
+    iface.VendorElemAdd(1, ie)
+
+    val = iface.VendorElemGet(1)
+    if len(val) != len(ie):
+        raise Exception("Unexpected VendorElemGet length")
+    for i in range(len(val)):
+        if val[i] != dbus.Byte(ie[i]):
+            raise Exception("Unexpected VendorElemGet data")
+
+    ie2 = dbus.ByteArray("\xe0\x00")
+    iface.VendorElemAdd(1, ie2)
+
+    ies = ie + ie2
+    val = iface.VendorElemGet(1)
+    if len(val) != len(ies):
+        raise Exception("Unexpected VendorElemGet length[2]")
+    for i in range(len(val)):
+        if val[i] != dbus.Byte(ies[i]):
+            raise Exception("Unexpected VendorElemGet data[2]")
+
+    try:
+        test_ie = dbus.ByteArray("\x01\x01")
+        iface.VendorElemRem(1, test_ie)
+        raise Exception("Invalid VendorElemRemove() accepted")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e) or "Parse error" not in str(e):
+            raise Exception("Unexpected error message for invalid VendorElemRemove[1]: " + str(e))
+
+    iface.VendorElemRem(1, ie)
+    val = iface.VendorElemGet(1)
+    if len(val) != len(ie2):
+        raise Exception("Unexpected VendorElemGet length[3]")
+
+    iface.VendorElemRem(1, "*")
+    try:
+        iface.VendorElemGet(1)
+        raise Exception("Invalid VendorElemGet() accepted after removal")
+    except dbus.exceptions.DBusException, e:
+        if "InvalidArgs" not in str(e) or "ID value does not exist" not in str(e):
+            raise Exception("Unexpected error message for invalid VendorElemGet after removal: " + str(e))
+
+def test_dbus_assoc_reject(dev, apdev):
+    """D-Bus AssocStatusCode"""
+    (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    ssid = "test-open"
+    params = { "ssid": ssid,
+               "max_listen_interval": "1" }
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    class TestDbusConnect(TestDbus):
+        def __init__(self, bus):
+            TestDbus.__init__(self, bus)
+            self.assoc_status_seen = False
+            self.state = 0
+
+        def __enter__(self):
+            gobject.timeout_add(1, self.run_connect)
+            gobject.timeout_add(15000, self.timeout)
+            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
+                            "PropertiesChanged")
+            self.loop.run()
+            return self
+
+        def propertiesChanged(self, properties):
+            logger.debug("propertiesChanged: %s" % str(properties))
+            if 'AssocStatusCode' in properties:
+                status = properties['AssocStatusCode']
+                if status != 51:
+                    logger.info("Unexpected status code: " + str(status))
+                else:
+                    self.assoc_status_seen = True
+                iface.Disconnect()
+                self.loop.quit()
+
+        def run_connect(self, *args):
+            args = dbus.Dictionary({ 'ssid': ssid,
+                                     'key_mgmt': 'NONE',
+                                     'scan_freq': 2412 },
+                                   signature='sv')
+            self.netw = iface.AddNetwork(args)
+            iface.SelectNetwork(self.netw)
+            return False
+
+        def success(self):
+            return self.assoc_status_seen
+
+    with TestDbusConnect(bus) as t:
+        if not t.success():
+            raise Exception("Expected signals not seen")
index c7c7e19..9034fdd 100644 (file)
@@ -111,11 +111,11 @@ def test_dbus_old_scan(dev, apdev):
     """The old D-Bus interface - scanning"""
     (bus,wpas_obj,path,if_obj) = prepare_dbus(dev[0])
 
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
 
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params['wpa'] = '3'
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd2 = hostapd.add_ap(apdev[1], params)
 
     class TestDbusScan(TestDbus):
         def __init__(self, bus):
@@ -401,7 +401,7 @@ def test_dbus_old_connect(dev, apdev):
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     for p in [ "/no/where/to/be/found",
                path + "/Networks/12345",
@@ -570,7 +570,7 @@ def test_dbus_old_connect_eap(dev, apdev):
 
     ssid = "test-wpa2-eap"
     params = hostapd.wpa2_eap_params(ssid=ssid)
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     class TestDbusConnect(TestDbus):
         def __init__(self, bus):
index 592736e..75a3c25 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import os
 import subprocess
 import time
@@ -26,16 +27,11 @@ def wait_dfs_event(hapd, event, timeout):
     return ev
 
 def start_dfs_ap(ap, allow_failure=False, ssid="dfs", ht=True, ht40=False,
-                 ht40minus=False, vht80=False, vht20=False, chanlist=None):
+                 ht40minus=False, vht80=False, vht20=False, chanlist=None,
+                 channel=None):
     ifname = ap['ifname']
     logger.info("Starting AP " + ifname + " on DFS channel")
-    hapd_global = hostapd.HostapdGlobal()
-    hapd_global.remove(ifname)
-    hapd_global.add(ifname)
-    hapd = hostapd.Hostapd(ifname)
-    if not hapd.ping():
-        raise Exception("Could not ping hostapd")
-    hapd.set_defaults()
+    hapd = hostapd.add_ap(ap, {}, no_enable=True)
     hapd.set("ssid", ssid)
     hapd.set("country_code", "FI")
     hapd.set("ieee80211d", "1")
@@ -59,6 +55,8 @@ def start_dfs_ap(ap, allow_failure=False, ssid="dfs", ht=True, ht40=False,
         hapd.set("vht_oper_centr_freq_seg0_idx", "0")
     if chanlist:
         hapd.set("chanlist", chanlist)
+    if channel:
+        hapd.set("channel", str(channel))
     hapd.enable()
 
     ev = wait_dfs_event(hapd, "DFS-CAC-START", 5)
@@ -115,18 +113,18 @@ def test_dfs(dev, apdev):
         if ev is None:
             raise Exception("DFS-RADAR-DETECTED event not reported")
         if "freq=5260" not in ev:
-            raise Exception("Incorrect frequency in radar detected event: " + ev);
+            raise Exception("Incorrect frequency in radar detected event: " + ev)
         ev = hapd.wait_event(["DFS-NEW-CHANNEL"], timeout=70)
         if ev is None:
             raise Exception("DFS-NEW-CHANNEL event not reported")
         if "freq=5260" in ev:
-            raise Exception("Channel did not change after radar was detected");
+            raise Exception("Channel did not change after radar was detected")
 
         ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=70)
         if ev is None:
             raise Exception("AP-CSA-FINISHED event not reported")
         if "freq=5260" in ev:
-            raise Exception("Channel did not change after radar was detected(2)");
+            raise Exception("Channel did not change after radar was detected(2)")
         time.sleep(1)
         hwsim_utils.test_connectivity(dev[0], hapd)
     finally:
@@ -216,10 +214,11 @@ def test_dfs_radar(dev, apdev):
         subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
 
+@remote_compatible
 def test_dfs_radar_on_non_dfs_channel(dev, apdev):
     """DFS radar detection test code on non-DFS channel"""
     params = { "ssid": "radar" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     hapd.request("RADAR DETECTED freq=5260 ht_enabled=1 chan_width=1")
     hapd.request("RADAR DETECTED freq=2412 ht_enabled=1 chan_width=1")
@@ -400,3 +399,39 @@ def test_dfs_radar_ht40minus(dev, apdev):
             hapd.request("DISABLE")
         subprocess.call(['iw', 'reg', 'set', '00'])
         dev[0].flush_scan_cache()
+
+def test_dfs_ht40_minus(dev, apdev, params):
+    """DFS CAC functionality on channel 104 HT40- [long]"""
+    if not params['long']:
+        raise HwsimSkip("Skip test case with long duration due to --long not specified")
+    try:
+        hapd = None
+        hapd = start_dfs_ap(apdev[0], allow_failure=True, ht40minus=True,
+                            channel=104)
+
+        ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 70)
+        if "success=1" not in ev:
+            raise Exception("CAC failed")
+        if "freq=5520" not in ev:
+            raise Exception("Unexpected DFS freq result")
+
+        ev = hapd.wait_event(["AP-ENABLED"], timeout=5)
+        if not ev:
+            raise Exception("AP setup timed out")
+
+        state = hapd.get_status_field("state")
+        if state != "ENABLED":
+            raise Exception("Unexpected interface state")
+
+        freq = hapd.get_status_field("freq")
+        if freq != "5520":
+            raise Exception("Unexpected frequency")
+
+        dev[0].connect("dfs", key_mgmt="NONE", scan_freq="5520")
+        hwsim_utils.test_connectivity(dev[0], hapd)
+    finally:
+        dev[0].request("DISCONNECT")
+        if hapd:
+            hapd.request("DISABLE")
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        dev[0].flush_scan_cache()
index f0c8a52..5e65475 100644 (file)
@@ -4,22 +4,34 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+import binascii
+import hashlib
 import hmac
 import logging
 logger = logging.getLogger()
+import os
 import select
 import struct
 import threading
 import time
 
 import hostapd
-from utils import HwsimSkip
-from test_ap_eap import check_eap_capa
+from utils import HwsimSkip, alloc_fail, fail_test, wait_fail_trigger
+from test_ap_eap import check_eap_capa, check_hlr_auc_gw_support, int_eap_server_params
+from test_erp import check_erp_capa
+
+try:
+    import OpenSSL
+    openssl_imported = True
+except ImportError:
+    openssl_imported = False
 
 EAP_CODE_REQUEST = 1
 EAP_CODE_RESPONSE = 2
 EAP_CODE_SUCCESS = 3
 EAP_CODE_FAILURE = 4
+EAP_CODE_INITIATE = 5
+EAP_CODE_FINISH = 6
 
 EAP_TYPE_IDENTITY = 1
 EAP_TYPE_NOTIFICATION = 2
@@ -45,6 +57,23 @@ EAP_TYPE_AKA_PRIME = 50
 EAP_TYPE_GPSK = 51
 EAP_TYPE_PWD = 52
 EAP_TYPE_EKE = 53
+EAP_TYPE_EXPANDED = 254
+
+# Type field in EAP-Initiate and EAP-Finish messages
+EAP_ERP_TYPE_REAUTH_START = 1
+EAP_ERP_TYPE_REAUTH = 2
+
+EAP_ERP_TLV_KEYNAME_NAI = 1
+EAP_ERP_TV_RRK_LIFETIME = 2
+EAP_ERP_TV_RMSK_LIFETIME = 3
+EAP_ERP_TLV_DOMAIN_NAME = 4
+EAP_ERP_TLV_CRYPTOSUITES = 5
+EAP_ERP_TLV_AUTHORIZATION_INDICATION = 6
+EAP_ERP_TLV_CALLED_STATION_ID = 128
+EAP_ERP_TLV_CALLING_STATION_ID = 129
+EAP_ERP_TLV_NAS_IDENTIFIER = 130
+EAP_ERP_TLV_NAS_IP_ADDRESS = 131
+EAP_ERP_TLV_NAS_IPV6_ADDRESS = 132
 
 def run_pyrad_server(srv, t_stop, eap_handler):
     srv.RunWithStop(t_stop, eap_handler)
@@ -60,10 +89,9 @@ def start_radius_server(eap_handler):
     class TestServer(pyrad.server.Server):
         def _HandleAuthPacket(self, pkt):
             pyrad.server.Server._HandleAuthPacket(self, pkt)
-            if len(pkt[79]) > 1:
-                logger.info("Multiple EAP-Message attributes")
-                # TODO: reassemble
-            eap = pkt[79][0]
+            eap = ""
+            for p in pkt[79]:
+                eap += p
             eap_req = self.eap_handler(self.ctx, eap)
             reply = self.CreateReplyPacket(pkt)
             if eap_req:
@@ -106,7 +134,7 @@ def start_radius_server(eap_handler):
             self.ctx = {}
 
             while not t_stop.is_set():
-                for (fd, event) in self._poll.poll(1000):
+                for (fd, event) in self._poll.poll(200):
                     if event == select.POLLIN:
                         try:
                             fdo = self._fdmap[fd]
@@ -134,10 +162,10 @@ def stop_radius_server(srv):
     srv['stop'].set()
     srv['thread'].join()
 
-def start_ap(ifname):
+def start_ap(ap):
     params = hostapd.wpa2_eap_params(ssid="eap-test")
     params['auth_server_port'] = "18138"
-    hapd = hostapd.add_ap(ifname, params)
+    hapd = hostapd.add_ap(ap, params)
     return hapd
 
 def test_eap_proto(dev, apdev):
@@ -265,7 +293,7 @@ def test_eap_proto(dev, apdev):
     srv = start_radius_server(eap_handler)
 
     try:
-        hapd = start_ap(apdev[0]['ifname'])
+        hapd = start_ap(apdev[0])
 
         dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
                        eap="MD5", identity="user", password="password",
@@ -362,6 +390,73 @@ def test_eap_proto(dev, apdev):
     finally:
         stop_radius_server(srv)
 
+def test_eap_proto_notification_errors(dev, apdev):
+    """EAP Notification errors"""
+    def eap_handler(ctx, req):
+        logger.info("eap_handler - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] = ctx['num'] + 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+        idx = 0
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: MD5 challenge")
+            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3,
+                               EAP_TYPE_MD5,
+                               1, 0xaa, ord('n'))
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Notification/Request")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_NOTIFICATION,
+                               ord('A'))
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: MD5 challenge")
+            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3,
+                               EAP_TYPE_MD5,
+                               1, 0xaa, ord('n'))
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Notification/Request")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_NOTIFICATION,
+                               ord('A'))
+
+        return None
+
+    srv = start_radius_server(eap_handler)
+
+    try:
+        hapd = start_ap(apdev[0])
+
+        with alloc_fail(dev[0], 1, "eap_sm_processNotify"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="MD5", identity="user", password="password",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+        with alloc_fail(dev[0], 1, "eap_msg_alloc;sm_EAP_NOTIFICATION_Enter"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="MD5", identity="user", password="password",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+    finally:
+        stop_radius_server(srv)
+
 EAP_SAKE_VERSION = 2
 
 EAP_SAKE_SUBTYPE_CHALLENGE = 1
@@ -387,6 +482,9 @@ EAP_SAKE_AT_MSK_LIFE = 132
 
 def test_eap_proto_sake(dev, apdev):
     """EAP-SAKE protocol tests"""
+    global eap_proto_sake_test_done
+    eap_proto_sake_test_done = False
+
     def sake_challenge(ctx):
         logger.info("Test: Challenge subtype")
         return struct.pack(">BBHBBBBBBLLLL", EAP_CODE_REQUEST, ctx['id'],
@@ -399,31 +497,36 @@ def test_eap_proto_sake(dev, apdev):
         logger.info("sake_handler - RX " + req.encode("hex"))
         if 'num' not in ctx:
             ctx['num'] = 0
-        ctx['num'] = ctx['num'] + 1
+        ctx['num'] += 1
         if 'id' not in ctx:
             ctx['id'] = 1
         ctx['id'] = (ctx['id'] + 1) % 256
+        idx = 0
 
-        if ctx['num'] == 1:
+        idx += 1
+        if ctx['num'] == idx:
             logger.info("Test: Missing payload")
             return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'], 4 + 1,
                                EAP_TYPE_SAKE)
 
-        if ctx['num'] == 2:
+        idx += 1
+        if ctx['num'] == idx:
             logger.info("Test: Identity subtype without any attributes")
             return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 3,
                                EAP_TYPE_SAKE,
                                EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY)
 
-        if ctx['num'] == 3:
+        idx += 1
+        if ctx['num'] == idx:
             logger.info("Test: Identity subtype")
             return struct.pack(">BBHBBBBBBH", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 3 + 4,
                                EAP_TYPE_SAKE,
                                EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
                                EAP_SAKE_AT_ANY_ID_REQ, 4, 0)
-        if ctx['num'] == 4:
+        idx += 1
+        if ctx['num'] == idx:
             logger.info("Test: Identity subtype (different session id)")
             return struct.pack(">BBHBBBBBBH", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 3 + 4,
@@ -431,7 +534,8 @@ def test_eap_proto_sake(dev, apdev):
                                EAP_SAKE_VERSION, 1, EAP_SAKE_SUBTYPE_IDENTITY,
                                EAP_SAKE_AT_PERM_ID_REQ, 4, 0)
 
-        if ctx['num'] == 5:
+        idx += 1
+        if ctx['num'] == idx:
             logger.info("Test: Identity subtype with too short attribute")
             return struct.pack(">BBHBBBBBB", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 3 + 2,
@@ -439,7 +543,8 @@ def test_eap_proto_sake(dev, apdev):
                                EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
                                EAP_SAKE_AT_ANY_ID_REQ, 2)
 
-        if ctx['num'] == 6:
+        idx += 1
+        if ctx['num'] == idx:
             logger.info("Test: Identity subtype with truncated attribute")
             return struct.pack(">BBHBBBBBB", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 3 + 2,
@@ -447,21 +552,115 @@ def test_eap_proto_sake(dev, apdev):
                                EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
                                EAP_SAKE_AT_ANY_ID_REQ, 4)
 
-        if ctx['num'] == 7:
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity subtype with too short attribute header")
+            payload = struct.pack("B", EAP_SAKE_AT_ANY_ID_REQ)
+            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + len(payload),
+                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
+                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity subtype with AT_IV but not AT_ENCR_DATA")
+            payload = struct.pack("BB", EAP_SAKE_AT_IV, 2)
+            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + len(payload),
+                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
+                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity subtype with skippable and non-skippable unknown attribute")
+            payload = struct.pack("BBBB", 255, 2, 127, 2)
+            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + len(payload),
+                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
+                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity subtype: AT_RAND_P with invalid payload length")
+            payload = struct.pack("BB", EAP_SAKE_AT_RAND_P, 2)
+            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + len(payload),
+                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
+                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity subtype: AT_MIC_P with invalid payload length")
+            payload = struct.pack("BB", EAP_SAKE_AT_MIC_P, 2)
+            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + len(payload),
+                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
+                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity subtype: AT_PERM_ID_REQ with invalid payload length")
+            payload = struct.pack("BBBBBBBBBBBBBB",
+                                  EAP_SAKE_AT_SPI_S, 2,
+                                  EAP_SAKE_AT_SPI_P, 2,
+                                  EAP_SAKE_AT_ENCR_DATA, 2,
+                                  EAP_SAKE_AT_NEXT_TMPID, 2,
+                                  EAP_SAKE_AT_PERM_ID_REQ, 4, 0, 0,
+                                  EAP_SAKE_AT_PERM_ID_REQ, 2)
+            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + len(payload),
+                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
+                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity subtype: AT_PADDING")
+            payload = struct.pack("BBBBBB",
+                                  EAP_SAKE_AT_PADDING, 3, 0,
+                                  EAP_SAKE_AT_PADDING, 3, 1)
+            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + len(payload),
+                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
+                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity subtype: AT_MSK_LIFE")
+            payload = struct.pack(">BBLBBH",
+                                  EAP_SAKE_AT_MSK_LIFE, 6, 0,
+                                  EAP_SAKE_AT_MSK_LIFE, 4, 0)
+            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + len(payload),
+                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
+                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity subtype with invalid attribute length")
+            payload = struct.pack("BB", EAP_SAKE_AT_ANY_ID_REQ, 0)
+            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + len(payload),
+                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
+                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
+
+        idx += 1
+        if ctx['num'] == idx:
             logger.info("Test: Unknown subtype")
             return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 3,
                                EAP_TYPE_SAKE,
                                EAP_SAKE_VERSION, 0, 123)
 
-        if ctx['num'] == 8:
+        idx += 1
+        if ctx['num'] == idx:
             logger.info("Test: Challenge subtype without any attributes")
             return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 3,
                                EAP_TYPE_SAKE,
                                EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CHALLENGE)
 
-        if ctx['num'] == 9:
+        idx += 1
+        if ctx['num'] == idx:
             logger.info("Test: Challenge subtype with too short AT_RAND_S")
             return struct.pack(">BBHBBBBBB", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 3 + 2,
@@ -469,9 +668,11 @@ def test_eap_proto_sake(dev, apdev):
                                EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CHALLENGE,
                                EAP_SAKE_AT_RAND_S, 2)
 
-        if ctx['num'] == 10:
+        idx += 1
+        if ctx['num'] == idx:
             return sake_challenge(ctx)
-        if ctx['num'] == 11:
+        idx += 1
+        if ctx['num'] == idx:
             logger.info("Test: Unexpected Identity subtype")
             return struct.pack(">BBHBBBBBBH", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 3 + 4,
@@ -479,9 +680,11 @@ def test_eap_proto_sake(dev, apdev):
                                EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
                                EAP_SAKE_AT_ANY_ID_REQ, 4, 0)
 
-        if ctx['num'] == 12:
+        idx += 1
+        if ctx['num'] == idx:
             return sake_challenge(ctx)
-        if ctx['num'] == 13:
+        idx += 1
+        if ctx['num'] == idx:
             logger.info("Test: Unexpected Challenge subtype")
             return struct.pack(">BBHBBBBBBLLLL", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 3 + 18,
@@ -489,18 +692,22 @@ def test_eap_proto_sake(dev, apdev):
                                EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CHALLENGE,
                                EAP_SAKE_AT_RAND_S, 18, 0, 0, 0, 0)
 
-        if ctx['num'] == 14:
+        idx += 1
+        if ctx['num'] == idx:
             return sake_challenge(ctx)
-        if ctx['num'] == 15:
+        idx += 1
+        if ctx['num'] == idx:
             logger.info("Test: Confirm subtype without any attributes")
             return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 3,
                                EAP_TYPE_SAKE,
                                EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CONFIRM)
 
-        if ctx['num'] == 16:
+        idx += 1
+        if ctx['num'] == idx:
             return sake_challenge(ctx)
-        if ctx['num'] == 17:
+        idx += 1
+        if ctx['num'] == idx:
             logger.info("Test: Confirm subtype with too short AT_MIC_S")
             return struct.pack(">BBHBBBBBB", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 3 + 2,
@@ -508,7 +715,8 @@ def test_eap_proto_sake(dev, apdev):
                                EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CONFIRM,
                                EAP_SAKE_AT_MIC_S, 2)
 
-        if ctx['num'] == 18:
+        idx += 1
+        if ctx['num'] == idx:
             logger.info("Test: Unexpected Confirm subtype")
             return struct.pack(">BBHBBBBBBLLLL", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 3 + 18,
@@ -516,9 +724,11 @@ def test_eap_proto_sake(dev, apdev):
                                EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CONFIRM,
                                EAP_SAKE_AT_MIC_S, 18, 0, 0, 0, 0)
 
-        if ctx['num'] == 19:
+        idx += 1
+        if ctx['num'] == idx:
             return sake_challenge(ctx)
-        if ctx['num'] == 20:
+        idx += 1
+        if ctx['num'] == idx:
             logger.info("Test: Confirm subtype with incorrect AT_MIC_S")
             return struct.pack(">BBHBBBBBBLLLL", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 3 + 18,
@@ -526,14 +736,20 @@ def test_eap_proto_sake(dev, apdev):
                                EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CONFIRM,
                                EAP_SAKE_AT_MIC_S, 18, 0, 0, 0, 0)
 
-        return sake_challenge(ctx)
+        global eap_proto_sake_test_done
+        if eap_proto_sake_test_done:
+            return sake_challenge(ctx)
+
+        logger.info("No more test responses available - test case completed")
+        eap_proto_sake_test_done = True
+        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
     srv = start_radius_server(sake_handler)
 
     try:
-        hapd = start_ap(apdev[0]['ifname'])
+        hapd = start_ap(apdev[0])
 
-        for i in range(0, 14):
+        while not eap_proto_sake_test_done:
             dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
                            eap="SAKE", identity="sake user",
                            password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
@@ -556,6 +772,102 @@ def test_eap_proto_sake(dev, apdev):
     finally:
         stop_radius_server(srv)
 
+def test_eap_proto_sake_errors(dev, apdev):
+    """EAP-SAKE local error cases"""
+    check_eap_capa(dev[0], "SAKE")
+    params = hostapd.wpa2_eap_params(ssid="eap-test")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    for i in range(1, 3):
+        with alloc_fail(dev[0], i, "eap_sake_init"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="SAKE", identity="sake user",
+                           password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ ( 1, "eap_msg_alloc;eap_sake_build_msg;eap_sake_process_challenge" ),
+              ( 1, "=eap_sake_process_challenge" ),
+              ( 1, "eap_sake_compute_mic;eap_sake_process_challenge" ),
+              ( 1, "eap_sake_build_msg;eap_sake_process_confirm" ),
+              ( 1, "eap_sake_compute_mic;eap_sake_process_confirm" ),
+              ( 2, "eap_sake_compute_mic;eap_sake_process_confirm" ),
+              ( 1, "eap_sake_getKey" ),
+              ( 1, "eap_sake_get_emsk" ),
+              ( 1, "eap_sake_get_session_id" ) ]
+    for count, func in tests:
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="SAKE", identity="sake user",
+                           password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
+                           erp="1",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    with fail_test(dev[0], 1, "os_get_random;eap_sake_process_challenge"):
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="SAKE", identity="sake user",
+                       password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
+                       wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
+        if ev is None:
+            raise Exception("Timeout on EAP start")
+        wait_fail_trigger(dev[0], "GET_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+def test_eap_proto_sake_errors2(dev, apdev):
+    """EAP-SAKE protocol tests (2)"""
+    def sake_handler(ctx, req):
+        logger.info("sake_handler - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] += 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+        idx = 0
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity subtype")
+            return struct.pack(">BBHBBBBBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_SAKE,
+                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
+                               EAP_SAKE_AT_ANY_ID_REQ, 4, 0)
+
+    srv = start_radius_server(sake_handler)
+
+    try:
+        hapd = start_ap(apdev[0])
+
+        with alloc_fail(dev[0], 1, "eap_msg_alloc;eap_sake_build_msg;eap_sake_process_identity"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="SAKE", identity="sake user",
+                           password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+                dev[0].request("REMOVE_NETWORK all")
+                dev[0].wait_disconnected()
+
+    finally:
+        stop_radius_server(srv)
+
 def test_eap_proto_leap(dev, apdev):
     """EAP-LEAP protocol tests"""
     check_eap_capa(dev[0], "LEAP")
@@ -706,7 +1018,7 @@ def test_eap_proto_leap(dev, apdev):
     srv = start_radius_server(leap_handler)
 
     try:
-        hapd = start_ap(apdev[0]['ifname'])
+        hapd = start_ap(apdev[0])
 
         for i in range(0, 12):
             dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
@@ -723,36 +1035,320 @@ def test_eap_proto_leap(dev, apdev):
     finally:
         stop_radius_server(srv)
 
-def test_eap_proto_md5(dev, apdev):
-    """EAP-MD5 protocol tests"""
-    check_eap_capa(dev[0], "MD5")
+def test_eap_proto_leap_errors(dev, apdev):
+    """EAP-LEAP protocol tests (error paths)"""
+    check_eap_capa(dev[0], "LEAP")
 
-    def md5_handler(ctx, req):
-        logger.info("md5_handler - RX " + req.encode("hex"))
+    def leap_handler2(ctx, req):
+        logger.info("leap_handler2 - RX " + req.encode("hex"))
         if 'num' not in ctx:
             ctx['num'] = 0
         ctx['num'] = ctx['num'] + 1
         if 'id' not in ctx:
             ctx['id'] = 1
         ctx['id'] = (ctx['id'] + 1) % 256
+        idx = 0
 
-        if ctx['num'] == 1:
-            logger.info("Test: Missing payload")
-            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1,
-                               EAP_TYPE_MD5)
-
-        if ctx['num'] == 2:
-            logger.info("Test: Zero-length challenge")
-            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1,
-                               EAP_TYPE_MD5,
-                               0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challenge")
+            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_LEAP,
+                               1, 0, 8, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
-        if ctx['num'] == 3:
-            logger.info("Test: Truncated challenge")
-            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1,
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challenge")
+            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_LEAP,
+                               1, 0, 8, 0, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challenge")
+            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_LEAP,
+                               1, 0, 8, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Success")
+            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challenge")
+            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_LEAP,
+                               1, 0, 8, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Success")
+            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challenge")
+            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_LEAP,
+                               1, 0, 8, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challange value in Response")
+            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
+                               4 + 1 + 3 + 24,
+                               EAP_TYPE_LEAP,
+                               1, 0, 24,
+                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
+                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
+                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challenge")
+            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_LEAP,
+                               1, 0, 8, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challange value in Response")
+            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
+                               4 + 1 + 3 + 24,
+                               EAP_TYPE_LEAP,
+                               1, 0, 24,
+                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
+                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
+                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challenge")
+            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_LEAP,
+                               1, 0, 8, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challange value in Response")
+            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
+                               4 + 1 + 3 + 24,
+                               EAP_TYPE_LEAP,
+                               1, 0, 24,
+                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
+                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
+                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challenge")
+            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_LEAP,
+                               1, 0, 8, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challange value in Response")
+            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
+                               4 + 1 + 3 + 24,
+                               EAP_TYPE_LEAP,
+                               1, 0, 24,
+                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
+                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
+                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challenge")
+            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_LEAP,
+                               1, 0, 8, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challange value in Response")
+            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
+                               4 + 1 + 3 + 24,
+                               EAP_TYPE_LEAP,
+                               1, 0, 24,
+                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
+                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
+                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challenge")
+            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_LEAP,
+                               1, 0, 8, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challange value in Response")
+            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
+                               4 + 1 + 3 + 24,
+                               EAP_TYPE_LEAP,
+                               1, 0, 24,
+                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
+                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
+                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challenge")
+            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_LEAP,
+                               1, 0, 8, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid challange value in Response")
+            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
+                               4 + 1 + 3 + 24,
+                               EAP_TYPE_LEAP,
+                               1, 0, 24,
+                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
+                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
+                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
+
+        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+    srv = start_radius_server(leap_handler2)
+
+    try:
+        hapd = start_ap(apdev[0])
+
+        with alloc_fail(dev[0], 1, "eap_leap_init"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="LEAP", identity="user", password="password",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+        with alloc_fail(dev[0], 1, "eap_msg_alloc;eap_leap_process_request"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="LEAP", identity="user",
+                           password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+        with alloc_fail(dev[0], 1, "eap_leap_process_success"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="LEAP", identity="user", password="password",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+        with fail_test(dev[0], 1, "os_get_random;eap_leap_process_success"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="LEAP", identity="user", password="password",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+        with fail_test(dev[0], 1, "eap_leap_process_response"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="LEAP", identity="user",
+                           password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+        with fail_test(dev[0], 1, "nt_password_hash;eap_leap_process_response"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="LEAP", identity="user", password="password",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+        with fail_test(dev[0], 1, "hash_nt_password_hash;eap_leap_process_response"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="LEAP", identity="user", password="password",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+        with alloc_fail(dev[0], 1, "eap_leap_getKey"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="LEAP", identity="user",
+                           password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+        with fail_test(dev[0], 1, "eap_leap_getKey"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="LEAP", identity="user",
+                           password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+        with fail_test(dev[0], 1, "nt_password_hash;eap_leap_getKey"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="LEAP", identity="user", password="password",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+        with fail_test(dev[0], 1, "hash_nt_password_hash;eap_leap_getKey"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="LEAP", identity="user", password="password",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+    finally:
+        stop_radius_server(srv)
+
+def test_eap_proto_md5(dev, apdev):
+    """EAP-MD5 protocol tests"""
+    check_eap_capa(dev[0], "MD5")
+
+    def md5_handler(ctx, req):
+        logger.info("md5_handler - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] = ctx['num'] + 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+
+        if ctx['num'] == 1:
+            logger.info("Test: Missing payload")
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1,
+                               EAP_TYPE_MD5)
+
+        if ctx['num'] == 2:
+            logger.info("Test: Zero-length challenge")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_MD5,
+                               0)
+
+        if ctx['num'] == 3:
+            logger.info("Test: Truncated challenge")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
                                EAP_TYPE_MD5,
                                1)
 
@@ -768,7 +1364,7 @@ def test_eap_proto_md5(dev, apdev):
     srv = start_radius_server(md5_handler)
 
     try:
-        hapd = start_ap(apdev[0]['ifname'])
+        hapd = start_ap(apdev[0])
 
         for i in range(0, 4):
             dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
@@ -782,80 +1378,2316 @@ def test_eap_proto_md5(dev, apdev):
     finally:
         stop_radius_server(srv)
 
-def test_eap_proto_otp(dev, apdev):
-    """EAP-OTP protocol tests"""
-    def otp_handler(ctx, req):
-        logger.info("otp_handler - RX " + req.encode("hex"))
-        if 'num' not in ctx:
-            ctx['num'] = 0
-        ctx['num'] = ctx['num'] + 1
-        if 'id' not in ctx:
-            ctx['id'] = 1
-        ctx['id'] = (ctx['id'] + 1) % 256
+def test_eap_proto_md5_errors(dev, apdev):
+    """EAP-MD5 local error cases"""
+    check_eap_capa(dev[0], "MD5")
+    params = hostapd.wpa2_eap_params(ssid="eap-test")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    with fail_test(dev[0], 1, "chap_md5"):
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="MD5", identity="phase1-user", password="password",
+                       wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=15)
+        if ev is None:
+            raise Exception("Timeout on EAP start")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    with alloc_fail(dev[0], 1, "eap_msg_alloc;eap_md5_process"):
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="MD5", identity="phase1-user", password="password",
+                       wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=15)
+        if ev is None:
+            raise Exception("Timeout on EAP start")
+        time.sleep(0.1)
+        dev[0].request("REMOVE_NETWORK all")
+
+def test_eap_proto_otp(dev, apdev):
+    """EAP-OTP protocol tests"""
+    def otp_handler(ctx, req):
+        logger.info("otp_handler - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] = ctx['num'] + 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+
+        if ctx['num'] == 1:
+            logger.info("Test: Empty payload")
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1,
+                               EAP_TYPE_OTP)
+        if ctx['num'] == 2:
+            logger.info("Test: Success")
+            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'],
+                               4)
+
+        if ctx['num'] == 3:
+            logger.info("Test: Challenge included")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_OTP,
+                               ord('A'))
+        if ctx['num'] == 4:
+            logger.info("Test: Success")
+            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'],
+                               4)
+
+        return None
+
+    srv = start_radius_server(otp_handler)
+
+    try:
+        hapd = start_ap(apdev[0])
+
+        for i in range(0, 1):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="OTP", identity="user", password="password",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            time.sleep(0.1)
+            dev[0].request("REMOVE_NETWORK all")
+
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="OTP", identity="user", wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-REQ-OTP"])
+        if ev is None:
+            raise Exception("Request for password timed out")
+        id = ev.split(':')[0].split('-')[-1]
+        dev[0].request("CTRL-RSP-OTP-" + id + ":password")
+        ev = dev[0].wait_event("CTRL-EVENT-EAP-SUCCESS")
+        if ev is None:
+            raise Exception("Success not reported")
+    finally:
+        stop_radius_server(srv)
+
+def test_eap_proto_otp_errors(dev, apdev):
+    """EAP-OTP local error cases"""
+    def otp_handler2(ctx, req):
+        logger.info("otp_handler2 - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] = ctx['num'] + 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+        idx = 0
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Challenge included")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_OTP,
+                               ord('A'))
+
+        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+    srv = start_radius_server(otp_handler2)
+
+    try:
+        hapd = start_ap(apdev[0])
+
+        with alloc_fail(dev[0], 1, "eap_msg_alloc;eap_otp_process"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="OTP", identity="user", password="password",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+    finally:
+        stop_radius_server(srv)
+
+EAP_GPSK_OPCODE_GPSK_1 = 1
+EAP_GPSK_OPCODE_GPSK_2 = 2
+EAP_GPSK_OPCODE_GPSK_3 = 3
+EAP_GPSK_OPCODE_GPSK_4 = 4
+EAP_GPSK_OPCODE_FAIL = 5
+EAP_GPSK_OPCODE_PROTECTED_FAIL = 6
+
+def test_eap_proto_gpsk(dev, apdev):
+    """EAP-GPSK protocol tests"""
+    def gpsk_handler(ctx, req):
+        logger.info("gpsk_handler - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] = ctx['num'] + 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+
+        idx = 0
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Missing payload")
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1,
+                               EAP_TYPE_GPSK)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unknown opcode")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_GPSK,
+                               255)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unexpected GPSK-3")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_3)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Too short GPSK-1")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Truncated ID_Server")
+            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 1)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Missing RAND_Server")
+            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Missing CSuite_List")
+            return struct.pack(">BBHBBH8L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Truncated CSuite_List")
+            return struct.pack(">BBHBBH8LH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               1)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Empty CSuite_List")
+            return struct.pack(">BBHBBH8LH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Invalid CSuite_List")
+            return struct.pack(">BBHBBH8LHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 1,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               1, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 No supported CSuite")
+            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Supported CSuite")
+            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 1)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unexpected GPSK-1")
+            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 1)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Supported CSuite but too short key")
+            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 1)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Supported CSuite")
+            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 1)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Too short GPSK-3")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_3)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Supported CSuite")
+            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 1)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-3 Mismatch in RAND_Peer")
+            return struct.pack(">BBHBB8L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 32,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_3,
+                               0, 0, 0, 0, 0, 0, 0, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Supported CSuite")
+            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 1)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-3 Missing RAND_Server")
+            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                              4 + 1 + 1 + 32,
+                              EAP_TYPE_GPSK,
+                              EAP_GPSK_OPCODE_GPSK_3)
+            msg += req[14:46]
+            return msg
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Supported CSuite")
+            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 1)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-3 Mismatch in RAND_Server")
+            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                              4 + 1 + 1 + 32 + 32,
+                              EAP_TYPE_GPSK,
+                              EAP_GPSK_OPCODE_GPSK_3)
+            msg += req[14:46]
+            msg += struct.pack(">8L", 1, 1, 1, 1, 1, 1, 1, 1)
+            return msg
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Supported CSuite")
+            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 1)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-3 Missing ID_Server")
+            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                              4 + 1 + 1 + 32 + 32,
+                              EAP_TYPE_GPSK,
+                              EAP_GPSK_OPCODE_GPSK_3)
+            msg += req[14:46]
+            msg += struct.pack(">8L", 0, 0, 0, 0, 0, 0, 0, 0)
+            return msg
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Supported CSuite")
+            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 1)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-3 Truncated ID_Server")
+            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                              4 + 1 + 1 + 32 + 32 + 2,
+                              EAP_TYPE_GPSK,
+                              EAP_GPSK_OPCODE_GPSK_3)
+            msg += req[14:46]
+            msg += struct.pack(">8LH", 0, 0, 0, 0, 0, 0, 0, 0, 1)
+            return msg
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Supported CSuite")
+            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 1)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-3 Mismatch in ID_Server")
+            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                              4 + 1 + 1 + 32 + 32 + 3,
+                              EAP_TYPE_GPSK,
+                              EAP_GPSK_OPCODE_GPSK_3)
+            msg += req[14:46]
+            msg += struct.pack(">8LHB", 0, 0, 0, 0, 0, 0, 0, 0, 1, ord('B'))
+            return msg
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Supported CSuite")
+            return struct.pack(">BBHBBHB8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 3 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 1, ord('A'),
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 1)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-3 Mismatch in ID_Server (same length)")
+            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                              4 + 1 + 1 + 32 + 32 + 3,
+                              EAP_TYPE_GPSK,
+                              EAP_GPSK_OPCODE_GPSK_3)
+            msg += req[15:47]
+            msg += struct.pack(">8LHB", 0, 0, 0, 0, 0, 0, 0, 0, 1, ord('B'))
+            return msg
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Supported CSuite")
+            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 1)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-3 Missing CSuite_Sel")
+            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                              4 + 1 + 1 + 32 + 32 + 2,
+                              EAP_TYPE_GPSK,
+                              EAP_GPSK_OPCODE_GPSK_3)
+            msg += req[14:46]
+            msg += struct.pack(">8LH", 0, 0, 0, 0, 0, 0, 0, 0, 0)
+            return msg
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Supported CSuite")
+            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 1)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-3 Mismatch in CSuite_Sel")
+            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                              4 + 1 + 1 + 32 + 32 + 2 + 6,
+                              EAP_TYPE_GPSK,
+                              EAP_GPSK_OPCODE_GPSK_3)
+            msg += req[14:46]
+            msg += struct.pack(">8LHLH", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2)
+            return msg
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Supported CSuite")
+            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 1)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-3 Missing len(PD_Payload_Block)")
+            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                              4 + 1 + 1 + 32 + 32 + 2 + 6,
+                              EAP_TYPE_GPSK,
+                              EAP_GPSK_OPCODE_GPSK_3)
+            msg += req[14:46]
+            msg += struct.pack(">8LHLH", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)
+            return msg
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Supported CSuite")
+            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 1)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-3 Truncated PD_Payload_Block")
+            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                              4 + 1 + 1 + 32 + 32 + 2 + 6 + 2,
+                              EAP_TYPE_GPSK,
+                              EAP_GPSK_OPCODE_GPSK_3)
+            msg += req[14:46]
+            msg += struct.pack(">8LHLHH", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1)
+            return msg
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Supported CSuite")
+            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 1)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-3 Missing MAC")
+            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                              4 + 1 + 1 + 32 + 32 + 2 + 6 + 3,
+                              EAP_TYPE_GPSK,
+                              EAP_GPSK_OPCODE_GPSK_3)
+            msg += req[14:46]
+            msg += struct.pack(">8LHLHHB",
+                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 123)
+            return msg
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-1 Supported CSuite")
+            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 32 + 2 + 6,
+                               EAP_TYPE_GPSK,
+                               EAP_GPSK_OPCODE_GPSK_1, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               6, 0, 1)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: GPSK-3 Incorrect MAC")
+            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                              4 + 1 + 1 + 32 + 32 + 2 + 6 + 3 + 16,
+                              EAP_TYPE_GPSK,
+                              EAP_GPSK_OPCODE_GPSK_3)
+            msg += req[14:46]
+            msg += struct.pack(">8LHLHHB4L",
+                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 123,
+                               0, 0, 0, 0)
+            return msg
+
+        return None
+
+    srv = start_radius_server(gpsk_handler)
+
+    try:
+        hapd = start_ap(apdev[0])
+
+        for i in range(0, 27):
+            if i == 12:
+                pw = "short"
+            else:
+                pw = "abcdefghijklmnop0123456789abcdef"
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="GPSK", identity="user", password=pw,
+                           wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            time.sleep(0.05)
+            dev[0].request("REMOVE_NETWORK all")
+    finally:
+        stop_radius_server(srv)
+
+EAP_EKE_ID = 1
+EAP_EKE_COMMIT = 2
+EAP_EKE_CONFIRM = 3
+EAP_EKE_FAILURE = 4
+
+def test_eap_proto_eke(dev, apdev):
+    """EAP-EKE protocol tests"""
+    def eke_handler(ctx, req):
+        logger.info("eke_handler - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] = ctx['num'] + 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+
+        idx = 0
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Missing payload")
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1,
+                               EAP_TYPE_EKE)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unknown exchange")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_EKE,
+                               255)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: No NumProposals in EAP-EKE-ID/Request")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_ID)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: NumProposals=0 in EAP-EKE-ID/Request")
+            return struct.pack(">BBHBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 1,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_ID,
+                               0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Truncated Proposals list in EAP-EKE-ID/Request")
+            return struct.pack(">BBHBBBB4B", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 4,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_ID,
+                               2, 0, 0, 0, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unsupported proposals in EAP-EKE-ID/Request")
+            return struct.pack(">BBHBBBB4B4B4B4B", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 4 * 4,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_ID,
+                               4, 0,
+                               0, 0, 0, 0,
+                               3, 0, 0, 0,
+                               3, 1, 0, 0,
+                               3, 1, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Missing IDType/Identity in EAP-EKE-ID/Request")
+            return struct.pack(">BBHBBBB4B4B4B4B4B",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 5 * 4,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_ID,
+                               5, 0,
+                               0, 0, 0, 0,
+                               3, 0, 0, 0,
+                               3, 1, 0, 0,
+                               3, 1, 1, 0,
+                               3, 1, 1, 1)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid EAP-EKE-ID/Request")
+            return struct.pack(">BBHBBBB4BB",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 4 + 1,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_ID,
+                               1, 0,
+                               3, 1, 1, 1,
+                               255)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unexpected EAP-EKE-ID/Request")
+            return struct.pack(">BBHBBBB4BB",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 4 + 1,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_ID,
+                               1, 0,
+                               3, 1, 1, 1,
+                               255)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid EAP-EKE-ID/Request")
+            return struct.pack(">BBHBBBB4BB",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 4 + 1,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_ID,
+                               1, 0,
+                               3, 1, 1, 1,
+                               255)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unexpected EAP-EKE-Confirm/Request")
+            return struct.pack(">BBHBB",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_CONFIRM)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Too short EAP-EKE-Failure/Request")
+            return struct.pack(">BBHBB",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_FAILURE)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unexpected EAP-EKE-Commit/Request")
+            return struct.pack(">BBHBB",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_COMMIT)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid EAP-EKE-ID/Request")
+            return struct.pack(">BBHBBBB4BB",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 4 + 1,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_ID,
+                               1, 0,
+                               3, 1, 1, 1,
+                               255)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Too short EAP-EKE-Commit/Request")
+            return struct.pack(">BBHBB",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_COMMIT)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid EAP-EKE-ID/Request")
+            return struct.pack(">BBHBBBB4BB",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 4 + 1,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_ID,
+                               1, 0,
+                               1, 1, 1, 1,
+                               255)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: All zeroes DHComponent_S and empty CBvalue in EAP-EKE-Commit/Request")
+            return struct.pack(">BBHBB4L32L",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 16 + 128,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_COMMIT,
+                               0, 0, 0, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Too short EAP-EKE-Confirm/Request")
+            return struct.pack(">BBHBB",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_CONFIRM)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid EAP-EKE-ID/Request")
+            return struct.pack(">BBHBBBB4BB",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2 + 4 + 1,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_ID,
+                               1, 0,
+                               1, 1, 1, 1,
+                               255)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: All zeroes DHComponent_S and empty CBvalue in EAP-EKE-Commit/Request")
+            return struct.pack(">BBHBB4L32L",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 16 + 128,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_COMMIT,
+                               0, 0, 0, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid PNonce_PS and Auth_S values in EAP-EKE-Confirm/Request")
+            return struct.pack(">BBHBB4L8L5L5L",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 16 + 2 * 16 + 20 + 20,
+                               EAP_TYPE_EKE,
+                               EAP_EKE_CONFIRM,
+                               0, 0, 0, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               0, 0, 0, 0, 0,
+                               0, 0, 0, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        return None
+
+    srv = start_radius_server(eke_handler)
+
+    try:
+        hapd = start_ap(apdev[0])
+
+        for i in range(0, 14):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="EKE", identity="user", password="password",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            if i in [ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 ]:
+                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
+                                       timeout=10)
+                if ev is None:
+                    raise Exception("Timeout on EAP failure")
+            else:
+                time.sleep(0.05)
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].dump_monitor()
+    finally:
+        stop_radius_server(srv)
+
+def eap_eke_test_fail(dev, phase1=None, success=False):
+    dev.connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                eap="EKE", identity="eke user", password="hello",
+                phase1=phase1, erp="1", wait_connect=False)
+    ev = dev.wait_event([ "CTRL-EVENT-EAP-FAILURE",
+                          "CTRL-EVENT-EAP-SUCCESS" ], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on EAP failure")
+    if not success and "CTRL-EVENT-EAP-FAILURE" not in ev:
+        raise Exception("EAP did not fail during failure test")
+    dev.request("REMOVE_NETWORK all")
+    dev.wait_disconnected()
+
+def test_eap_proto_eke_errors(dev, apdev):
+    """EAP-EKE local error cases"""
+    check_eap_capa(dev[0], "EKE")
+    params = hostapd.wpa2_eap_params(ssid="eap-test")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    for i in range(1, 3):
+        with alloc_fail(dev[0], i, "eap_eke_init"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="EKE", identity="eke user", password="hello",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "eap_eke_dh_init", None),
+              (1, "eap_eke_prf_hmac_sha1", "dhgroup=3 encr=1 prf=1 mac=1"),
+              (1, "eap_eke_prf_hmac_sha256", "dhgroup=5 encr=1 prf=2 mac=2"),
+              (1, "eap_eke_prf", None),
+              (1, "os_get_random;eap_eke_dhcomp", None),
+              (1, "aes_128_cbc_encrypt;eap_eke_dhcomp", None),
+              (1, "aes_128_cbc_decrypt;eap_eke_shared_secret", None),
+              (1, "eap_eke_prf;eap_eke_shared_secret", None),
+              (1, "eap_eke_prfplus;eap_eke_derive_ke_ki", None),
+              (1, "eap_eke_prfplus;eap_eke_derive_ka", None),
+              (1, "eap_eke_prfplus;eap_eke_derive_msk", None),
+              (1, "os_get_random;eap_eke_prot", None),
+              (1, "aes_128_cbc_decrypt;eap_eke_decrypt_prot", None),
+              (1, "eap_eke_derive_key;eap_eke_process_commit", None),
+              (1, "eap_eke_dh_init;eap_eke_process_commit", None),
+              (1, "eap_eke_shared_secret;eap_eke_process_commit", None),
+              (1, "eap_eke_derive_ke_ki;eap_eke_process_commit", None),
+              (1, "eap_eke_dhcomp;eap_eke_process_commit", None),
+              (1, "os_get_random;eap_eke_process_commit", None),
+              (1, "os_get_random;=eap_eke_process_commit", None),
+              (1, "eap_eke_prot;eap_eke_process_commit", None),
+              (1, "eap_eke_decrypt_prot;eap_eke_process_confirm", None),
+              (1, "eap_eke_derive_ka;eap_eke_process_confirm", None),
+              (1, "eap_eke_auth;eap_eke_process_confirm", None),
+              (2, "eap_eke_auth;eap_eke_process_confirm", None),
+              (1, "eap_eke_prot;eap_eke_process_confirm", None),
+              (1, "eap_eke_derive_msk;eap_eke_process_confirm", None) ]
+    for count, func, phase1 in tests:
+        with fail_test(dev[0], count, func):
+            eap_eke_test_fail(dev[0], phase1)
+
+    tests = [ (1, "=eap_eke_derive_ke_ki", None),
+              (1, "=eap_eke_derive_ka", None),
+              (1, "=eap_eke_derive_msk", None),
+              (1, "eap_eke_build_msg;eap_eke_process_id", None),
+              (1, "wpabuf_alloc;eap_eke_process_id", None),
+              (1, "=eap_eke_process_id", None),
+              (1, "wpabuf_alloc;=eap_eke_process_id", None),
+              (1, "wpabuf_alloc;eap_eke_process_id", None),
+              (1, "eap_eke_build_msg;eap_eke_process_commit", None),
+              (1, "wpabuf_resize;eap_eke_process_commit", None),
+              (1, "eap_eke_build_msg;eap_eke_process_confirm", None) ]
+    for count, func, phase1 in tests:
+        with alloc_fail(dev[0], count, func):
+            eap_eke_test_fail(dev[0], phase1)
+
+    tests = [ (1, "eap_eke_getKey", None),
+              (1, "eap_eke_get_emsk", None),
+              (1, "eap_eke_get_session_id", None) ]
+    for count, func, phase1 in tests:
+        with alloc_fail(dev[0], count, func):
+            eap_eke_test_fail(dev[0], phase1, success=True)
+
+EAP_PAX_OP_STD_1 = 0x01
+EAP_PAX_OP_STD_2 = 0x02
+EAP_PAX_OP_STD_3 = 0x03
+EAP_PAX_OP_SEC_1 = 0x11
+EAP_PAX_OP_SEC_2 = 0x12
+EAP_PAX_OP_SEC_3 = 0x13
+EAP_PAX_OP_SEC_4 = 0x14
+EAP_PAX_OP_SEC_5 = 0x15
+EAP_PAX_OP_ACK = 0x21
+
+EAP_PAX_FLAGS_MF = 0x01
+EAP_PAX_FLAGS_CE = 0x02
+EAP_PAX_FLAGS_AI = 0x04
+
+EAP_PAX_MAC_HMAC_SHA1_128 = 0x01
+EAP_PAX_HMAC_SHA256_128 = 0x02
+
+EAP_PAX_DH_GROUP_NONE = 0x00
+EAP_PAX_DH_GROUP_2048_MODP = 0x01
+EAP_PAX_DH_GROUP_3072_MODP = 0x02
+EAP_PAX_DH_GROUP_NIST_ECC_P_256 = 0x03
+
+EAP_PAX_PUBLIC_KEY_NONE = 0x00
+EAP_PAX_PUBLIC_KEY_RSAES_OAEP = 0x01
+EAP_PAX_PUBLIC_KEY_RSA_PKCS1_V1_5 = 0x02
+EAP_PAX_PUBLIC_KEY_EL_GAMAL_NIST_ECC = 0x03
+
+EAP_PAX_ADE_VENDOR_SPECIFIC = 0x01
+EAP_PAX_ADE_CLIENT_CHANNEL_BINDING = 0x02
+EAP_PAX_ADE_SERVER_CHANNEL_BINDING = 0x03
+
+def test_eap_proto_pax(dev, apdev):
+    """EAP-PAX protocol tests"""
+    def pax_std_1(ctx):
+            logger.info("Test: STD-1")
+            ctx['id'] = 10
+            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 2 + 32 + 16,
+                               EAP_TYPE_PAX,
+                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
+                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
+                               32, 0, 0, 0, 0, 0, 0, 0, 0,
+                               0x16, 0xc9, 0x08, 0x9d, 0x98, 0xa5, 0x6e, 0x1f,
+                               0xf0, 0xac, 0xcf, 0xc4, 0x66, 0xcd, 0x2d, 0xbf)
+
+    def pax_handler(ctx, req):
+        logger.info("pax_handler - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] = ctx['num'] + 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+
+        idx = 0
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Missing payload")
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1,
+                               EAP_TYPE_PAX)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Minimum length payload")
+            return struct.pack(">BBHB4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 16,
+                               EAP_TYPE_PAX,
+                               0, 0, 0, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unsupported MAC ID")
+            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 16,
+                               EAP_TYPE_PAX,
+                               EAP_PAX_OP_STD_1, 0, 255, EAP_PAX_DH_GROUP_NONE,
+                               EAP_PAX_PUBLIC_KEY_NONE,
+                               0, 0, 0, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unsupported DH Group ID")
+            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 16,
+                               EAP_TYPE_PAX,
+                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
+                               255, EAP_PAX_PUBLIC_KEY_NONE,
+                               0, 0, 0, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unsupported Public Key ID")
+            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 16,
+                               EAP_TYPE_PAX,
+                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
+                               EAP_PAX_DH_GROUP_NONE, 255,
+                               0, 0, 0, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: More fragments")
+            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 16,
+                               EAP_TYPE_PAX,
+                               EAP_PAX_OP_STD_1, EAP_PAX_FLAGS_MF,
+                               EAP_PAX_MAC_HMAC_SHA1_128,
+                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
+                               0, 0, 0, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid ICV")
+            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 16,
+                               EAP_TYPE_PAX,
+                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
+                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
+                               0, 0, 0, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid ICV in short frame")
+            return struct.pack(">BBHBBBBBB3L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 12,
+                               EAP_TYPE_PAX,
+                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
+                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
+                               0, 0, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Correct ICV - unsupported op_code")
+            ctx['id'] = 10
+            return struct.pack(">BBHBBBBBB16B", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 16,
+                               EAP_TYPE_PAX,
+                               255, 0, EAP_PAX_MAC_HMAC_SHA1_128,
+                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
+                               0x90, 0x78, 0x97, 0x38, 0x29, 0x94, 0x32, 0xd4,
+                               0x81, 0x27, 0xe0, 0xf6, 0x3b, 0x0d, 0xb2, 0xb2)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Correct ICV - CE flag in STD-1")
+            ctx['id'] = 10
+            return struct.pack(">BBHBBBBBB16B", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 16,
+                               EAP_TYPE_PAX,
+                               EAP_PAX_OP_STD_1, EAP_PAX_FLAGS_CE,
+                               EAP_PAX_MAC_HMAC_SHA1_128,
+                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
+                               0x9c, 0x98, 0xb4, 0x0b, 0x94, 0x90, 0xde, 0x88,
+                               0xb7, 0x72, 0x63, 0x44, 0x1d, 0xe3, 0x7c, 0x5c)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Correct ICV - too short STD-1 payload")
+            ctx['id'] = 10
+            return struct.pack(">BBHBBBBBB16B", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 16,
+                               EAP_TYPE_PAX,
+                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
+                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
+                               0xda, 0xab, 0x2c, 0xe7, 0x84, 0x41, 0xb5, 0x5c,
+                               0xee, 0xcf, 0x62, 0x03, 0xc5, 0x69, 0xcb, 0xf4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Correct ICV - incorrect A length in STD-1")
+            ctx['id'] = 10
+            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 2 + 32 + 16,
+                               EAP_TYPE_PAX,
+                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
+                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
+                               0, 0, 0, 0, 0, 0, 0, 0, 0,
+                               0xc4, 0xb0, 0x81, 0xe4, 0x6c, 0x8c, 0x20, 0x23,
+                               0x60, 0x46, 0x89, 0xea, 0x94, 0x60, 0xf3, 0x2a)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Correct ICV - extra data in STD-1")
+            ctx['id'] = 10
+            return struct.pack(">BBHBBBBBBH8LB16B", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 2 + 32 + 1 + 16,
+                               EAP_TYPE_PAX,
+                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
+                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
+                               32, 0, 0, 0, 0, 0, 0, 0, 0,
+                               1,
+                               0x61, 0x49, 0x65, 0x37, 0x21, 0xe8, 0xd8, 0xbf,
+                               0xf3, 0x02, 0x01, 0xe5, 0x42, 0x51, 0xd3, 0x34)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unexpected STD-1")
+            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 2 + 32 + 16,
+                               EAP_TYPE_PAX,
+                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
+                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
+                               32, 0, 0, 0, 0, 0, 0, 0, 0,
+                               0xe5, 0x1d, 0xbf, 0xb8, 0x70, 0x20, 0x5c, 0xba,
+                               0x41, 0xbb, 0x34, 0xda, 0x1a, 0x08, 0xe6, 0x8d)
+
+        idx += 1
+        if ctx['num'] == idx:
+            return pax_std_1(ctx)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: MAC ID changed during session")
+            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 2 + 32 + 16,
+                               EAP_TYPE_PAX,
+                               EAP_PAX_OP_STD_1, 0, EAP_PAX_HMAC_SHA256_128,
+                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
+                               32, 0, 0, 0, 0, 0, 0, 0, 0,
+                               0xee, 0x00, 0xbf, 0xb8, 0x70, 0x20, 0x5c, 0xba,
+                               0x41, 0xbb, 0x34, 0xda, 0x1a, 0x08, 0xe6, 0x8d)
+
+        idx += 1
+        if ctx['num'] == idx:
+            return pax_std_1(ctx)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: DH Group ID changed during session")
+            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 2 + 32 + 16,
+                               EAP_TYPE_PAX,
+                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
+                               EAP_PAX_DH_GROUP_2048_MODP,
+                               EAP_PAX_PUBLIC_KEY_NONE,
+                               32, 0, 0, 0, 0, 0, 0, 0, 0,
+                               0xee, 0x01, 0xbf, 0xb8, 0x70, 0x20, 0x5c, 0xba,
+                               0x41, 0xbb, 0x34, 0xda, 0x1a, 0x08, 0xe6, 0x8d)
+
+        idx += 1
+        if ctx['num'] == idx:
+            return pax_std_1(ctx)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Public Key ID changed during session")
+            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 2 + 32 + 16,
+                               EAP_TYPE_PAX,
+                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
+                               EAP_PAX_DH_GROUP_NONE,
+                               EAP_PAX_PUBLIC_KEY_RSAES_OAEP,
+                               32, 0, 0, 0, 0, 0, 0, 0, 0,
+                               0xee, 0x02, 0xbf, 0xb8, 0x70, 0x20, 0x5c, 0xba,
+                               0x41, 0xbb, 0x34, 0xda, 0x1a, 0x08, 0xe6, 0x8d)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unexpected STD-3")
+            ctx['id'] = 10
+            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 2 + 32 + 16,
+                               EAP_TYPE_PAX,
+                               EAP_PAX_OP_STD_3, 0, EAP_PAX_MAC_HMAC_SHA1_128,
+                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
+                               32, 0, 0, 0, 0, 0, 0, 0, 0,
+                               0x47, 0xbb, 0xc0, 0xf9, 0xb9, 0x69, 0xf5, 0xcb,
+                               0x3a, 0xe8, 0xe7, 0xd6, 0x80, 0x28, 0xf2, 0x59)
+
+        idx += 1
+        if ctx['num'] == idx:
+            return pax_std_1(ctx)
+        idx += 1
+        if ctx['num'] == idx:
+            # TODO: MAC calculation; for now, this gets dropped due to incorrect
+            # ICV
+            logger.info("Test: STD-3 with CE flag")
+            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 5 + 2 + 32 + 16,
+                               EAP_TYPE_PAX,
+                               EAP_PAX_OP_STD_3, EAP_PAX_FLAGS_CE,
+                               EAP_PAX_MAC_HMAC_SHA1_128,
+                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
+                               32, 0, 0, 0, 0, 0, 0, 0, 0,
+                               0x8a, 0xc2, 0xf9, 0xf4, 0x8b, 0x75, 0x72, 0xa2,
+                               0x4d, 0xd3, 0x1e, 0x54, 0x77, 0x04, 0x05, 0xe2)
+
+        idx += 1
+        if ctx['num'] & 0x1 == idx & 0x1:
+            logger.info("Test: Default request")
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1,
+                               EAP_TYPE_PAX)
+        else:
+            logger.info("Test: Default EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+    srv = start_radius_server(pax_handler)
+
+    try:
+        hapd = start_ap(apdev[0])
+
+        for i in range(0, 18):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PAX", identity="user",
+                           password_hex="0123456789abcdef0123456789abcdef",
+                           wait_connect=False)
+            logger.info("Waiting for EAP method to start")
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            time.sleep(0.05)
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].dump_monitor()
+
+        logger.info("Too short password")
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="PAX", identity="user",
+                       password_hex="0123456789abcdef0123456789abcd",
+                       wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
+        if ev is None:
+            raise Exception("Timeout on EAP start")
+        time.sleep(0.1)
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].dump_monitor()
+
+        logger.info("No password")
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="PAX", identity="user",
+                       wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
+        if ev is None:
+            raise Exception("Timeout on EAP start")
+        time.sleep(0.1)
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].dump_monitor()
+    finally:
+        stop_radius_server(srv)
+
+def test_eap_proto_pax_errors(dev, apdev):
+    """EAP-PAX local error cases"""
+    check_eap_capa(dev[0], "PAX")
+    params = hostapd.wpa2_eap_params(ssid="eap-test")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    for i in range(1, 3):
+        with alloc_fail(dev[0], i, "eap_pax_init"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PAX", identity="pax.user@example.com",
+                           password_hex="0123456789abcdef0123456789abcdef",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ "eap_msg_alloc;eap_pax_alloc_resp;eap_pax_process_std_1",
+              "eap_msg_alloc;eap_pax_alloc_resp;eap_pax_process_std_3",
+              "eap_pax_getKey",
+              "eap_pax_get_emsk",
+              "eap_pax_get_session_id" ]
+    for func in tests:
+        with alloc_fail(dev[0], 1, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PAX", identity="pax.user@example.com",
+                           password_hex="0123456789abcdef0123456789abcdef",
+                           erp="1", wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "os_get_random;eap_pax_process_std_1"),
+              (1, "eap_pax_initial_key_derivation"),
+              (1, "eap_pax_mac;eap_pax_process_std_3"),
+              (2, "eap_pax_mac;eap_pax_process_std_3"),
+              (1, "eap_pax_kdf;eap_pax_getKey"),
+              (1, "eap_pax_kdf;eap_pax_get_emsk") ]
+    for count, func in tests:
+        with fail_test(dev[0], count, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PAX", identity="pax.user@example.com",
+                           password_hex="0123456789abcdef0123456789abcdef",
+                           erp="1", wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+def test_eap_proto_psk(dev, apdev):
+    """EAP-PSK protocol tests"""
+    def psk_handler(ctx, req):
+        logger.info("psk_handler - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] = ctx['num'] + 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+
+        idx = 0
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Missing payload")
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1,
+                               EAP_TYPE_PSK)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Non-zero T in first message")
+            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 16,
+                               EAP_TYPE_PSK, 0xc0, 0, 0, 0, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid first message")
+            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 16,
+                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Too short third message")
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1,
+                               EAP_TYPE_PSK)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid first message")
+            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 16,
+                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Incorrect T in third message")
+            return struct.pack(">BBHBB4L4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 16 + 16,
+                               EAP_TYPE_PSK, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid first message")
+            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 16,
+                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Missing PCHANNEL in third message")
+            return struct.pack(">BBHBB4L4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 16 + 16,
+                               EAP_TYPE_PSK, 0x80, 0, 0, 0, 0, 0, 0, 0, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid first message")
+            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 16,
+                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalic MAC_S in third message")
+            return struct.pack(">BBHBB4L4L5LB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 16 + 16 + 21,
+                               EAP_TYPE_PSK, 0x80, 0, 0, 0, 0, 0, 0, 0, 0,
+                               0, 0, 0, 0, 0, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Valid first message")
+            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 16,
+                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        return None
+
+    srv = start_radius_server(psk_handler)
+
+    try:
+        hapd = start_ap(apdev[0])
+
+        for i in range(0, 6):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PSK", identity="user",
+                           password_hex="0123456789abcdef0123456789abcdef",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            time.sleep(0.1)
+            dev[0].request("REMOVE_NETWORK all")
+
+        logger.info("Test: Invalid PSK length")
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="PSK", identity="user",
+                       password_hex="0123456789abcdef0123456789abcd",
+                       wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                               timeout=15)
+        if ev is None:
+            raise Exception("Timeout on EAP start")
+        time.sleep(0.1)
+        dev[0].request("REMOVE_NETWORK all")
+    finally:
+        stop_radius_server(srv)
+
+def test_eap_proto_psk_errors(dev, apdev):
+    """EAP-PSK local error cases"""
+    check_eap_capa(dev[0], "PSK")
+    params = hostapd.wpa2_eap_params(ssid="eap-test")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    for i in range(1, 3):
+        with alloc_fail(dev[0], i, "eap_psk_init"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PSK", identity="psk.user@example.com",
+                           password_hex="0123456789abcdef0123456789abcdef",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    for i in range(1, 4):
+        with fail_test(dev[0], i, "eap_psk_key_setup;eap_psk_init"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PSK", identity="psk.user@example.com",
+                           password_hex="0123456789abcdef0123456789abcdef",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "=eap_psk_process_1"),
+              (2, "=eap_psk_process_1"),
+              (1, "eap_msg_alloc;eap_psk_process_1"),
+              (1, "=eap_psk_process_3"),
+              (2, "=eap_psk_process_3"),
+              (1, "eap_msg_alloc;eap_psk_process_3"),
+              (1, "eap_psk_getKey"),
+              (1, "eap_psk_get_session_id"),
+              (1, "eap_psk_get_emsk") ]
+    for count, func in tests:
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PSK", identity="psk.user@example.com",
+                           password_hex="0123456789abcdef0123456789abcdef",
+                           erp="1", wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL",
+                              note="No allocation failure seen for %d:%s" % (count, func))
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "os_get_random;eap_psk_process_1"),
+              (1, "omac1_aes_128;eap_psk_process_3"),
+              (1, "aes_128_eax_decrypt;eap_psk_process_3"),
+              (2, "aes_128_eax_decrypt;eap_psk_process_3"),
+              (3, "aes_128_eax_decrypt;eap_psk_process_3"),
+              (1, "aes_128_eax_encrypt;eap_psk_process_3"),
+              (2, "aes_128_eax_encrypt;eap_psk_process_3"),
+              (3, "aes_128_eax_encrypt;eap_psk_process_3"),
+              (1, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
+              (2, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
+              (3, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
+              (4, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
+              (5, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
+              (6, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
+              (7, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
+              (8, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
+              (9, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
+              (10, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
+              (1, "aes_128_ctr_encrypt;aes_128_eax_decrypt;eap_psk_process_3"),
+              (1, "aes_128_ctr_encrypt;aes_128_eax_encrypt;eap_psk_process_3") ]
+    for count, func in tests:
+        with fail_test(dev[0], count, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PSK", identity="psk.user@example.com",
+                           password_hex="0123456789abcdef0123456789abcdef",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            wait_fail_trigger(dev[0], "GET_FAIL",
+                              note="No failure seen for %d:%s" % (count, func))
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+EAP_SIM_SUBTYPE_START = 10
+EAP_SIM_SUBTYPE_CHALLENGE = 11
+EAP_SIM_SUBTYPE_NOTIFICATION = 12
+EAP_SIM_SUBTYPE_REAUTHENTICATION = 13
+EAP_SIM_SUBTYPE_CLIENT_ERROR = 14
+
+EAP_AKA_SUBTYPE_CHALLENGE = 1
+EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT = 2
+EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE = 4
+EAP_AKA_SUBTYPE_IDENTITY = 5
+EAP_AKA_SUBTYPE_NOTIFICATION = 12
+EAP_AKA_SUBTYPE_REAUTHENTICATION = 13
+EAP_AKA_SUBTYPE_CLIENT_ERROR = 14
+
+EAP_SIM_AT_RAND = 1
+EAP_SIM_AT_AUTN = 2
+EAP_SIM_AT_RES = 3
+EAP_SIM_AT_AUTS = 4
+EAP_SIM_AT_PADDING = 6
+EAP_SIM_AT_NONCE_MT = 7
+EAP_SIM_AT_PERMANENT_ID_REQ = 10
+EAP_SIM_AT_MAC = 11
+EAP_SIM_AT_NOTIFICATION = 12
+EAP_SIM_AT_ANY_ID_REQ = 13
+EAP_SIM_AT_IDENTITY = 14
+EAP_SIM_AT_VERSION_LIST = 15
+EAP_SIM_AT_SELECTED_VERSION = 16
+EAP_SIM_AT_FULLAUTH_ID_REQ = 17
+EAP_SIM_AT_COUNTER = 19
+EAP_SIM_AT_COUNTER_TOO_SMALL = 20
+EAP_SIM_AT_NONCE_S = 21
+EAP_SIM_AT_CLIENT_ERROR_CODE = 22
+EAP_SIM_AT_KDF_INPUT = 23
+EAP_SIM_AT_KDF = 24
+EAP_SIM_AT_IV = 129
+EAP_SIM_AT_ENCR_DATA = 130
+EAP_SIM_AT_NEXT_PSEUDONYM = 132
+EAP_SIM_AT_NEXT_REAUTH_ID = 133
+EAP_SIM_AT_CHECKCODE = 134
+EAP_SIM_AT_RESULT_IND = 135
+EAP_SIM_AT_BIDDING = 136
+
+def test_eap_proto_aka(dev, apdev):
+    """EAP-AKA protocol tests"""
+    def aka_handler(ctx, req):
+        logger.info("aka_handler - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] = ctx['num'] + 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+
+        idx = 0
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Missing payload")
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1,
+                               EAP_TYPE_AKA)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unknown subtype")
+            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3,
+                               EAP_TYPE_AKA, 255, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Client Error")
+            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CLIENT_ERROR, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Too short attribute header")
+            return struct.pack(">BBHBBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 3,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0, 255)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Truncated attribute")
+            return struct.pack(">BBHBBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0, 255,
+                               255)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Too short attribute data")
+            return struct.pack(">BBHBBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0, 255,
+                               0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Skippable/non-skippable unrecognzized attribute")
+            return struct.pack(">BBHBBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 10,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               255, 1, 0, 127, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity request without ID type")
+            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity request ANY_ID")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity request ANY_ID (duplicate)")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity request ANY_ID")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity request FULLAUTH_ID")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity request FULLAUTH_ID (duplicate)")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity request ANY_ID")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity request FULLAUTH_ID")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity request PERMANENT_ID")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_PERMANENT_ID_REQ, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity request PERMANENT_ID (duplicate)")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_PERMANENT_ID_REQ, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Challenge with no attributes")
+            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: AKA Challenge with BIDDING")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_BIDDING, 1, 0x8000)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Notification with no attributes")
+            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Notification indicating success, but no MAC")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
+                               EAP_SIM_AT_NOTIFICATION, 1, 32768)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Notification indicating success, but invalid MAC value")
+            return struct.pack(">BBHBBHBBHBBH4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 20,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
+                               EAP_SIM_AT_NOTIFICATION, 1, 32768,
+                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Notification indicating success with zero-key MAC")
+            return struct.pack(">BBHBBHBBHBBH16B", EAP_CODE_REQUEST,
+                               ctx['id'] - 2,
+                               4 + 1 + 3 + 4 + 20,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
+                               EAP_SIM_AT_NOTIFICATION, 1, 32768,
+                               EAP_SIM_AT_MAC, 5, 0,
+                               0xbe, 0x2e, 0xbb, 0xa9, 0xfa, 0x2e, 0x82, 0x36,
+                               0x37, 0x8c, 0x32, 0x41, 0xb7, 0xc7, 0x58, 0xa3)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Success")
+            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Notification before auth")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
+                               EAP_SIM_AT_NOTIFICATION, 1, 16384)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Notification before auth")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
+                               EAP_SIM_AT_NOTIFICATION, 1, 16385)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Notification with unrecognized non-failure")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
+                               EAP_SIM_AT_NOTIFICATION, 1, 0xc000)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Notification before auth (duplicate)")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
+                               EAP_SIM_AT_NOTIFICATION, 1, 0xc000)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Re-authentication (unexpected) with no attributes")
+            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_REAUTHENTICATION,
+                               0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: AKA Challenge with Checkcode claiming identity round was used")
+            return struct.pack(">BBHBBHBBH5L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 24,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_CHECKCODE, 6, 0, 0, 0, 0, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity request ANY_ID")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: AKA Challenge with Checkcode claiming no identity round was used")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_CHECKCODE, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity request ANY_ID")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: AKA Challenge with mismatching Checkcode value")
+            return struct.pack(">BBHBBHBBH5L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 24,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_CHECKCODE, 6, 0, 0, 0, 0, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Re-authentication (unexpected) with Checkcode claimin identity round was used")
+            return struct.pack(">BBHBBHBBH5L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 24,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_REAUTHENTICATION,
+                               0,
+                               EAP_SIM_AT_CHECKCODE, 6, 0, 0, 0, 0, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid AT_RAND length")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_RAND, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid AT_AUTN length")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_AUTN, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unencrypted AT_PADDING")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_PADDING, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid AT_NONCE_MT length")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_NONCE_MT, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid AT_MAC length")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_MAC, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid AT_NOTIFICATION length")
+            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_NOTIFICATION, 2, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: AT_IDENTITY overflow")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_IDENTITY, 1, 0xffff)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unexpected AT_VERSION_LIST")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_VERSION_LIST, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid AT_SELECTED_VERSION length")
+            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_SELECTED_VERSION, 2, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unencrypted AT_COUNTER")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_COUNTER, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unencrypted AT_COUNTER_TOO_SMALL")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_COUNTER_TOO_SMALL, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unencrypted AT_NONCE_S")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_NONCE_S, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid AT_CLIENT_ERROR_CODE length")
+            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_CLIENT_ERROR_CODE, 2, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid AT_IV length")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_IV, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid AT_ENCR_DATA length")
+            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_ENCR_DATA, 2, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unencrypted AT_NEXT_PSEUDONYM")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_NEXT_PSEUDONYM, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unencrypted AT_NEXT_REAUTH_ID")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_NEXT_REAUTH_ID, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid AT_RES length")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_RES, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid AT_RES length")
+            return struct.pack(">BBHBBHBBH5L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 24,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_RES, 6, 0xffff, 0, 0, 0, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid AT_AUTS length")
+            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_AUTS, 2, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid AT_CHECKCODE length")
+            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_CHECKCODE, 2, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid AT_RESULT_IND length")
+            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_RESULT_IND, 2, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unexpected AT_KDF_INPUT")
+            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_KDF_INPUT, 2, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
-        if ctx['num'] == 1:
-            logger.info("Test: Empty payload")
-            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1,
-                               EAP_TYPE_OTP)
-        if ctx['num'] == 2:
-            logger.info("Test: Success")
-            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'],
-                               4)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unexpected AT_KDF")
+            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_KDF, 2, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
-        if ctx['num'] == 3:
-            logger.info("Test: Challenge included")
-            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1,
-                               EAP_TYPE_OTP,
-                               ord('A'))
-        if ctx['num'] == 4:
-            logger.info("Test: Success")
-            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'],
-                               4)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid AT_BIDDING length")
+            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_BIDDING, 2, 0, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         return None
 
-    srv = start_radius_server(otp_handler)
+    srv = start_radius_server(aka_handler)
 
     try:
-        hapd = start_ap(apdev[0]['ifname'])
+        hapd = start_ap(apdev[0])
 
-        for i in range(0, 1):
+        for i in range(0, 49):
+            eap = "AKA AKA'" if i == 11 else "AKA"
             dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
-                           eap="OTP", identity="user", password="password",
+                           eap=eap, identity="0232010000000000",
+                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
                            wait_connect=False)
             ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
                                    timeout=15)
             if ev is None:
                 raise Exception("Timeout on EAP start")
-            time.sleep(0.1)
+            if i in [ 0, 15 ]:
+                time.sleep(0.1)
+            else:
+                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
+                                       timeout=10)
+                if ev is None:
+                    raise Exception("Timeout on EAP failure")
             dev[0].request("REMOVE_NETWORK all")
-
-        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
-                       eap="OTP", identity="user", wait_connect=False)
-        ev = dev[0].wait_event(["CTRL-REQ-OTP"])
-        if ev is None:
-            raise Exception("Request for password timed out")
-        id = ev.split(':')[0].split('-')[-1]
-        dev[0].request("CTRL-RSP-OTP-" + id + ":password")
-        ev = dev[0].wait_event("CTRL-EVENT-EAP-SUCCESS")
-        if ev is None:
-            raise Exception("Success not reported")
+            dev[0].dump_monitor()
     finally:
         stop_radius_server(srv)
 
-EAP_GPSK_OPCODE_GPSK_1 = 1
-EAP_GPSK_OPCODE_GPSK_2 = 2
-EAP_GPSK_OPCODE_GPSK_3 = 3
-EAP_GPSK_OPCODE_GPSK_4 = 4
-EAP_GPSK_OPCODE_FAIL = 5
-EAP_GPSK_OPCODE_PROTECTED_FAIL = 6
-
-def test_eap_proto_gpsk(dev, apdev):
-    """EAP-GPSK protocol tests"""
-    def gpsk_handler(ctx, req):
-        logger.info("gpsk_handler - RX " + req.encode("hex"))
+def test_eap_proto_aka_prime(dev, apdev):
+    """EAP-AKA' protocol tests"""
+    def aka_prime_handler(ctx, req):
+        logger.info("aka_prime_handler - RX " + req.encode("hex"))
         if 'num' not in ctx:
             ctx['num'] = 0
         ctx['num'] = ctx['num'] + 1
@@ -870,436 +3702,337 @@ def test_eap_proto_gpsk(dev, apdev):
             logger.info("Test: Missing payload")
             return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1,
-                               EAP_TYPE_GPSK)
-
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Unknown opcode")
-            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1,
-                               EAP_TYPE_GPSK,
-                               255)
-
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Unexpected GPSK-3")
-            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_3)
-
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Too short GPSK-1")
-            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1)
-
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Truncated ID_Server")
-            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 1)
+                               EAP_TYPE_AKA_PRIME)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Missing RAND_Server")
+            logger.info("Test: Challenge with no attributes")
             return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0)
-
+                               4 + 1 + 3,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Missing CSuite_List")
-            return struct.pack(">BBHBBH8L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0)
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Truncated CSuite_List")
-            return struct.pack(">BBHBBH8LH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               1)
-
+            logger.info("Test: Challenge with empty AT_KDF_INPUT")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_KDF_INPUT, 1, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Empty CSuite_List")
-            return struct.pack(">BBHBBH8LH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               0)
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Invalid CSuite_List")
-            return struct.pack(">BBHBBH8LHB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 1,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               1, 0)
-
+            logger.info("Test: Challenge with AT_KDF_INPUT")
+            return struct.pack(">BBHBBHBBHBBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
+                               ord('c'), ord('d'))
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 No supported CSuite")
-            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 0)
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Supported CSuite")
-            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 1)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Unexpected GPSK-1")
-            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 1)
-
+            logger.info("Test: Challenge with duplicated KDF")
+            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 3 * 4,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
+                               ord('c'), ord('d'),
+                               EAP_SIM_AT_KDF, 1, 1,
+                               EAP_SIM_AT_KDF, 1, 2,
+                               EAP_SIM_AT_KDF, 1, 1)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Supported CSuite but too short key")
-            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 1)
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Supported CSuite")
-            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 1)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Too short GPSK-3")
-            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_3)
-
+            logger.info("Test: Challenge with multiple KDF proposals")
+            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 3 * 4,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
+                               ord('c'), ord('d'),
+                               EAP_SIM_AT_KDF, 1, 255,
+                               EAP_SIM_AT_KDF, 1, 254,
+                               EAP_SIM_AT_KDF, 1, 1)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Supported CSuite")
-            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 1)
+            logger.info("Test: Challenge with incorrect KDF selected")
+            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBHBBH",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 4 * 4,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
+                               ord('c'), ord('d'),
+                               EAP_SIM_AT_KDF, 1, 255,
+                               EAP_SIM_AT_KDF, 1, 255,
+                               EAP_SIM_AT_KDF, 1, 254,
+                               EAP_SIM_AT_KDF, 1, 1)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-3 Mismatch in RAND_Peer")
-            return struct.pack(">BBHBB8L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 32,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_3,
-                               0, 0, 0, 0, 0, 0, 0, 0)
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Supported CSuite")
-            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 1)
+            logger.info("Test: Challenge with multiple KDF proposals")
+            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 3 * 4,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
+                               ord('c'), ord('d'),
+                               EAP_SIM_AT_KDF, 1, 255,
+                               EAP_SIM_AT_KDF, 1, 254,
+                               EAP_SIM_AT_KDF, 1, 1)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-3 Missing RAND_Server")
-            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                              4 + 1 + 1 + 32,
-                              EAP_TYPE_GPSK,
-                              EAP_GPSK_OPCODE_GPSK_3)
-            msg += req[14:46]
-            return msg
-
+            logger.info("Test: Challenge with selected KDF not duplicated")
+            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 3 * 4,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
+                               ord('c'), ord('d'),
+                               EAP_SIM_AT_KDF, 1, 1,
+                               EAP_SIM_AT_KDF, 1, 255,
+                               EAP_SIM_AT_KDF, 1, 254)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Supported CSuite")
-            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 1)
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-3 Mismatch in RAND_Server")
-            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                              4 + 1 + 1 + 32 + 32,
-                              EAP_TYPE_GPSK,
-                              EAP_GPSK_OPCODE_GPSK_3)
-            msg += req[14:46]
-            msg += struct.pack(">8L", 1, 1, 1, 1, 1, 1, 1, 1)
-            return msg
-
+            logger.info("Test: Challenge with multiple KDF proposals")
+            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 3 * 4,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
+                               ord('c'), ord('d'),
+                               EAP_SIM_AT_KDF, 1, 255,
+                               EAP_SIM_AT_KDF, 1, 254,
+                               EAP_SIM_AT_KDF, 1, 1)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Supported CSuite")
-            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 1)
+            logger.info("Test: Challenge with selected KDF duplicated (missing MAC, RAND, AUTN)")
+            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBHBBH",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 4 * 4,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
+                               ord('c'), ord('d'),
+                               EAP_SIM_AT_KDF, 1, 1,
+                               EAP_SIM_AT_KDF, 1, 255,
+                               EAP_SIM_AT_KDF, 1, 254,
+                               EAP_SIM_AT_KDF, 1, 1)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-3 Missing ID_Server")
-            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                              4 + 1 + 1 + 32 + 32,
-                              EAP_TYPE_GPSK,
-                              EAP_GPSK_OPCODE_GPSK_3)
-            msg += req[14:46]
-            msg += struct.pack(">8L", 0, 0, 0, 0, 0, 0, 0, 0)
-            return msg
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Supported CSuite")
-            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 1)
+            logger.info("Test: Challenge with multiple unsupported KDF proposals")
+            return struct.pack(">BBHBBHBBHBBBBBBHBBH",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 2 * 4,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
+                               ord('c'), ord('d'),
+                               EAP_SIM_AT_KDF, 1, 255,
+                               EAP_SIM_AT_KDF, 1, 254)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-3 Truncated ID_Server")
-            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                              4 + 1 + 1 + 32 + 32 + 2,
-                              EAP_TYPE_GPSK,
-                              EAP_GPSK_OPCODE_GPSK_3)
-            msg += req[14:46]
-            msg += struct.pack(">8LH", 0, 0, 0, 0, 0, 0, 0, 0, 1)
-            return msg
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Supported CSuite")
-            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 1)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: GPSK-3 Mismatch in ID_Server")
-            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                              4 + 1 + 1 + 32 + 32 + 3,
-                              EAP_TYPE_GPSK,
-                              EAP_GPSK_OPCODE_GPSK_3)
-            msg += req[14:46]
-            msg += struct.pack(">8LHB", 0, 0, 0, 0, 0, 0, 0, 0, 1, ord('B'))
-            return msg
-
+            logger.info("Test: Challenge with multiple KDF proposals")
+            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 3 * 4,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
+                               ord('c'), ord('d'),
+                               EAP_SIM_AT_KDF, 1, 255,
+                               EAP_SIM_AT_KDF, 1, 254,
+                               EAP_SIM_AT_KDF, 1, 1)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Supported CSuite")
-            return struct.pack(">BBHBBHB8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 3 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 1, ord('A'),
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 1)
+            logger.info("Test: Challenge with invalid MAC, RAND, AUTN values)")
+            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBHBBHBBH4LBBH4LBBH4L",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 4 * 4 + 20 + 20 + 20,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
+                               ord('c'), ord('d'),
+                               EAP_SIM_AT_KDF, 1, 1,
+                               EAP_SIM_AT_KDF, 1, 255,
+                               EAP_SIM_AT_KDF, 1, 254,
+                               EAP_SIM_AT_KDF, 1, 1,
+                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0,
+                               EAP_SIM_AT_RAND, 5, 0, 0, 0, 0, 0,
+                               EAP_SIM_AT_AUTN, 5, 0, 0, 0, 0, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-3 Mismatch in ID_Server (same length)")
-            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                              4 + 1 + 1 + 32 + 32 + 3,
-                              EAP_TYPE_GPSK,
-                              EAP_GPSK_OPCODE_GPSK_3)
-            msg += req[15:47]
-            msg += struct.pack(">8LHB", 0, 0, 0, 0, 0, 0, 0, 0, 1, ord('B'))
-            return msg
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Supported CSuite")
-            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 1)
+            logger.info("Test: Challenge - AMF separation bit not set)")
+            return struct.pack(">BBHBBHBBHBBBBBBHBBH4LBBH4LBBH4L",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 4 + 20 + 20 + 20,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
+                               ord('c'), ord('d'),
+                               EAP_SIM_AT_KDF, 1, 1,
+                               EAP_SIM_AT_MAC, 5, 0, 1, 2, 3, 4,
+                               EAP_SIM_AT_RAND, 5, 0, 5, 6, 7, 8,
+                               EAP_SIM_AT_AUTN, 5, 0, 9, 10,
+                               0x2fda8ef7, 0xbba518cc)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-3 Missing CSuite_Sel")
-            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                              4 + 1 + 1 + 32 + 32 + 2,
-                              EAP_TYPE_GPSK,
-                              EAP_GPSK_OPCODE_GPSK_3)
-            msg += req[14:46]
-            msg += struct.pack(">8LH", 0, 0, 0, 0, 0, 0, 0, 0, 0)
-            return msg
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Supported CSuite")
-            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 1)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: GPSK-3 Mismatch in CSuite_Sel")
-            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                              4 + 1 + 1 + 32 + 32 + 2 + 6,
-                              EAP_TYPE_GPSK,
-                              EAP_GPSK_OPCODE_GPSK_3)
-            msg += req[14:46]
-            msg += struct.pack(">8LHLH", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2)
-            return msg
-
+            logger.info("Test: Challenge - Invalid MAC")
+            return struct.pack(">BBHBBHBBHBBBBBBHBBH4LBBH4LBBH4L",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 4 + 20 + 20 + 20,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
+                               ord('c'), ord('d'),
+                               EAP_SIM_AT_KDF, 1, 1,
+                               EAP_SIM_AT_MAC, 5, 0, 1, 2, 3, 4,
+                               EAP_SIM_AT_RAND, 5, 0, 5, 6, 7, 8,
+                               EAP_SIM_AT_AUTN, 5, 0, 0xffffffff, 0xffffffff,
+                               0xd1f90322, 0x40514cb4)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Supported CSuite")
-            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 1)
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-3 Missing len(PD_Payload_Block)")
-            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                              4 + 1 + 1 + 32 + 32 + 2 + 6,
-                              EAP_TYPE_GPSK,
-                              EAP_GPSK_OPCODE_GPSK_3)
-            msg += req[14:46]
-            msg += struct.pack(">8LHLH", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)
-            return msg
+            logger.info("Test: Challenge - Valid MAC")
+            return struct.pack(">BBHBBHBBHBBBBBBHBBH4LBBH4LBBH4L",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 4 + 20 + 20 + 20,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
+                               ord('c'), ord('d'),
+                               EAP_SIM_AT_KDF, 1, 1,
+                               EAP_SIM_AT_MAC, 5, 0,
+                               0xf4a3c1d3, 0x7c901401, 0x34bd8b01, 0x6f7fa32f,
+                               EAP_SIM_AT_RAND, 5, 0, 5, 6, 7, 8,
+                               EAP_SIM_AT_AUTN, 5, 0, 0xffffffff, 0xffffffff,
+                               0xd1f90322, 0x40514cb4)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Supported CSuite")
-            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 1)
+            logger.info("Test: Invalid AT_KDF_INPUT length")
+            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_KDF_INPUT, 2, 0xffff, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-3 Truncated PD_Payload_Block")
-            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                              4 + 1 + 1 + 32 + 32 + 2 + 6 + 2,
-                              EAP_TYPE_GPSK,
-                              EAP_GPSK_OPCODE_GPSK_3)
-            msg += req[14:46]
-            msg += struct.pack(">8LHLHH", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1)
-            return msg
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Supported CSuite")
-            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 1)
+            logger.info("Test: Invalid AT_KDF length")
+            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_IDENTITY, 0,
+                               EAP_SIM_AT_KDF, 2, 0, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-3 Missing MAC")
-            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                              4 + 1 + 1 + 32 + 32 + 2 + 6 + 3,
-                              EAP_TYPE_GPSK,
-                              EAP_GPSK_OPCODE_GPSK_3)
-            msg += req[14:46]
-            msg += struct.pack(">8LHLHHB",
-                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 123)
-            return msg
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-1 Supported CSuite")
-            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 32 + 2 + 6,
-                               EAP_TYPE_GPSK,
-                               EAP_GPSK_OPCODE_GPSK_1, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               6, 0, 1)
+            logger.info("Test: Challenge with large number of KDF proposals")
+            return struct.pack(">BBHBBHBBHBBHBBHBBHBBHBBHBBHBBHBBHBBHBBHBBH",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 12 * 4,
+                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_KDF, 1, 255,
+                               EAP_SIM_AT_KDF, 1, 254,
+                               EAP_SIM_AT_KDF, 1, 253,
+                               EAP_SIM_AT_KDF, 1, 252,
+                               EAP_SIM_AT_KDF, 1, 251,
+                               EAP_SIM_AT_KDF, 1, 250,
+                               EAP_SIM_AT_KDF, 1, 249,
+                               EAP_SIM_AT_KDF, 1, 248,
+                               EAP_SIM_AT_KDF, 1, 247,
+                               EAP_SIM_AT_KDF, 1, 246,
+                               EAP_SIM_AT_KDF, 1, 245,
+                               EAP_SIM_AT_KDF, 1, 244)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: GPSK-3 Incorrect MAC")
-            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                              4 + 1 + 1 + 32 + 32 + 2 + 6 + 3 + 16,
-                              EAP_TYPE_GPSK,
-                              EAP_GPSK_OPCODE_GPSK_3)
-            msg += req[14:46]
-            msg += struct.pack(">8LHLHHB4L",
-                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 123,
-                               0, 0, 0, 0)
-            return msg
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         return None
 
-    srv = start_radius_server(gpsk_handler)
+    srv = start_radius_server(aka_prime_handler)
 
     try:
-        hapd = start_ap(apdev[0]['ifname'])
+        hapd = start_ap(apdev[0])
 
-        for i in range(0, 27):
-            if i == 12:
-                pw = "short"
-            else:
-                pw = "abcdefghijklmnop0123456789abcdef"
+        for i in range(0, 16):
             dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
-                           eap="GPSK", identity="user", password=pw,
+                           eap="AKA'", identity="6555444333222111",
+                           password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
                            wait_connect=False)
             ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
                                    timeout=15)
             if ev is None:
                 raise Exception("Timeout on EAP start")
-            time.sleep(0.05)
+            if i in [ 0 ]:
+                time.sleep(0.1)
+            else:
+                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
+                                       timeout=10)
+                if ev is None:
+                    raise Exception("Timeout on EAP failure")
             dev[0].request("REMOVE_NETWORK all")
+            dev[0].dump_monitor()
     finally:
         stop_radius_server(srv)
 
-EAP_EKE_ID = 1
-EAP_EKE_COMMIT = 2
-EAP_EKE_CONFIRM = 3
-EAP_EKE_FAILURE = 4
-
-def test_eap_proto_eke(dev, apdev):
-    """EAP-EKE protocol tests"""
-    def eke_handler(ctx, req):
-        logger.info("eke_handler - RX " + req.encode("hex"))
+def test_eap_proto_sim(dev, apdev):
+    """EAP-SIM protocol tests"""
+    def sim_handler(ctx, req):
+        logger.info("sim_handler - RX " + req.encode("hex"))
         if 'num' not in ctx:
             ctx['num'] = 0
         ctx['num'] = ctx['num'] + 1
@@ -1314,66 +4047,15 @@ def test_eap_proto_eke(dev, apdev):
             logger.info("Test: Missing payload")
             return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1,
-                               EAP_TYPE_EKE)
-
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Unknown exchange")
-            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1,
-                               EAP_TYPE_EKE,
-                               255)
-
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: No NumProposals in EAP-EKE-ID/Request")
-            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_ID)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
-
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: NumProposals=0 in EAP-EKE-ID/Request")
-            return struct.pack(">BBHBBB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 1,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_ID,
-                               0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
-
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Truncated Proposals list in EAP-EKE-ID/Request")
-            return struct.pack(">BBHBBBB4B", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 4,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_ID,
-                               2, 0, 0, 0, 0, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+                               EAP_TYPE_SIM)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unsupported proposals in EAP-EKE-ID/Request")
-            return struct.pack(">BBHBBBB4B4B4B4B", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 4 * 4,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_ID,
-                               4, 0,
-                               0, 0, 0, 0,
-                               3, 0, 0, 0,
-                               3, 1, 0, 0,
-                               3, 1, 1, 0)
+            logger.info("Test: Unexpected AT_AUTN")
+            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
+                               EAP_SIM_AT_AUTN, 2, 0, 0)
         idx += 1
         if ctx['num'] == idx:
             logger.info("Test: EAP-Failure")
@@ -1381,18 +4063,11 @@ def test_eap_proto_eke(dev, apdev):
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Missing IDType/Identity in EAP-EKE-ID/Request")
-            return struct.pack(">BBHBBBB4B4B4B4B4B",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 5 * 4,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_ID,
-                               5, 0,
-                               0, 0, 0, 0,
-                               3, 0, 0, 0,
-                               3, 1, 0, 0,
-                               3, 1, 1, 0,
-                               3, 1, 1, 1)
+            logger.info("Test: Too short AT_VERSION_LIST")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
+                               EAP_SIM_AT_VERSION_LIST, 1, 0)
         idx += 1
         if ctx['num'] == idx:
             logger.info("Test: EAP-Failure")
@@ -1400,26 +4075,11 @@ def test_eap_proto_eke(dev, apdev):
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Valid EAP-EKE-ID/Request")
-            return struct.pack(">BBHBBBB4BB",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 4 + 1,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_ID,
-                               1, 0,
-                               3, 1, 1, 1,
-                               255)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Unexpected EAP-EKE-ID/Request")
-            return struct.pack(">BBHBBBB4BB",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 4 + 1,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_ID,
-                               1, 0,
-                               3, 1, 1, 1,
-                               255)
+            logger.info("Test: AT_VERSION_LIST overflow")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
+                               EAP_SIM_AT_VERSION_LIST, 1, 0xffff)
         idx += 1
         if ctx['num'] == idx:
             logger.info("Test: EAP-Failure")
@@ -1427,23 +4087,23 @@ def test_eap_proto_eke(dev, apdev):
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Valid EAP-EKE-ID/Request")
-            return struct.pack(">BBHBBBB4BB",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 4 + 1,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_ID,
-                               1, 0,
-                               3, 1, 1, 1,
-                               255)
+            logger.info("Test: Unexpected AT_AUTS")
+            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
+                               EAP_SIM_AT_AUTS, 2, 0, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected EAP-EKE-Confirm/Request")
-            return struct.pack(">BBHBB",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_CONFIRM)
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unexpected AT_CHECKCODE")
+            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
+                               EAP_SIM_AT_CHECKCODE, 2, 0, 0)
         idx += 1
         if ctx['num'] == idx:
             logger.info("Test: EAP-Failure")
@@ -1451,12 +4111,10 @@ def test_eap_proto_eke(dev, apdev):
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Too short EAP-EKE-Failure/Request")
-            return struct.pack(">BBHBB",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_FAILURE)
+            logger.info("Test: No AT_VERSION_LIST in Start")
+            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0)
         idx += 1
         if ctx['num'] == idx:
             logger.info("Test: EAP-Failure")
@@ -1464,36 +4122,40 @@ def test_eap_proto_eke(dev, apdev):
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected EAP-EKE-Commit/Request")
-            return struct.pack(">BBHBB",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_COMMIT)
+            logger.info("Test: No support version in AT_VERSION_LIST")
+            return struct.pack(">BBHBBHBBH4B", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
+                               EAP_SIM_AT_VERSION_LIST, 2, 3, 2, 3, 4, 5)
         idx += 1
         if ctx['num'] == idx:
             logger.info("Test: EAP-Failure")
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Valid EAP-EKE-ID/Request")
-            return struct.pack(">BBHBBBB4BB",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 4 + 1,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_ID,
-                               1, 0,
-                               3, 1, 1, 1,
-                               255)
+            logger.info("Test: Identity request without ID type")
+            return struct.pack(">BBHBBHBBH2H", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
+                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Too short EAP-EKE-Commit/Request")
-            return struct.pack(">BBHBB",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_COMMIT)
+            logger.info("Test: Identity request ANY_ID")
+            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 4,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
+                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
+                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity request ANY_ID (duplicate)")
+            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 4,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
+                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
+                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
         idx += 1
         if ctx['num'] == idx:
             logger.info("Test: EAP-Failure")
@@ -1501,34 +4163,28 @@ def test_eap_proto_eke(dev, apdev):
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Valid EAP-EKE-ID/Request")
-            return struct.pack(">BBHBBBB4BB",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 4 + 1,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_ID,
-                               1, 0,
-                               1, 1, 1, 1,
-                               255)
+            logger.info("Test: Identity request ANY_ID")
+            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 4,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
+                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
+                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: All zeroes DHComponent_S and empty CBvalue in EAP-EKE-Commit/Request")
-            return struct.pack(">BBHBB4L32L",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 16 + 128,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_COMMIT,
-                               0, 0, 0, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+            logger.info("Test: Identity request FULLAUTH_ID")
+            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 4,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
+                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
+                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Too short EAP-EKE-Confirm/Request")
-            return struct.pack(">BBHBB",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_CONFIRM)
+            logger.info("Test: Identity request FULLAUTH_ID (duplicate)")
+            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 4,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
+                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
+                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
         idx += 1
         if ctx['num'] == idx:
             logger.info("Test: EAP-Failure")
@@ -1536,579 +4192,567 @@ def test_eap_proto_eke(dev, apdev):
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Valid EAP-EKE-ID/Request")
-            return struct.pack(">BBHBBBB4BB",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2 + 4 + 1,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_ID,
-                               1, 0,
-                               1, 1, 1, 1,
-                               255)
+            logger.info("Test: Identity request ANY_ID")
+            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 4,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
+                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
+                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: All zeroes DHComponent_S and empty CBvalue in EAP-EKE-Commit/Request")
-            return struct.pack(">BBHBB4L32L",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 16 + 128,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_COMMIT,
-                               0, 0, 0, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+            logger.info("Test: Identity request FULLAUTH_ID")
+            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 4,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
+                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
+                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid PNonce_PS and Auth_S values in EAP-EKE-Confirm/Request")
-            return struct.pack(">BBHBB4L8L5L5L",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 16 + 2 * 16 + 20 + 20,
-                               EAP_TYPE_EKE,
-                               EAP_EKE_CONFIRM,
-                               0, 0, 0, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               0, 0, 0, 0, 0,
-                               0, 0, 0, 0, 0)
+            logger.info("Test: Identity request PERMANENT_ID")
+            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 4,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
+                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
+                               EAP_SIM_AT_PERMANENT_ID_REQ, 1, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Identity request PERMANENT_ID (duplicate)")
+            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 8 + 4,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
+                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
+                               EAP_SIM_AT_PERMANENT_ID_REQ, 1, 0)
         idx += 1
         if ctx['num'] == idx:
             logger.info("Test: EAP-Failure")
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
-        return None
-
-    srv = start_radius_server(eke_handler)
-
-    try:
-        hapd = start_ap(apdev[0]['ifname'])
-
-        for i in range(0, 14):
-            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
-                           eap="EKE", identity="user", password="password",
-                           wait_connect=False)
-            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
-                                   timeout=15)
-            if ev is None:
-                raise Exception("Timeout on EAP start")
-            if i in [ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 ]:
-                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
-                                       timeout=10)
-                if ev is None:
-                    raise Exception("Timeout on EAP failure")
-            else:
-                time.sleep(0.05)
-            dev[0].request("REMOVE_NETWORK all")
-            dev[0].dump_monitor()
-    finally:
-        stop_radius_server(srv)
-
-EAP_PAX_OP_STD_1 = 0x01
-EAP_PAX_OP_STD_2 = 0x02
-EAP_PAX_OP_STD_3 = 0x03
-EAP_PAX_OP_SEC_1 = 0x11
-EAP_PAX_OP_SEC_2 = 0x12
-EAP_PAX_OP_SEC_3 = 0x13
-EAP_PAX_OP_SEC_4 = 0x14
-EAP_PAX_OP_SEC_5 = 0x15
-EAP_PAX_OP_ACK = 0x21
-
-EAP_PAX_FLAGS_MF = 0x01
-EAP_PAX_FLAGS_CE = 0x02
-EAP_PAX_FLAGS_AI = 0x04
-
-EAP_PAX_MAC_HMAC_SHA1_128 = 0x01
-EAP_PAX_HMAC_SHA256_128 = 0x02
-
-EAP_PAX_DH_GROUP_NONE = 0x00
-EAP_PAX_DH_GROUP_2048_MODP = 0x01
-EAP_PAX_DH_GROUP_3072_MODP = 0x02
-EAP_PAX_DH_GROUP_NIST_ECC_P_256 = 0x03
-
-EAP_PAX_PUBLIC_KEY_NONE = 0x00
-EAP_PAX_PUBLIC_KEY_RSAES_OAEP = 0x01
-EAP_PAX_PUBLIC_KEY_RSA_PKCS1_V1_5 = 0x02
-EAP_PAX_PUBLIC_KEY_EL_GAMAL_NIST_ECC = 0x03
-
-EAP_PAX_ADE_VENDOR_SPECIFIC = 0x01
-EAP_PAX_ADE_CLIENT_CHANNEL_BINDING = 0x02
-EAP_PAX_ADE_SERVER_CHANNEL_BINDING = 0x03
-
-def test_eap_proto_pax(dev, apdev):
-    """EAP-PAX protocol tests"""
-    def pax_std_1(ctx):
-            logger.info("Test: STD-1")
-            ctx['id'] = 10
-            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 2 + 32 + 16,
-                               EAP_TYPE_PAX,
-                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
-                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
-                               32, 0, 0, 0, 0, 0, 0, 0, 0,
-                               0x16, 0xc9, 0x08, 0x9d, 0x98, 0xa5, 0x6e, 0x1f,
-                               0xf0, 0xac, 0xcf, 0xc4, 0x66, 0xcd, 0x2d, 0xbf)
-
-    def pax_handler(ctx, req):
-        logger.info("pax_handler - RX " + req.encode("hex"))
-        if 'num' not in ctx:
-            ctx['num'] = 0
-        ctx['num'] = ctx['num'] + 1
-        if 'id' not in ctx:
-            ctx['id'] = 1
-        ctx['id'] = (ctx['id'] + 1) % 256
-
-        idx = 0
-
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Missing payload")
-            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1,
-                               EAP_TYPE_PAX)
+            logger.info("Test: No AT_MAC and AT_RAND in Challenge")
+            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Minimum length payload")
-            return struct.pack(">BBHB4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 16,
-                               EAP_TYPE_PAX,
-                               0, 0, 0, 0)
-
+            logger.info("Test: No AT_RAND in Challenge")
+            return struct.pack(">BBHBBHBBH4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 20,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unsupported MAC ID")
-            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 16,
-                               EAP_TYPE_PAX,
-                               EAP_PAX_OP_STD_1, 0, 255, EAP_PAX_DH_GROUP_NONE,
-                               EAP_PAX_PUBLIC_KEY_NONE,
-                               0, 0, 0, 0)
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unsupported DH Group ID")
-            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 16,
-                               EAP_TYPE_PAX,
-                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
-                               255, EAP_PAX_PUBLIC_KEY_NONE,
-                               0, 0, 0, 0)
-
+            logger.info("Test: Insufficient number of challenges in Challenge")
+            return struct.pack(">BBHBBHBBH4LBBH4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 20 + 20,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_RAND, 5, 0, 0, 0, 0, 0,
+                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unsupported Public Key ID")
-            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 16,
-                               EAP_TYPE_PAX,
-                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
-                               EAP_PAX_DH_GROUP_NONE, 255,
-                               0, 0, 0, 0)
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: More fragments")
-            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 16,
-                               EAP_TYPE_PAX,
-                               EAP_PAX_OP_STD_1, EAP_PAX_FLAGS_MF,
-                               EAP_PAX_MAC_HMAC_SHA1_128,
-                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
-                               0, 0, 0, 0)
-
+            logger.info("Test: Too many challenges in Challenge")
+            return struct.pack(">BBHBBHBBH4L4L4L4LBBH4L", EAP_CODE_REQUEST,
+                               ctx['id'],
+                               4 + 1 + 3 + 4 + 4 * 16 + 20,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_RAND, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0,
+                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid ICV")
-            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 16,
-                               EAP_TYPE_PAX,
-                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
-                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
-                               0, 0, 0, 0)
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid ICV in short frame")
-            return struct.pack(">BBHBBBBBB3L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 12,
-                               EAP_TYPE_PAX,
-                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
-                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
-                               0, 0, 0)
-
+            logger.info("Test: Same RAND multiple times in Challenge")
+            return struct.pack(">BBHBBHBBH4L4L4LBBH4L", EAP_CODE_REQUEST,
+                               ctx['id'],
+                               4 + 1 + 3 + 4 + 3 * 16 + 20,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0,
+                               EAP_SIM_AT_RAND, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+                               0, 0, 0, 0,
+                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Correct ICV - unsupported op_code")
-            ctx['id'] = 10
-            return struct.pack(">BBHBBBBBB16B", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 16,
-                               EAP_TYPE_PAX,
-                               255, 0, EAP_PAX_MAC_HMAC_SHA1_128,
-                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
-                               0x90, 0x78, 0x97, 0x38, 0x29, 0x94, 0x32, 0xd4,
-                               0x81, 0x27, 0xe0, 0xf6, 0x3b, 0x0d, 0xb2, 0xb2)
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Correct ICV - CE flag in STD-1")
-            ctx['id'] = 10
-            return struct.pack(">BBHBBBBBB16B", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 16,
-                               EAP_TYPE_PAX,
-                               EAP_PAX_OP_STD_1, EAP_PAX_FLAGS_CE,
-                               EAP_PAX_MAC_HMAC_SHA1_128,
-                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
-                               0x9c, 0x98, 0xb4, 0x0b, 0x94, 0x90, 0xde, 0x88,
-                               0xb7, 0x72, 0x63, 0x44, 0x1d, 0xe3, 0x7c, 0x5c)
-
+            logger.info("Test: Notification with no attributes")
+            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Correct ICV - too short STD-1 payload")
-            ctx['id'] = 10
-            return struct.pack(">BBHBBBBBB16B", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 16,
-                               EAP_TYPE_PAX,
-                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
-                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
-                               0xda, 0xab, 0x2c, 0xe7, 0x84, 0x41, 0xb5, 0x5c,
-                               0xee, 0xcf, 0x62, 0x03, 0xc5, 0x69, 0xcb, 0xf4)
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Correct ICV - incorrect A length in STD-1")
-            ctx['id'] = 10
-            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 2 + 32 + 16,
-                               EAP_TYPE_PAX,
-                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
-                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
-                               0, 0, 0, 0, 0, 0, 0, 0, 0,
-                               0xc4, 0xb0, 0x81, 0xe4, 0x6c, 0x8c, 0x20, 0x23,
-                               0x60, 0x46, 0x89, 0xea, 0x94, 0x60, 0xf3, 0x2a)
+            logger.info("Test: Notification indicating success, but no MAC")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
+                               EAP_SIM_AT_NOTIFICATION, 1, 32768)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Correct ICV - extra data in STD-1")
-            ctx['id'] = 10
-            return struct.pack(">BBHBBBBBBH8LB16B", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 2 + 32 + 1 + 16,
-                               EAP_TYPE_PAX,
-                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
-                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
-                               32, 0, 0, 0, 0, 0, 0, 0, 0,
-                               1,
-                               0x61, 0x49, 0x65, 0x37, 0x21, 0xe8, 0xd8, 0xbf,
-                               0xf3, 0x02, 0x01, 0xe5, 0x42, 0x51, 0xd3, 0x34)
+            logger.info("Test: Notification indicating success, but invalid MAC value")
+            return struct.pack(">BBHBBHBBHBBH4L", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 20,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
+                               EAP_SIM_AT_NOTIFICATION, 1, 32768,
+                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected STD-1")
-            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 2 + 32 + 16,
-                               EAP_TYPE_PAX,
-                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
-                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
-                               32, 0, 0, 0, 0, 0, 0, 0, 0,
-                               0xe5, 0x1d, 0xbf, 0xb8, 0x70, 0x20, 0x5c, 0xba,
-                               0x41, 0xbb, 0x34, 0xda, 0x1a, 0x08, 0xe6, 0x8d)
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            return pax_std_1(ctx)
+            logger.info("Test: Notification before auth")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
+                               EAP_SIM_AT_NOTIFICATION, 1, 16384)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: MAC ID changed during session")
-            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 2 + 32 + 16,
-                               EAP_TYPE_PAX,
-                               EAP_PAX_OP_STD_1, 0, EAP_PAX_HMAC_SHA256_128,
-                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
-                               32, 0, 0, 0, 0, 0, 0, 0, 0,
-                               0xee, 0x00, 0xbf, 0xb8, 0x70, 0x20, 0x5c, 0xba,
-                               0x41, 0xbb, 0x34, 0xda, 0x1a, 0x08, 0xe6, 0x8d)
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            return pax_std_1(ctx)
+            logger.info("Test: Notification before auth")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
+                               EAP_SIM_AT_NOTIFICATION, 1, 16385)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: DH Group ID changed during session")
-            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 2 + 32 + 16,
-                               EAP_TYPE_PAX,
-                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
-                               EAP_PAX_DH_GROUP_2048_MODP,
-                               EAP_PAX_PUBLIC_KEY_NONE,
-                               32, 0, 0, 0, 0, 0, 0, 0, 0,
-                               0xee, 0x01, 0xbf, 0xb8, 0x70, 0x20, 0x5c, 0xba,
-                               0x41, 0xbb, 0x34, 0xda, 0x1a, 0x08, 0xe6, 0x8d)
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            return pax_std_1(ctx)
+            logger.info("Test: Notification with unrecognized non-failure")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
+                               EAP_SIM_AT_NOTIFICATION, 1, 0xc000)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Public Key ID changed during session")
-            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 2 + 32 + 16,
-                               EAP_TYPE_PAX,
-                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
-                               EAP_PAX_DH_GROUP_NONE,
-                               EAP_PAX_PUBLIC_KEY_RSAES_OAEP,
-                               32, 0, 0, 0, 0, 0, 0, 0, 0,
-                               0xee, 0x02, 0xbf, 0xb8, 0x70, 0x20, 0x5c, 0xba,
-                               0x41, 0xbb, 0x34, 0xda, 0x1a, 0x08, 0xe6, 0x8d)
+            logger.info("Test: Notification before auth (duplicate)")
+            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
+                               EAP_SIM_AT_NOTIFICATION, 1, 0xc000)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected STD-3")
-            ctx['id'] = 10
-            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 2 + 32 + 16,
-                               EAP_TYPE_PAX,
-                               EAP_PAX_OP_STD_3, 0, EAP_PAX_MAC_HMAC_SHA1_128,
-                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
-                               32, 0, 0, 0, 0, 0, 0, 0, 0,
-                               0x47, 0xbb, 0xc0, 0xf9, 0xb9, 0x69, 0xf5, 0xcb,
-                               0x3a, 0xe8, 0xe7, 0xd6, 0x80, 0x28, 0xf2, 0x59)
+            logger.info("Test: Re-authentication (unexpected) with no attributes")
+            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_REAUTHENTICATION,
+                               0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            return pax_std_1(ctx)
+            logger.info("Test: Client Error")
+            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3,
+                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CLIENT_ERROR, 0)
         idx += 1
         if ctx['num'] == idx:
-            # TODO: MAC calculation; for now, this gets dropped due to incorrect
-            # ICV
-            logger.info("Test: STD-3 with CE flag")
-            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 5 + 2 + 32 + 16,
-                               EAP_TYPE_PAX,
-                               EAP_PAX_OP_STD_3, EAP_PAX_FLAGS_CE,
-                               EAP_PAX_MAC_HMAC_SHA1_128,
-                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
-                               32, 0, 0, 0, 0, 0, 0, 0, 0,
-                               0x8a, 0xc2, 0xf9, 0xf4, 0x8b, 0x75, 0x72, 0xa2,
-                               0x4d, 0xd3, 0x1e, 0x54, 0x77, 0x04, 0x05, 0xe2)
+            logger.info("Test: EAP-Failure")
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
-        if ctx['num'] & 0x1 == idx & 0x1:
-            logger.info("Test: Default request")
-            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1,
-                               EAP_TYPE_PAX)
-        else:
-            logger.info("Test: Default EAP-Failure")
+        if ctx['num'] == idx:
+            logger.info("Test: Unknown subtype")
+            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3,
+                               EAP_TYPE_SIM, 255, 0)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: EAP-Failure")
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
-    srv = start_radius_server(pax_handler)
+        return None
+
+    srv = start_radius_server(sim_handler)
 
     try:
-        hapd = start_ap(apdev[0]['ifname'])
+        hapd = start_ap(apdev[0])
 
-        for i in range(0, 18):
+        for i in range(0, 25):
             dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
-                           eap="PAX", identity="user",
-                           password_hex="0123456789abcdef0123456789abcdef",
+                           eap="SIM", identity="1232010000000000",
+                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
                            wait_connect=False)
-            logger.info("Waiting for EAP method to start")
             ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
                                    timeout=15)
             if ev is None:
                 raise Exception("Timeout on EAP start")
-            time.sleep(0.05)
+            if i in [ 0 ]:
+                time.sleep(0.1)
+            else:
+                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
+                                       timeout=10)
+                if ev is None:
+                    raise Exception("Timeout on EAP failure")
             dev[0].request("REMOVE_NETWORK all")
             dev[0].dump_monitor()
+    finally:
+        stop_radius_server(srv)
 
-        logger.info("Too short password")
+def test_eap_proto_sim_errors(dev, apdev):
+    """EAP-SIM protocol tests (error paths)"""
+    check_hlr_auc_gw_support()
+    params = hostapd.wpa2_eap_params(ssid="eap-test")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    with alloc_fail(dev[0], 1, "eap_sim_init"):
         dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
-                       eap="PAX", identity="user",
-                       password_hex="0123456789abcdef0123456789abcd",
+                       eap="SIM", identity="1232010000000000",
+                       password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
                        wait_connect=False)
-        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
+        ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
+                               timeout=15)
         if ev is None:
             raise Exception("Timeout on EAP start")
-        time.sleep(0.1)
         dev[0].request("REMOVE_NETWORK all")
-        dev[0].dump_monitor()
+        dev[0].wait_disconnected()
 
-        logger.info("No password")
+    with fail_test(dev[0], 1, "os_get_random;eap_sim_init"):
         dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
-                       eap="PAX", identity="user",
+                       eap="SIM", identity="1232010000000000",
+                       password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
                        wait_connect=False)
-        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
+        ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
+                               timeout=15)
         if ev is None:
             raise Exception("Timeout on EAP start")
-        time.sleep(0.1)
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="SIM", identity="1232010000000000",
+                   password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
+
+    with fail_test(dev[0], 1, "aes_128_cbc_encrypt;eap_sim_response_reauth"):
+        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
+        if ev is None:
+            raise Exception("EAP re-authentication did not start")
+        wait_fail_trigger(dev[0], "GET_FAIL")
         dev[0].request("REMOVE_NETWORK all")
         dev[0].dump_monitor()
-    finally:
-        stop_radius_server(srv)
 
-def test_eap_proto_psk(dev, apdev):
-    """EAP-PSK protocol tests"""
-    def psk_handler(ctx, req):
-        logger.info("psk_handler - RX " + req.encode("hex"))
-        if 'num' not in ctx:
-            ctx['num'] = 0
-        ctx['num'] = ctx['num'] + 1
-        if 'id' not in ctx:
-            ctx['id'] = 1
-        ctx['id'] = (ctx['id'] + 1) % 256
+    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="SIM", identity="1232010000000000",
+                   password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
 
-        idx = 0
+    with fail_test(dev[0], 1, "os_get_random;eap_sim_msg_add_encr_start"):
+        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
+        if ev is None:
+            raise Exception("EAP re-authentication did not start")
+        wait_fail_trigger(dev[0], "GET_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].dump_monitor()
 
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Missing payload")
-            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1,
-                               EAP_TYPE_PSK)
+    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="SIM", identity="1232010000000000",
+                   password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
 
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Non-zero T in first message")
-            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 16,
-                               EAP_TYPE_PSK, 0xc0, 0, 0, 0, 0)
+    with fail_test(dev[0], 1, "os_get_random;eap_sim_init_for_reauth"):
+        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
+        if ev is None:
+            raise Exception("EAP re-authentication did not start")
+        wait_fail_trigger(dev[0], "GET_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].dump_monitor()
 
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Valid first message")
-            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 16,
-                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Too short third message")
-            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1,
-                               EAP_TYPE_PSK)
+    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="SIM", identity="1232010000000000",
+                   password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
 
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Valid first message")
-            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 16,
-                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Incorrect T in third message")
-            return struct.pack(">BBHBB4L4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 16 + 16,
-                               EAP_TYPE_PSK, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+    with alloc_fail(dev[0], 1, "eap_sim_parse_encr;eap_sim_process_reauthentication"):
+        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
+        if ev is None:
+            raise Exception("EAP re-authentication did not start")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].dump_monitor()
 
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Valid first message")
-            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 16,
-                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Missing PCHANNEL in third message")
-            return struct.pack(">BBHBB4L4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 16 + 16,
-                               EAP_TYPE_PSK, 0x80, 0, 0, 0, 0, 0, 0, 0, 0)
+    tests = [ (1, "eap_sim_verify_mac;eap_sim_process_challenge"),
+              (1, "eap_sim_parse_encr;eap_sim_process_challenge"),
+              (1, "eap_sim_msg_init;eap_sim_response_start"),
+              (1, "wpabuf_alloc;eap_sim_msg_init;eap_sim_response_start"),
+              (1, "=eap_sim_learn_ids"),
+              (2, "=eap_sim_learn_ids"),
+              (2, "eap_sim_learn_ids"),
+              (3, "eap_sim_learn_ids"),
+              (1, "eap_sim_process_start"),
+              (1, "eap_sim_getKey"),
+              (1, "eap_sim_get_emsk"),
+              (1, "eap_sim_get_session_id") ]
+    for count, func in tests:
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="SIM", identity="1232010000000000",
+                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
+                           erp="1", wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].dump_monitor()
 
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Valid first message")
-            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 16,
-                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Invalic MAC_S in third message")
-            return struct.pack(">BBHBB4L4L5LB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 16 + 16 + 21,
-                               EAP_TYPE_PSK, 0x80, 0, 0, 0, 0, 0, 0, 0, 0,
-                               0, 0, 0, 0, 0, 0)
+    tests = [ (1, "aes_128_cbc_decrypt;eap_sim_parse_encr") ]
+    for count, func in tests:
+        with fail_test(dev[0], count, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="SIM", identity="1232010000000000",
+                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].dump_monitor()
 
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Valid first message")
-            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 16,
-                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+    params = int_eap_server_params()
+    params['eap_sim_db'] = "unix:/tmp/hlr_auc_gw.sock"
+    params['eap_sim_aka_result_ind'] = "1"
+    hostapd.add_ap(apdev[1], params)
+
+    with alloc_fail(dev[0], 1,
+                    "eap_sim_msg_init;eap_sim_response_notification"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
+                       scan_freq="2412",
+                       eap="SIM", identity="1232010000000000",
+                       phase1="result_ind=1",
+                       password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
+                       wait_connect=False)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].dump_monitor()
 
-        return None
+    tests = [ "eap_sim_msg_add_encr_start;eap_sim_response_notification",
+              "aes_128_cbc_encrypt;eap_sim_response_notification" ]
+    for func in tests:
+        with fail_test(dev[0], 1, func):
+            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
+                           scan_freq="2412",
+                           eap="SIM", identity="1232010000000000",
+                           phase1="result_ind=1",
+                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
+            dev[0].request("REAUTHENTICATE")
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
+            if ev is None:
+                raise Exception("EAP method not started on reauthentication")
+            time.sleep(0.1)
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].dump_monitor()
 
-    srv = start_radius_server(psk_handler)
+    tests = [ "eap_sim_parse_encr;eap_sim_process_notification_reauth" ]
+    for func in tests:
+        with alloc_fail(dev[0], 1, func):
+            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
+                           scan_freq="2412",
+                           eap="SIM", identity="1232010000000000",
+                           phase1="result_ind=1",
+                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
+            dev[0].request("REAUTHENTICATE")
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
+            if ev is None:
+                raise Exception("EAP method not started on reauthentication")
+            time.sleep(0.1)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].dump_monitor()
 
-    try:
-        hapd = start_ap(apdev[0]['ifname'])
+def test_eap_proto_aka_errors(dev, apdev):
+    """EAP-AKA protocol tests (error paths)"""
+    check_hlr_auc_gw_support()
+    params = hostapd.wpa2_eap_params(ssid="eap-test")
+    hapd = hostapd.add_ap(apdev[0], params)
 
-        for i in range(0, 6):
+    with alloc_fail(dev[0], 1, "eap_aka_init"):
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="AKA", identity="0232010000000000",
+                       password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
+                       wait_connect=False)
+        ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
+                               timeout=15)
+        if ev is None:
+            raise Exception("Timeout on EAP start")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    tests = [ (1, "=eap_aka_learn_ids"),
+              (2, "=eap_aka_learn_ids"),
+              (1, "eap_sim_parse_encr;eap_aka_process_challenge"),
+              (1, "wpabuf_dup;eap_aka_add_id_msg"),
+              (1, "wpabuf_resize;eap_aka_add_id_msg"),
+              (1, "eap_aka_getKey"),
+              (1, "eap_aka_get_emsk"),
+              (1, "eap_aka_get_session_id") ]
+    for count, func in tests:
+        with alloc_fail(dev[0], count, func):
             dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
-                           eap="PSK", identity="user",
-                           password_hex="0123456789abcdef0123456789abcdef",
-                           wait_connect=False)
-            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
-                                   timeout=15)
+                           eap="AKA", identity="0232010000000000",
+                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
+                           erp="1", wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].dump_monitor()
+
+    params = int_eap_server_params()
+    params['eap_sim_db'] = "unix:/tmp/hlr_auc_gw.sock"
+    params['eap_sim_aka_result_ind'] = "1"
+    hostapd.add_ap(apdev[1], params)
+
+    with alloc_fail(dev[0], 1,
+                    "eap_sim_msg_init;eap_aka_response_notification"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="AKA", identity="0232010000000000",
+                       phase1="result_ind=1",
+                       password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
+                       wait_connect=False)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].dump_monitor()
+
+    tests = [ "eap_sim_msg_add_encr_start;eap_aka_response_notification",
+              "aes_128_cbc_encrypt;eap_aka_response_notification" ]
+    for func in tests:
+        with fail_test(dev[0], 1, func):
+            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
+                           scan_freq="2412",
+                           eap="AKA", identity="0232010000000000",
+                           phase1="result_ind=1",
+                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123")
+            dev[0].request("REAUTHENTICATE")
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
             if ev is None:
-                raise Exception("Timeout on EAP start")
+                raise Exception("EAP method not started on reauthentication")
             time.sleep(0.1)
+            wait_fail_trigger(dev[0], "GET_FAIL")
             dev[0].request("REMOVE_NETWORK all")
+            dev[0].dump_monitor()
 
-        logger.info("Test: Invalid PSK length")
+    tests = [ "eap_sim_parse_encr;eap_aka_process_notification_reauth" ]
+    for func in tests:
+        with alloc_fail(dev[0], 1, func):
+            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
+                           scan_freq="2412",
+                           eap="AKA", identity="0232010000000000",
+                           phase1="result_ind=1",
+                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123")
+            dev[0].request("REAUTHENTICATE")
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
+            if ev is None:
+                raise Exception("EAP method not started on reauthentication")
+            time.sleep(0.1)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].dump_monitor()
+
+def test_eap_proto_aka_prime_errors(dev, apdev):
+    """EAP-AKA' protocol tests (error paths)"""
+    check_hlr_auc_gw_support()
+    params = hostapd.wpa2_eap_params(ssid="eap-test")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    with alloc_fail(dev[0], 1, "eap_aka_init"):
         dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
-                       eap="PSK", identity="user",
-                       password_hex="0123456789abcdef0123456789abcd",
+                       eap="AKA'", identity="6555444333222111",
+                       password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
                        wait_connect=False)
-        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+        ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
                                timeout=15)
         if ev is None:
             raise Exception("Timeout on EAP start")
-        time.sleep(0.1)
         dev[0].request("REMOVE_NETWORK all")
-    finally:
-        stop_radius_server(srv)
+        dev[0].wait_disconnected()
 
-EAP_SIM_SUBTYPE_START = 10
-EAP_SIM_SUBTYPE_CHALLENGE = 11
-EAP_SIM_SUBTYPE_NOTIFICATION = 12
-EAP_SIM_SUBTYPE_REAUTHENTICATION = 13
-EAP_SIM_SUBTYPE_CLIENT_ERROR = 14
+    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="AKA'", identity="6555444333222111",
+                   password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123")
 
-EAP_AKA_SUBTYPE_CHALLENGE = 1
-EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT = 2
-EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE = 4
-EAP_AKA_SUBTYPE_IDENTITY = 5
-EAP_AKA_SUBTYPE_NOTIFICATION = 12
-EAP_AKA_SUBTYPE_REAUTHENTICATION = 13
-EAP_AKA_SUBTYPE_CLIENT_ERROR = 14
+    with fail_test(dev[0], 1, "aes_128_cbc_encrypt;eap_aka_response_reauth"):
+        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
+        if ev is None:
+            raise Exception("EAP re-authentication did not start")
+        wait_fail_trigger(dev[0], "GET_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].dump_monitor()
+
+    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="AKA'", identity="6555444333222111",
+                   password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123")
+
+    with alloc_fail(dev[0], 1, "eap_sim_parse_encr;eap_aka_process_reauthentication"):
+        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
+        if ev is None:
+            raise Exception("EAP re-authentication did not start")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].dump_monitor()
+
+    tests = [ (1, "eap_sim_verify_mac_sha256"),
+              (1, "=eap_aka_process_challenge") ]
+    for count, func in tests:
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="AKA'", identity="6555444333222111",
+                           password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
+                           erp="1", wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].dump_monitor()
 
-EAP_SIM_AT_RAND = 1
-EAP_SIM_AT_AUTN = 2
-EAP_SIM_AT_RES = 3
-EAP_SIM_AT_AUTS = 4
-EAP_SIM_AT_PADDING = 6
-EAP_SIM_AT_NONCE_MT = 7
-EAP_SIM_AT_PERMANENT_ID_REQ = 10
-EAP_SIM_AT_MAC = 11
-EAP_SIM_AT_NOTIFICATION = 12
-EAP_SIM_AT_ANY_ID_REQ = 13
-EAP_SIM_AT_IDENTITY = 14
-EAP_SIM_AT_VERSION_LIST = 15
-EAP_SIM_AT_SELECTED_VERSION = 16
-EAP_SIM_AT_FULLAUTH_ID_REQ = 17
-EAP_SIM_AT_COUNTER = 19
-EAP_SIM_AT_COUNTER_TOO_SMALL = 20
-EAP_SIM_AT_NONCE_S = 21
-EAP_SIM_AT_CLIENT_ERROR_CODE = 22
-EAP_SIM_AT_KDF_INPUT = 23
-EAP_SIM_AT_KDF = 24
-EAP_SIM_AT_IV = 129
-EAP_SIM_AT_ENCR_DATA = 130
-EAP_SIM_AT_NEXT_PSEUDONYM = 132
-EAP_SIM_AT_NEXT_REAUTH_ID = 133
-EAP_SIM_AT_CHECKCODE = 134
-EAP_SIM_AT_RESULT_IND = 135
-EAP_SIM_AT_BIDDING = 136
+def test_eap_proto_ikev2(dev, apdev):
+    """EAP-IKEv2 protocol tests"""
+    check_eap_capa(dev[0], "IKEV2")
 
-def test_eap_proto_aka(dev, apdev):
-    """EAP-AKA protocol tests"""
-    def aka_handler(ctx, req):
-        logger.info("aka_handler - RX " + req.encode("hex"))
+    global eap_proto_ikev2_test_done
+    eap_proto_ikev2_test_done = False
+
+    def ikev2_handler(ctx, req):
+        logger.info("ikev2_handler - RX " + req.encode("hex"))
         if 'num' not in ctx:
             ctx['num'] = 0
         ctx['num'] = ctx['num'] + 1
@@ -2123,433 +4767,331 @@ def test_eap_proto_aka(dev, apdev):
             logger.info("Test: Missing payload")
             return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1,
-                               EAP_TYPE_AKA)
-
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Unknown subtype")
-            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3,
-                               EAP_TYPE_AKA, 255, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
-
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Client Error")
-            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CLIENT_ERROR, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+                               EAP_TYPE_IKEV2)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Too short attribute header")
-            return struct.pack(">BBHBBHB", EAP_CODE_REQUEST, ctx['id'],
+            logger.info("Test: Truncated Message Length field")
+            return struct.pack(">BBHBB3B", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 1 + 3,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0, 255)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+                               EAP_TYPE_IKEV2, 0x80, 0, 0, 0)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Truncated attribute")
-            return struct.pack(">BBHBBHBB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0, 255,
-                               255)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Too short Message Length value")
+            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 4 + 1,
+                               EAP_TYPE_IKEV2, 0x80, 0, 1)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Too short attribute data")
-            return struct.pack(">BBHBBHBB", EAP_CODE_REQUEST, ctx['id'],
+            logger.info("Test: Truncated message")
+            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 1 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0, 255,
-                               0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
-
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Skippable/non-skippable unrecognzized attribute")
-            return struct.pack(">BBHBBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 10,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               255, 1, 0, 127, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
-
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request without ID type")
-            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request ANY_ID")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request ANY_ID (duplicate)")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
-
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request ANY_ID")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request FULLAUTH_ID")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request FULLAUTH_ID (duplicate)")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+                               EAP_TYPE_IKEV2, 0x80, 1)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Identity request ANY_ID")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request FULLAUTH_ID")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request PERMANENT_ID")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_PERMANENT_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request PERMANENT_ID (duplicate)")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_PERMANENT_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Truncated message(2)")
+            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 4,
+                               EAP_TYPE_IKEV2, 0x80, 0xffffffff)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge with no attributes")
-            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Truncated message(3)")
+            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 4,
+                               EAP_TYPE_IKEV2, 0xc0, 0xffffffff)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: AKA Challenge with BIDDING")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_BIDDING, 1, 0x8000)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Truncated message(4)")
+            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 4,
+                               EAP_TYPE_IKEV2, 0xc0, 10000000)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Notification with no attributes")
-            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Too long fragments (first fragment)")
+            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 4 + 1,
+                               EAP_TYPE_IKEV2, 0xc0, 2, 1)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Notification indicating success, but no MAC")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
-                               EAP_SIM_AT_NOTIFICATION, 1, 32768)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Too long fragments (second fragment)")
+            return struct.pack(">BBHBB2B", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2,
+                               EAP_TYPE_IKEV2, 0x00, 2, 3)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Notification indicating success, but invalid MAC value")
-            return struct.pack(">BBHBBHBBHBBH4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4 + 20,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
-                               EAP_SIM_AT_NOTIFICATION, 1, 32768,
-                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: No Message Length field in first fragment")
+            return struct.pack(">BBHBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 1,
+                               EAP_TYPE_IKEV2, 0x40, 1)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Notification indicating success with zero-key MAC")
-            return struct.pack(">BBHBBHBBHBBH16B", EAP_CODE_REQUEST,
-                               ctx['id'] - 2,
-                               4 + 1 + 3 + 4 + 20,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
-                               EAP_SIM_AT_NOTIFICATION, 1, 32768,
-                               EAP_SIM_AT_MAC, 5, 0,
-                               0xbe, 0x2e, 0xbb, 0xa9, 0xfa, 0x2e, 0x82, 0x36,
-                               0x37, 0x8c, 0x32, 0x41, 0xb7, 0xc7, 0x58, 0xa3)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Success")
-            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
+            logger.info("Test: ICV before keys")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_IKEV2, 0x20)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Notification before auth")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
-                               EAP_SIM_AT_NOTIFICATION, 1, 16384)
+            logger.info("Test: Unsupported IKEv2 header version")
+            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 28,
+                               EAP_TYPE_IKEV2, 0x00,
+                               0, 0, 0, 0,
+                               0, 0, 0, 0, 0, 0)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Incorrect IKEv2 header Length")
+            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 28,
+                               EAP_TYPE_IKEV2, 0x00,
+                               0, 0, 0, 0,
+                               0, 0x20, 0, 0, 0, 0)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Notification before auth")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
-                               EAP_SIM_AT_NOTIFICATION, 1, 16385)
+            logger.info("Test: Unexpected IKEv2 Exchange Type in SA_INIT state")
+            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 28,
+                               EAP_TYPE_IKEV2, 0x00,
+                               0, 0, 0, 0,
+                               0, 0x20, 0, 0, 0, 28)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Unexpected IKEv2 Message ID in SA_INIT state")
+            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 28,
+                               EAP_TYPE_IKEV2, 0x00,
+                               0, 0, 0, 0,
+                               0, 0x20, 34, 0, 1, 28)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Notification with unrecognized non-failure")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
-                               EAP_SIM_AT_NOTIFICATION, 1, 0xc000)
+            logger.info("Test: Unexpected IKEv2 Flags value")
+            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 28,
+                               EAP_TYPE_IKEV2, 0x00,
+                               0, 0, 0, 0,
+                               0, 0x20, 34, 0, 0, 28)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Notification before auth (duplicate)")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
-                               EAP_SIM_AT_NOTIFICATION, 1, 0xc000)
+            logger.info("Test: Unexpected IKEv2 Flags value(2)")
+            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 28,
+                               EAP_TYPE_IKEV2, 0x00,
+                               0, 0, 0, 0,
+                               0, 0x20, 34, 0x20, 0, 28)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: No SAi1 in SA_INIT")
+            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 28,
+                               EAP_TYPE_IKEV2, 0x00,
+                               0, 0, 0, 0,
+                               0, 0x20, 34, 0x08, 0, 28)
+
+        def build_ike(id, next=0, exch_type=34, flags=0x00, ike=''):
+            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, id,
+                               4 + 1 + 1 + 28 + len(ike),
+                               EAP_TYPE_IKEV2, flags,
+                               0, 0, 0, 0,
+                               next, 0x20, exch_type, 0x08, 0,
+                               28 + len(ike)) + ike
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Re-authentication (unexpected) with no attributes")
-            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_REAUTHENTICATION,
-                               0)
+            logger.info("Test: Unexpected extra data after payloads")
+            return build_ike(ctx['id'], ike=struct.pack(">B", 1))
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Truncated payload header")
+            return build_ike(ctx['id'], next=128, ike=struct.pack(">B", 1))
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: AKA Challenge with Checkcode claiming identity round was used")
-            return struct.pack(">BBHBBHBBH5L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 24,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_CHECKCODE, 6, 0, 0, 0, 0, 0, 0)
+            logger.info("Test: Too small payload header length")
+            ike = struct.pack(">BBH", 0, 0, 3)
+            return build_ike(ctx['id'], next=128, ike=ike)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Too large payload header length")
+            ike = struct.pack(">BBH", 0, 0, 5)
+            return build_ike(ctx['id'], next=128, ike=ike)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Identity request ANY_ID")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
+            logger.info("Test: Unsupported payload (non-critical and critical)")
+            ike = struct.pack(">BBHBBH", 129, 0, 4, 0, 0x01, 4)
+            return build_ike(ctx['id'], next=128, ike=ike)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: AKA Challenge with Checkcode claiming no identity round was used")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_CHECKCODE, 1, 0)
+            logger.info("Test: Certificate and empty SAi1")
+            ike = struct.pack(">BBHBBH", 33, 0, 4, 0, 0, 4)
+            return build_ike(ctx['id'], next=37, ike=ike)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Too short proposal")
+            ike = struct.pack(">BBHBBHBBB", 0, 0, 4 + 7,
+                              0, 0, 7, 0, 0, 0)
+            return build_ike(ctx['id'], next=33, ike=ike)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Identity request ANY_ID")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
+            logger.info("Test: Too small proposal length in SAi1")
+            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
+                              0, 0, 7, 0, 0, 0, 0)
+            return build_ike(ctx['id'], next=33, ike=ike)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: AKA Challenge with mismatching Checkcode value")
-            return struct.pack(">BBHBBHBBH5L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 24,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_CHECKCODE, 6, 0, 0, 0, 0, 0, 0)
+            logger.info("Test: Too large proposal length in SAi1")
+            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
+                              0, 0, 9, 0, 0, 0, 0)
+            return build_ike(ctx['id'], next=33, ike=ike)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Unexpected proposal type in SAi1")
+            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
+                              1, 0, 8, 0, 0, 0, 0)
+            return build_ike(ctx['id'], next=33, ike=ike)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Re-authentication (unexpected) with Checkcode claimin identity round was used")
-            return struct.pack(">BBHBBHBBH5L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 24,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_REAUTHENTICATION,
-                               0,
-                               EAP_SIM_AT_CHECKCODE, 6, 0, 0, 0, 0, 0, 0)
+            logger.info("Test: Unexpected Protocol ID in SAi1")
+            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
+                              0, 0, 8, 0, 0, 0, 0)
+            return build_ike(ctx['id'], next=33, ike=ike)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Unexpected proposal number in SAi1")
+            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
+                              0, 0, 8, 0, 1, 0, 0)
+            return build_ike(ctx['id'], next=33, ike=ike)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid AT_RAND length")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_RAND, 1, 0)
+            logger.info("Test: Not enough room for SPI in SAi1")
+            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
+                              0, 0, 8, 1, 1, 1, 0)
+            return build_ike(ctx['id'], next=33, ike=ike)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Unexpected SPI in SAi1")
+            ike = struct.pack(">BBHBBHBBBBB", 0, 0, 4 + 9,
+                              0, 0, 9, 1, 1, 1, 0, 1)
+            return build_ike(ctx['id'], next=33, ike=ike)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid AT_AUTN length")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_AUTN, 1, 0)
+            logger.info("Test: No transforms in SAi1")
+            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
+                              0, 0, 8, 1, 1, 0, 0)
+            return build_ike(ctx['id'], next=33, ike=ike)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Too short transform in SAi1")
+            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
+                              0, 0, 8, 1, 1, 0, 1)
+            return build_ike(ctx['id'], next=33, ike=ike)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unencrypted AT_PADDING")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_PADDING, 1, 0)
+            logger.info("Test: Too small transform length in SAi1")
+            ike = struct.pack(">BBHBBHBBBBBBHBBH", 0, 0, 4 + 8 + 8,
+                              0, 0, 8 + 8, 1, 1, 0, 1,
+                              0, 0, 7, 0, 0, 0)
+            return build_ike(ctx['id'], next=33, ike=ike)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Too large transform length in SAi1")
+            ike = struct.pack(">BBHBBHBBBBBBHBBH", 0, 0, 4 + 8 + 8,
+                              0, 0, 8 + 8, 1, 1, 0, 1,
+                              0, 0, 9, 0, 0, 0)
+            return build_ike(ctx['id'], next=33, ike=ike)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid AT_NONCE_MT length")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_NONCE_MT, 1, 0)
+            logger.info("Test: Unexpected Transform type in SAi1")
+            ike = struct.pack(">BBHBBHBBBBBBHBBH", 0, 0, 4 + 8 + 8,
+                              0, 0, 8 + 8, 1, 1, 0, 1,
+                              1, 0, 8, 0, 0, 0)
+            return build_ike(ctx['id'], next=33, ike=ike)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: No transform attributes in SAi1")
+            ike = struct.pack(">BBHBBHBBBBBBHBBH", 0, 0, 4 + 8 + 8,
+                              0, 0, 8 + 8, 1, 1, 0, 1,
+                              0, 0, 8, 0, 0, 0)
+            return build_ike(ctx['id'], next=33, ike=ike)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid AT_MAC length")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_MAC, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: No transform attr for AES and unexpected data after transforms in SAi1")
+            tlen1 = 8 + 3
+            tlen2 = 8 + 4
+            tlen3 = 8 + 4
+            tlen = tlen1 + tlen2 + tlen3
+            ike = struct.pack(">BBHBBHBBBBBBHBBH3BBBHBBHHHBBHBBHHHB",
+                              0, 0, 4 + 8 + tlen + 1,
+                              0, 0, 8 + tlen + 1, 1, 1, 0, 3,
+                              3, 0, tlen1, 1, 0, 12, 1, 2, 3,
+                              3, 0, tlen2, 1, 0, 12, 0, 128,
+                              0, 0, tlen3, 1, 0, 12, 0x8000 | 14, 127,
+                              1)
+            return build_ike(ctx['id'], next=33, ike=ike)
+
+        def build_sa(next=0):
+            tlen = 5 * 8
+            return struct.pack(">BBHBBHBBBBBBHBBHBBHBBHBBHBBHBBHBBHBBHBBH",
+                               next, 0, 4 + 8 + tlen,
+                               0, 0, 8 + tlen, 1, 1, 0, 5,
+                               3, 0, 8, 1, 0, 3,
+                               3, 0, 8, 2, 0, 1,
+                               3, 0, 8, 3, 0, 1,
+                               3, 0, 8, 4, 0, 5,
+                               0, 0, 8, 241, 0, 0)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid AT_NOTIFICATION length")
-            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_NOTIFICATION, 2, 0, 0)
+            logger.info("Test: Valid proposal, but no KEi in SAi1")
+            ike = build_sa()
+            return build_ike(ctx['id'], next=33, ike=ike)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Empty KEi in SAi1")
+            ike = build_sa(next=34) + struct.pack(">BBH", 0, 0, 4)
+            return build_ike(ctx['id'], next=33, ike=ike)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: AT_IDENTITY overflow")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_IDENTITY, 1, 0xffff)
+            logger.info("Test: Mismatch in DH Group in SAi1")
+            ike = build_sa(next=34)
+            ike += struct.pack(">BBHHH", 0, 0, 4 + 4 + 96, 12345, 0)
+            ike += 96*'\x00'
+            return build_ike(ctx['id'], next=33, ike=ike)
         idx += 1
         if ctx['num'] == idx:
             logger.info("Test: EAP-Failure")
@@ -2557,35 +5099,53 @@ def test_eap_proto_aka(dev, apdev):
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected AT_VERSION_LIST")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_VERSION_LIST, 1, 0)
+            logger.info("Test: Invalid DH public value length in SAi1")
+            ike = build_sa(next=34)
+            ike += struct.pack(">BBHHH", 0, 0, 4 + 4 + 96, 5, 0)
+            ike += 96*'\x00'
+            return build_ike(ctx['id'], next=33, ike=ike)
+
+        def build_ke(next=0):
+            ke = struct.pack(">BBHHH", next, 0, 4 + 4 + 192, 5, 0)
+            ke += 192*'\x00'
+            return ke
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Valid proposal and KEi, but no Ni in SAi1")
+            ike = build_sa(next=34)
+            ike += build_ke()
+            return build_ike(ctx['id'], next=33, ike=ike)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid AT_SELECTED_VERSION length")
-            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_SELECTED_VERSION, 2, 0, 0)
+            logger.info("Test: Too short Ni in SAi1")
+            ike = build_sa(next=34)
+            ike += build_ke(next=40)
+            ike += struct.pack(">BBH", 0, 0, 4)
+            return build_ike(ctx['id'], next=33, ike=ike)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Too long Ni in SAi1")
+            ike = build_sa(next=34)
+            ike += build_ke(next=40)
+            ike += struct.pack(">BBH", 0, 0, 4 + 257) + 257*'\x00'
+            return build_ike(ctx['id'], next=33, ike=ike)
+
+        def build_ni(next=0):
+            return struct.pack(">BBH", next, 0, 4 + 256) + 256*'\x00'
+
+        def build_sai1(id):
+            ike = build_sa(next=34)
+            ike += build_ke(next=40)
+            ike += build_ni()
+            return build_ike(ctx['id'], next=33, ike=ike)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unencrypted AT_COUNTER")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_COUNTER, 1, 0)
+            logger.info("Test: Valid proposal, KEi, and Ni in SAi1")
+            return build_sai1(ctx['id'])
         idx += 1
         if ctx['num'] == idx:
             logger.info("Test: EAP-Failure")
@@ -2593,828 +5153,1934 @@ def test_eap_proto_aka(dev, apdev):
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unencrypted AT_COUNTER_TOO_SMALL")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_COUNTER_TOO_SMALL, 1, 0)
+            logger.info("Test: Valid proposal, KEi, and Ni in SAi1")
+            return build_sai1(ctx['id'])
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: No integrity checksum")
+            ike = ''
+            return build_ike(ctx['id'], next=37, ike=ike)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unencrypted AT_NONCE_S")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_NONCE_S, 1, 0)
+            logger.info("Test: Valid proposal, KEi, and Ni in SAi1")
+            return build_sai1(ctx['id'])
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Truncated integrity checksum")
+            return struct.pack(">BBHBB",
+                               EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_IKEV2, 0x20)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid AT_CLIENT_ERROR_CODE length")
-            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_CLIENT_ERROR_CODE, 2, 0, 0)
+            logger.info("Test: Valid proposal, KEi, and Ni in SAi1")
+            return build_sai1(ctx['id'])
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Invalid integrity checksum")
+            ike = ''
+            return build_ike(ctx['id'], next=37, flags=0x20, ike=ike)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid AT_IV length")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_IV, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("No more test responses available - test case completed")
+            global eap_proto_ikev2_test_done
+            eap_proto_ikev2_test_done = True
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1,
+                               EAP_TYPE_IKEV2)
+        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+    srv = start_radius_server(ikev2_handler)
+
+    try:
+        hapd = start_ap(apdev[0])
+
+        i = 0
+        while not eap_proto_ikev2_test_done:
+            i += 1
+            logger.info("Running connection iteration %d" % i)
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="IKEV2", identity="user",
+                           password="password",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP method start")
+            if i in [ 41, 46 ]:
+                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
+                                       timeout=10)
+                if ev is None:
+                    raise Exception("Timeout on EAP failure")
+            else:
+                time.sleep(0.05)
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+            dev[0].dump_monitor()
+            dev[1].dump_monitor()
+            dev[2].dump_monitor()
+    finally:
+        stop_radius_server(srv)
+
+def NtPasswordHash(password):
+    pw = password.encode('utf_16_le')
+    return hashlib.new('md4', pw).digest()
+
+def HashNtPasswordHash(password_hash):
+    return hashlib.new('md4', password_hash).digest()
+
+def ChallengeHash(peer_challenge, auth_challenge, username):
+    data = peer_challenge + auth_challenge + username
+    return hashlib.sha1(data).digest()[0:8]
+
+def GenerateAuthenticatorResponse(password, nt_response, peer_challenge,
+                                  auth_challenge, username):
+    magic1 = binascii.unhexlify("4D616769632073657276657220746F20636C69656E74207369676E696E6720636F6E7374616E74")
+    magic2 = binascii.unhexlify("50616420746F206D616B6520697420646F206D6F7265207468616E206F6E6520697465726174696F6E")
+
+    password_hash = NtPasswordHash(password)
+    password_hash_hash = HashNtPasswordHash(password_hash)
+    data = password_hash_hash + nt_response + magic1
+    digest = hashlib.sha1(data).digest()
+
+    challenge = ChallengeHash(peer_challenge, auth_challenge, username)
+
+    data = digest + challenge + magic2
+    resp = hashlib.sha1(data).digest()
+    return resp
+
+def test_eap_proto_ikev2_errors(dev, apdev):
+    """EAP-IKEv2 local error cases"""
+    check_eap_capa(dev[0], "IKEV2")
+    params = hostapd.wpa2_eap_params(ssid="eap-test")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    for i in range(1, 5):
+        with alloc_fail(dev[0], i, "eap_ikev2_init"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="IKEV2", identity="ikev2 user",
+                           password="ike password",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "ikev2_encr_encrypt"),
+              (1, "ikev2_encr_decrypt"),
+              (1, "ikev2_derive_auth_data"),
+              (2, "ikev2_derive_auth_data"),
+              (1, "=ikev2_decrypt_payload"),
+              (1, "ikev2_encr_decrypt;ikev2_decrypt_payload"),
+              (1, "ikev2_encr_encrypt;ikev2_build_encrypted"),
+              (1, "ikev2_derive_sk_keys"),
+              (2, "ikev2_derive_sk_keys"),
+              (3, "ikev2_derive_sk_keys"),
+              (4, "ikev2_derive_sk_keys"),
+              (5, "ikev2_derive_sk_keys"),
+              (6, "ikev2_derive_sk_keys"),
+              (7, "ikev2_derive_sk_keys"),
+              (8, "ikev2_derive_sk_keys"),
+              (1, "eap_ikev2_derive_keymat;eap_ikev2_peer_keymat"),
+              (1, "eap_msg_alloc;eap_ikev2_build_msg"),
+              (1, "eap_ikev2_getKey"),
+              (1, "eap_ikev2_get_emsk"),
+              (1, "eap_ikev2_get_session_id"),
+              (1, "=ikev2_derive_keys"),
+              (2, "=ikev2_derive_keys"),
+              (1, "wpabuf_alloc;ikev2_process_kei"),
+              (1, "=ikev2_process_idi"),
+              (1, "ikev2_derive_auth_data;ikev2_build_auth"),
+              (1, "wpabuf_alloc;ikev2_build_sa_init"),
+              (2, "wpabuf_alloc;ikev2_build_sa_init"),
+              (3, "wpabuf_alloc;ikev2_build_sa_init"),
+              (4, "wpabuf_alloc;ikev2_build_sa_init"),
+              (5, "wpabuf_alloc;ikev2_build_sa_init"),
+              (6, "wpabuf_alloc;ikev2_build_sa_init"),
+              (1, "wpabuf_alloc;ikev2_build_sa_auth"),
+              (2, "wpabuf_alloc;ikev2_build_sa_auth"),
+              (1, "ikev2_build_auth;ikev2_build_sa_auth") ]
+    for count, func in tests:
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="IKEV2", identity="ikev2 user",
+                           password="ike password", erp="1", wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            ok = False
+            for j in range(10):
+                state = dev[0].request('GET_ALLOC_FAIL')
+                if state.startswith('0:'):
+                    ok = True
+                    break
+                time.sleep(0.1)
+            if not ok:
+                raise Exception("No allocation failure seen for %d:%s" % (count, func))
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "wpabuf_alloc;ikev2_build_notify"),
+              (2, "wpabuf_alloc;ikev2_build_notify"),
+              (1, "ikev2_build_encrypted;ikev2_build_notify") ]
+    for count, func in tests:
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="IKEV2", identity="ikev2 user",
+                           password="wrong password", erp="1",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            ok = False
+            for j in range(10):
+                state = dev[0].request('GET_ALLOC_FAIL')
+                if state.startswith('0:'):
+                    ok = True
+                    break
+                time.sleep(0.1)
+            if not ok:
+                raise Exception("No allocation failure seen for %d:%s" % (count, func))
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "ikev2_integ_hash"),
+              (1, "ikev2_integ_hash;ikev2_decrypt_payload"),
+              (1, "os_get_random;ikev2_build_encrypted"),
+              (1, "ikev2_prf_plus;ikev2_derive_sk_keys"),
+              (1, "eap_ikev2_derive_keymat;eap_ikev2_peer_keymat"),
+              (1, "os_get_random;ikev2_build_sa_init"),
+              (2, "os_get_random;ikev2_build_sa_init"),
+              (1, "ikev2_integ_hash;eap_ikev2_validate_icv"),
+              (1, "hmac_sha1_vector;?ikev2_prf_hash;ikev2_derive_keys"),
+              (1, "hmac_sha1_vector;?ikev2_prf_hash;ikev2_derive_auth_data"),
+              (2, "hmac_sha1_vector;?ikev2_prf_hash;ikev2_derive_auth_data"),
+              (3, "hmac_sha1_vector;?ikev2_prf_hash;ikev2_derive_auth_data") ]
+    for count, func in tests:
+        with fail_test(dev[0], count, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="IKEV2", identity="ikev2 user",
+                           password="ike password", wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            ok = False
+            for j in range(10):
+                state = dev[0].request('GET_FAIL')
+                if state.startswith('0:'):
+                    ok = True
+                    break
+                time.sleep(0.1)
+            if not ok:
+                raise Exception("No failure seen for %d:%s" % (count, func))
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    params = { "ssid": "eap-test2", "wpa": "2", "wpa_key_mgmt": "WPA-EAP",
+               "rsn_pairwise": "CCMP", "ieee8021x": "1",
+               "eap_server": "1", "eap_user_file": "auth_serv/eap_user.conf",
+               "fragment_size": "50" }
+    hostapd.add_ap(apdev[1], params)
+
+    tests = [ (1, "eap_ikev2_build_frag_ack"),
+              (1, "wpabuf_alloc;eap_ikev2_process_fragment") ]
+    for count, func in tests:
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("eap-test2", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="IKEV2", identity="ikev2 user",
+                           password="ike password", erp="1", wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            ok = False
+            for j in range(10):
+                state = dev[0].request('GET_ALLOC_FAIL')
+                if state.startswith('0:'):
+                    ok = True
+                    break
+                time.sleep(0.1)
+            if not ok:
+                raise Exception("No allocation failure seen for %d:%s" % (count, func))
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+def test_eap_proto_mschapv2(dev, apdev):
+    """EAP-MSCHAPv2 protocol tests"""
+    check_eap_capa(dev[0], "MSCHAPV2")
+
+    def mschapv2_handler(ctx, req):
+        logger.info("mschapv2_handler - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] = ctx['num'] + 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+        idx = 0
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid AT_ENCR_DATA length")
-            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_ENCR_DATA, 2, 0, 0)
+            logger.info("Test: Missing payload")
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1,
+                               EAP_TYPE_MSCHAPV2)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Unknown MSCHAPv2 op_code")
+            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + 1,
+                               EAP_TYPE_MSCHAPV2,
+                               0, 0, 5, 0)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unencrypted AT_NEXT_PSEUDONYM")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_NEXT_PSEUDONYM, 1, 0)
+            logger.info("Test: Invalid ms_len and unknown MSCHAPv2 op_code")
+            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + 1,
+                               EAP_TYPE_MSCHAPV2,
+                               255, 0, 0, 0)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Success before challenge")
+            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + 1,
+                               EAP_TYPE_MSCHAPV2,
+                               3, 0, 5, 0)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unencrypted AT_NEXT_REAUTH_ID")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_NEXT_REAUTH_ID, 1, 0)
+            logger.info("Test: Failure before challenge - required challenge field not present")
+            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + 1,
+                               EAP_TYPE_MSCHAPV2,
+                               4, 0, 5, 0)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
+            logger.info("Test: Failure")
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid AT_RES length")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_RES, 1, 0)
+            logger.info("Test: Failure before challenge - invalid failure challenge len")
+            payload = 'C=12'
+            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + len(payload),
+                               EAP_TYPE_MSCHAPV2,
+                               4, 0, 4 + len(payload)) + payload
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
+            logger.info("Test: Failure")
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid AT_RES length")
-            return struct.pack(">BBHBBHBBH5L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 24,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_RES, 6, 0xffff, 0, 0, 0, 0, 0)
+            logger.info("Test: Failure before challenge - invalid failure challenge len")
+            payload = 'C=12 V=3'
+            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + len(payload),
+                               EAP_TYPE_MSCHAPV2,
+                               4, 0, 4 + len(payload)) + payload
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
+            logger.info("Test: Failure")
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid AT_AUTS length")
-            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_AUTS, 2, 0, 0)
+            logger.info("Test: Failure before challenge - invalid failure challenge")
+            payload = 'C=00112233445566778899aabbccddeefQ '
+            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + len(payload),
+                               EAP_TYPE_MSCHAPV2,
+                               4, 0, 4 + len(payload)) + payload
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
+            logger.info("Test: Failure")
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid AT_CHECKCODE length")
-            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_CHECKCODE, 2, 0, 0)
+            logger.info("Test: Failure before challenge - password expired")
+            payload = 'E=648 R=1 C=00112233445566778899aabbccddeeff V=3 M=Password expired'
+            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + len(payload),
+                               EAP_TYPE_MSCHAPV2,
+                               4, 0, 4 + len(payload)) + payload
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Success after password change")
+            payload = "S=1122334455667788990011223344556677889900"
+            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + len(payload),
+                               EAP_TYPE_MSCHAPV2,
+                               3, 0, 4 + len(payload)) + payload
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid AT_RESULT_IND length")
-            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_RESULT_IND, 2, 0, 0)
+            logger.info("Test: Invalid challenge length")
+            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + 1,
+                               EAP_TYPE_MSCHAPV2,
+                               1, 0, 4 + 1, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Too short challenge packet")
+            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + 1,
+                               EAP_TYPE_MSCHAPV2,
+                               1, 0, 4 + 1, 16)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Challenge")
+            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + 1 + 16 + 6,
+                               EAP_TYPE_MSCHAPV2,
+                               1, 0, 4 + 1 + 16 + 6, 16) + 16*'A' + 'foobar'
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Failure - password expired")
+            payload = 'E=648 R=1 C=00112233445566778899aabbccddeeff V=3 M=Password expired'
+            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + len(payload),
+                               EAP_TYPE_MSCHAPV2,
+                               4, 0, 4 + len(payload)) + payload
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Success after password change")
+            if len(req) != 591:
+                logger.info("Unexpected Change-Password packet length: %s" % len(req))
+                return None
+            data = req[9:]
+            enc_pw = data[0:516]
+            data = data[516:]
+            enc_hash = data[0:16]
+            data = data[16:]
+            peer_challenge = data[0:16]
+            data = data[16:]
+            # Reserved
+            data = data[8:]
+            nt_response = data[0:24]
+            data = data[24:]
+            flags = data
+            logger.info("enc_hash: " + enc_hash.encode("hex"))
+            logger.info("peer_challenge: " + peer_challenge.encode("hex"))
+            logger.info("nt_response: " + nt_response.encode("hex"))
+            logger.info("flags: " + flags.encode("hex"))
+
+            auth_challenge = binascii.unhexlify("00112233445566778899aabbccddeeff")
+            logger.info("auth_challenge: " + auth_challenge.encode("hex"))
+            auth_resp = GenerateAuthenticatorResponse("new-pw", nt_response,
+                                                      peer_challenge,
+                                                      auth_challenge, "user")
+            payload = "S=" + auth_resp.encode('hex').upper()
+            logger.info("Success message payload: " + payload)
+            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + len(payload),
+                               EAP_TYPE_MSCHAPV2,
+                               3, 0, 4 + len(payload)) + payload
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: EAP-Success")
+            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected AT_KDF_INPUT")
-            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_KDF_INPUT, 2, 0, 0)
+            logger.info("Test: Failure - password expired")
+            payload = 'E=648 R=1 C=00112233445566778899aabbccddeeff V=3 M=Password expired'
+            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + len(payload),
+                               EAP_TYPE_MSCHAPV2,
+                               4, 0, 4 + len(payload)) + payload
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Success after password change")
+            if len(req) != 591:
+                logger.info("Unexpected Change-Password packet length: %s" % len(req))
+                return None
+            data = req[9:]
+            enc_pw = data[0:516]
+            data = data[516:]
+            enc_hash = data[0:16]
+            data = data[16:]
+            peer_challenge = data[0:16]
+            data = data[16:]
+            # Reserved
+            data = data[8:]
+            nt_response = data[0:24]
+            data = data[24:]
+            flags = data
+            logger.info("enc_hash: " + enc_hash.encode("hex"))
+            logger.info("peer_challenge: " + peer_challenge.encode("hex"))
+            logger.info("nt_response: " + nt_response.encode("hex"))
+            logger.info("flags: " + flags.encode("hex"))
+
+            auth_challenge = binascii.unhexlify("00112233445566778899aabbccddeeff")
+            logger.info("auth_challenge: " + auth_challenge.encode("hex"))
+            auth_resp = GenerateAuthenticatorResponse("new-pw", nt_response,
+                                                      peer_challenge,
+                                                      auth_challenge, "user")
+            payload = "S=" + auth_resp.encode('hex').upper()
+            logger.info("Success message payload: " + payload)
+            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + len(payload),
+                               EAP_TYPE_MSCHAPV2,
+                               3, 0, 4 + len(payload)) + payload
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: EAP-Success")
+            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected AT_KDF")
-            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_KDF, 2, 0, 0)
+            logger.info("Test: Challenge")
+            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + 1 + 16 + 6,
+                               EAP_TYPE_MSCHAPV2,
+                               1, 0, 4 + 1 + 16 + 6, 16) + 16*'A' + 'foobar'
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Failure - authentication failure")
+            payload = 'E=691 R=1 C=00112233445566778899aabbccddeeff V=3 M=Authentication failed'
+            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + len(payload),
+                               EAP_TYPE_MSCHAPV2,
+                               4, 0, 4 + len(payload)) + payload
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid AT_BIDDING length")
-            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_BIDDING, 2, 0, 0)
+            logger.info("Test: Challenge")
+            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + 1 + 16 + 6,
+                               EAP_TYPE_MSCHAPV2,
+                               1, 0, 4 + 1 + 16 + 6, 16) + 16*'A' + 'foobar'
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
+            logger.info("Test: Failure - authentication failure")
+            payload = 'E=691 R=1 C=00112233445566778899aabbccddeeff V=3 M=Authentication failed (2)'
+            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + len(payload),
+                               EAP_TYPE_MSCHAPV2,
+                               4, 0, 4 + len(payload)) + payload
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Failure")
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Challenge - invalid ms_len and workaround disabled")
+            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + 1 + 16 + 6,
+                               EAP_TYPE_MSCHAPV2,
+                               1, 0, 4 + 1 + 16 + 6 + 1, 16) + 16*'A' + 'foobar'
+
         return None
 
-    srv = start_radius_server(aka_handler)
+    srv = start_radius_server(mschapv2_handler)
 
     try:
-        hapd = start_ap(apdev[0]['ifname'])
+        hapd = start_ap(apdev[0])
 
-        for i in range(0, 49):
-            eap = "AKA AKA'" if i == 11 else "AKA"
-            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
-                           eap=eap, identity="0232010000000000",
-                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
-                           wait_connect=False)
-            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
-                                   timeout=15)
+        for i in range(0, 16):
+            logger.info("RUN: %d" % i)
+            if i == 12:
+                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                               eap="MSCHAPV2", identity="user",
+                               password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
+                               wait_connect=False)
+            elif i == 14:
+                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                               eap="MSCHAPV2", identity="user",
+                               phase2="mschapv2_retry=0",
+                               password="password", wait_connect=False)
+            elif i == 15:
+                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                               eap="MSCHAPV2", identity="user",
+                               eap_workaround="0",
+                               password="password", wait_connect=False)
+            else:
+                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                               eap="MSCHAPV2", identity="user",
+                               password="password", wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
             if ev is None:
                 raise Exception("Timeout on EAP start")
-            if i in [ 0, 15 ]:
-                time.sleep(0.1)
-            else:
+
+            if i in [ 8, 11, 12 ]:
+                ev = dev[0].wait_event(["CTRL-REQ-NEW_PASSWORD"],
+                                       timeout=10)
+                if ev is None:
+                    raise Exception("Timeout on new password request")
+                id = ev.split(':')[0].split('-')[-1]
+                dev[0].request("CTRL-RSP-NEW_PASSWORD-" + id + ":new-pw")
+                if i in [ 11, 12 ]:
+                    ev = dev[0].wait_event(["CTRL-EVENT-PASSWORD-CHANGED"],
+                                       timeout=10)
+                    if ev is None:
+                        raise Exception("Timeout on password change")
+                    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"],
+                                       timeout=10)
+                    if ev is None:
+                        raise Exception("Timeout on EAP success")
+                else:
+                    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
+                                           timeout=10)
+                    if ev is None:
+                        raise Exception("Timeout on EAP failure")
+
+            if i in [ 13 ]:
+                ev = dev[0].wait_event(["CTRL-REQ-IDENTITY"],
+                                       timeout=10)
+                if ev is None:
+                    raise Exception("Timeout on identity request")
+                id = ev.split(':')[0].split('-')[-1]
+                dev[0].request("CTRL-RSP-IDENTITY-" + id + ":user")
+
+                ev = dev[0].wait_event(["CTRL-REQ-PASSWORD"],
+                                       timeout=10)
+                if ev is None:
+                    raise Exception("Timeout on password request")
+                id = ev.split(':')[0].split('-')[-1]
+                dev[0].request("CTRL-RSP-PASSWORD-" + id + ":password")
+
+                # TODO: Does this work correctly?
+
+                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
+                                       timeout=10)
+                if ev is None:
+                    raise Exception("Timeout on EAP failure")
+
+            if i in [ 4, 5, 6, 7, 14 ]:
                 ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
                                        timeout=10)
                 if ev is None:
                     raise Exception("Timeout on EAP failure")
+            else:
+                time.sleep(0.05)
             dev[0].request("REMOVE_NETWORK all")
-            dev[0].dump_monitor()
+            dev[0].wait_disconnected(timeout=1)
     finally:
         stop_radius_server(srv)
 
-def test_eap_proto_aka_prime(dev, apdev):
-    """EAP-AKA' protocol tests"""
-    def aka_prime_handler(ctx, req):
-        logger.info("aka_prime_handler - RX " + req.encode("hex"))
+def test_eap_proto_mschapv2_errors(dev, apdev):
+    """EAP-MSCHAPv2 protocol tests (error paths)"""
+    check_eap_capa(dev[0], "MSCHAPV2")
+
+    def mschapv2_fail_password_expired(ctx):
+        logger.info("Test: Failure before challenge - password expired")
+        payload = 'E=648 R=1 C=00112233445566778899aabbccddeeff V=3 M=Password expired'
+        return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
+                           4 + 1 + 4 + len(payload),
+                           EAP_TYPE_MSCHAPV2,
+                           4, 0, 4 + len(payload)) + payload
+
+    def mschapv2_success_after_password_change(ctx, req=None):
+        logger.info("Test: Success after password change")
+        if req is None or len(req) != 591:
+            payload = "S=1122334455667788990011223344556677889900"
+        else:
+            data = req[9:]
+            enc_pw = data[0:516]
+            data = data[516:]
+            enc_hash = data[0:16]
+            data = data[16:]
+            peer_challenge = data[0:16]
+            data = data[16:]
+            # Reserved
+            data = data[8:]
+            nt_response = data[0:24]
+            data = data[24:]
+            flags = data
+            logger.info("enc_hash: " + enc_hash.encode("hex"))
+            logger.info("peer_challenge: " + peer_challenge.encode("hex"))
+            logger.info("nt_response: " + nt_response.encode("hex"))
+            logger.info("flags: " + flags.encode("hex"))
+
+            auth_challenge = binascii.unhexlify("00112233445566778899aabbccddeeff")
+            logger.info("auth_challenge: " + auth_challenge.encode("hex"))
+
+            auth_resp = GenerateAuthenticatorResponse("new-pw", nt_response,
+                                                      peer_challenge,
+                                                      auth_challenge, "user")
+            payload = "S=" + auth_resp.encode('hex').upper()
+        return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
+                           4 + 1 + 4 + len(payload),
+                           EAP_TYPE_MSCHAPV2,
+                           3, 0, 4 + len(payload)) + payload
+
+    def mschapv2_handler(ctx, req):
+        logger.info("mschapv2_handler - RX " + req.encode("hex"))
         if 'num' not in ctx:
             ctx['num'] = 0
         ctx['num'] = ctx['num'] + 1
         if 'id' not in ctx:
             ctx['id'] = 1
         ctx['id'] = (ctx['id'] + 1) % 256
-
         idx = 0
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Missing payload")
-            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1,
-                               EAP_TYPE_AKA_PRIME)
+            return mschapv2_fail_password_expired(ctx)
+        idx += 1
+        if ctx['num'] == idx:
+            return mschapv2_success_after_password_change(ctx, req)
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge with no attributes")
-            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0)
+            return mschapv2_fail_password_expired(ctx)
+        idx += 1
+        if ctx['num'] == idx:
+            return mschapv2_success_after_password_change(ctx, req)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge with empty AT_KDF_INPUT")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_KDF_INPUT, 1, 0)
+            return mschapv2_fail_password_expired(ctx)
+        idx += 1
+        if ctx['num'] == idx:
+            return mschapv2_success_after_password_change(ctx, req)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge with AT_KDF_INPUT")
-            return struct.pack(">BBHBBHBBHBBBB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
-                               ord('c'), ord('d'))
+            return mschapv2_fail_password_expired(ctx)
+        idx += 1
+        if ctx['num'] == idx:
+            return mschapv2_success_after_password_change(ctx, req)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge with duplicated KDF")
-            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 3 * 4,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
-                               ord('c'), ord('d'),
-                               EAP_SIM_AT_KDF, 1, 1,
-                               EAP_SIM_AT_KDF, 1, 2,
-                               EAP_SIM_AT_KDF, 1, 1)
+            return mschapv2_fail_password_expired(ctx)
+        idx += 1
+        if ctx['num'] == idx:
+            return mschapv2_success_after_password_change(ctx, req)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge with multiple KDF proposals")
-            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 3 * 4,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
-                               ord('c'), ord('d'),
-                               EAP_SIM_AT_KDF, 1, 255,
-                               EAP_SIM_AT_KDF, 1, 254,
-                               EAP_SIM_AT_KDF, 1, 1)
+            return mschapv2_fail_password_expired(ctx)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge with incorrect KDF selected")
-            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBHBBH",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 4 * 4,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
-                               ord('c'), ord('d'),
-                               EAP_SIM_AT_KDF, 1, 255,
-                               EAP_SIM_AT_KDF, 1, 255,
-                               EAP_SIM_AT_KDF, 1, 254,
-                               EAP_SIM_AT_KDF, 1, 1)
+            return mschapv2_success_after_password_change(ctx, req)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge with multiple KDF proposals")
-            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 3 * 4,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
-                               ord('c'), ord('d'),
-                               EAP_SIM_AT_KDF, 1, 255,
-                               EAP_SIM_AT_KDF, 1, 254,
-                               EAP_SIM_AT_KDF, 1, 1)
+            return mschapv2_fail_password_expired(ctx)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge with selected KDF not duplicated")
-            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 3 * 4,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
-                               ord('c'), ord('d'),
-                               EAP_SIM_AT_KDF, 1, 1,
-                               EAP_SIM_AT_KDF, 1, 255,
-                               EAP_SIM_AT_KDF, 1, 254)
+            return mschapv2_success_after_password_change(ctx, req)
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            return mschapv2_fail_password_expired(ctx)
+        idx += 1
+        if ctx['num'] == idx:
+            return mschapv2_success_after_password_change(ctx, req)
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            return mschapv2_fail_password_expired(ctx)
+        idx += 1
+        if ctx['num'] == idx:
+            return mschapv2_success_after_password_change(ctx, req)
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        return None
+
+    srv = start_radius_server(mschapv2_handler)
+
+    try:
+        hapd = start_ap(apdev[0])
+
+        tests = [ "os_get_random;eap_mschapv2_change_password",
+                  "generate_nt_response;eap_mschapv2_change_password",
+                  "get_master_key;eap_mschapv2_change_password",
+                  "nt_password_hash;eap_mschapv2_change_password",
+                  "old_nt_password_hash_encrypted_with_new_nt_password_hash" ]
+        for func in tests:
+            with fail_test(dev[0], 1, func):
+                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                               eap="MSCHAPV2", identity="user",
+                               password="password", wait_connect=False)
+                ev = dev[0].wait_event(["CTRL-REQ-NEW_PASSWORD"], timeout=10)
+                if ev is None:
+                    raise Exception("Timeout on new password request")
+                id = ev.split(':')[0].split('-')[-1]
+                dev[0].request("CTRL-RSP-NEW_PASSWORD-" + id + ":new-pw")
+                time.sleep(0.1)
+                wait_fail_trigger(dev[0], "GET_FAIL")
+                dev[0].request("REMOVE_NETWORK all")
+                dev[0].wait_disconnected(timeout=1)
+
+        tests = [ "encrypt_pw_block_with_password_hash;eap_mschapv2_change_password",
+                  "nt_password_hash;eap_mschapv2_change_password",
+                  "nt_password_hash;eap_mschapv2_success" ]
+        for func in tests:
+            with fail_test(dev[0], 1, func):
+                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                               eap="MSCHAPV2", identity="user",
+                               password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
+                               wait_connect=False)
+                ev = dev[0].wait_event(["CTRL-REQ-NEW_PASSWORD"], timeout=10)
+                if ev is None:
+                    raise Exception("Timeout on new password request")
+                id = ev.split(':')[0].split('-')[-1]
+                dev[0].request("CTRL-RSP-NEW_PASSWORD-" + id + ":new-pw")
+                time.sleep(0.1)
+                wait_fail_trigger(dev[0], "GET_FAIL")
+                dev[0].request("REMOVE_NETWORK all")
+                dev[0].wait_disconnected(timeout=1)
+
+        tests = [ "eap_msg_alloc;eap_mschapv2_change_password" ]
+        for func in tests:
+            with alloc_fail(dev[0], 1, func):
+                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                               eap="MSCHAPV2", identity="user",
+                               password="password", wait_connect=False)
+                ev = dev[0].wait_event(["CTRL-REQ-NEW_PASSWORD"], timeout=10)
+                if ev is None:
+                    raise Exception("Timeout on new password request")
+                id = ev.split(':')[0].split('-')[-1]
+                dev[0].request("CTRL-RSP-NEW_PASSWORD-" + id + ":new-pw")
+                time.sleep(0.1)
+                wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+                dev[0].request("REMOVE_NETWORK all")
+                dev[0].wait_disconnected(timeout=1)
+    finally:
+        stop_radius_server(srv)
+
+def test_eap_proto_pwd(dev, apdev):
+    """EAP-pwd protocol tests"""
+    check_eap_capa(dev[0], "PWD")
+
+    global eap_proto_pwd_test_done, eap_proto_pwd_test_wait
+    eap_proto_pwd_test_done = False
+    eap_proto_pwd_test_wait = False
+
+    def pwd_handler(ctx, req):
+        logger.info("pwd_handler - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] = ctx['num'] + 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+        idx = 0
+
+        global eap_proto_pwd_test_wait
+        eap_proto_pwd_test_wait = False
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Missing payload")
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'], 4 + 1,
+                               EAP_TYPE_PWD)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Missing Total-Length field")
+            payload = struct.pack("B", 0x80)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge with multiple KDF proposals")
-            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 3 * 4,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
-                               ord('c'), ord('d'),
-                               EAP_SIM_AT_KDF, 1, 255,
-                               EAP_SIM_AT_KDF, 1, 254,
-                               EAP_SIM_AT_KDF, 1, 1)
+            logger.info("Test: Too large Total-Length")
+            payload = struct.pack(">BH", 0x80, 65535)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge with selected KDF duplicated (missing MAC, RAND, AUTN)")
-            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBHBBH",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 4 * 4,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
-                               ord('c'), ord('d'),
-                               EAP_SIM_AT_KDF, 1, 1,
-                               EAP_SIM_AT_KDF, 1, 255,
-                               EAP_SIM_AT_KDF, 1, 254,
-                               EAP_SIM_AT_KDF, 1, 1)
+            eap_proto_pwd_test_wait = True
+            logger.info("Test: First fragment")
+            payload = struct.pack(">BH", 0xc0, 10)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Unexpected Total-Length value in the second fragment")
+            payload = struct.pack(">BH", 0x80, 0)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge with multiple unsupported KDF proposals")
-            return struct.pack(">BBHBBHBBHBBBBBBHBBH",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 2 * 4,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
-                               ord('c'), ord('d'),
-                               EAP_SIM_AT_KDF, 1, 255,
-                               EAP_SIM_AT_KDF, 1, 254)
+            logger.info("Test: First and only fragment")
+            payload = struct.pack(">BH", 0x80, 0)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: First and only fragment with extra data")
+            payload = struct.pack(">BHB", 0x80, 0, 0)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge with multiple KDF proposals")
-            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 3 * 4,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
-                               ord('c'), ord('d'),
-                               EAP_SIM_AT_KDF, 1, 255,
-                               EAP_SIM_AT_KDF, 1, 254,
-                               EAP_SIM_AT_KDF, 1, 1)
+            eap_proto_pwd_test_wait = True
+            logger.info("Test: First fragment")
+            payload = struct.pack(">BHB", 0xc0, 2, 1)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge with invalid MAC, RAND, AUTN values)")
-            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBHBBHBBH4LBBH4LBBH4L",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 4 * 4 + 20 + 20 + 20,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
-                               ord('c'), ord('d'),
-                               EAP_SIM_AT_KDF, 1, 1,
-                               EAP_SIM_AT_KDF, 1, 255,
-                               EAP_SIM_AT_KDF, 1, 254,
-                               EAP_SIM_AT_KDF, 1, 1,
-                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0,
-                               EAP_SIM_AT_RAND, 5, 0, 0, 0, 0, 0,
-                               EAP_SIM_AT_AUTN, 5, 0, 0, 0, 0, 0)
+            logger.info("Test: Extra data in the second fragment")
+            payload = struct.pack(">BBB", 0x0, 2, 3)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Too short id exchange")
+            payload = struct.pack(">B", 0x01)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge - AMF separation bit not set)")
-            return struct.pack(">BBHBBHBBHBBBBBBHBBH4LBBH4LBBH4L",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 4 + 20 + 20 + 20,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
-                               ord('c'), ord('d'),
-                               EAP_SIM_AT_KDF, 1, 1,
-                               EAP_SIM_AT_MAC, 5, 0, 1, 2, 3, 4,
-                               EAP_SIM_AT_RAND, 5, 0, 5, 6, 7, 8,
-                               EAP_SIM_AT_AUTN, 5, 0, 9, 10,
-                               0x2fda8ef7, 0xbba518cc)
+            logger.info("Test: Unsupported rand func in id exchange")
+            payload = struct.pack(">BHBBLB", 0x01, 0, 0, 0, 0, 0)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Unsupported prf in id exchange")
+            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 0, 0, 0)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge - Invalid MAC")
-            return struct.pack(">BBHBBHBBHBBBBBBHBBH4LBBH4LBBH4L",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 4 + 20 + 20 + 20,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
-                               ord('c'), ord('d'),
-                               EAP_SIM_AT_KDF, 1, 1,
-                               EAP_SIM_AT_MAC, 5, 0, 1, 2, 3, 4,
-                               EAP_SIM_AT_RAND, 5, 0, 5, 6, 7, 8,
-                               EAP_SIM_AT_AUTN, 5, 0, 0xffffffff, 0xffffffff,
-                               0xd1f90322, 0x40514cb4)
+            logger.info("Test: Unsupported password pre-processing technique in id exchange")
+            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 255)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            eap_proto_pwd_test_wait = True
+            logger.info("Test: Valid id exchange")
+            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unexpected id exchange")
+            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge - Valid MAC")
-            return struct.pack(">BBHBBHBBHBBBBBBHBBH4LBBH4LBBH4L",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 4 + 20 + 20 + 20,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
-                               ord('c'), ord('d'),
-                               EAP_SIM_AT_KDF, 1, 1,
-                               EAP_SIM_AT_MAC, 5, 0,
-                               0xf4a3c1d3, 0x7c901401, 0x34bd8b01, 0x6f7fa32f,
-                               EAP_SIM_AT_RAND, 5, 0, 5, 6, 7, 8,
-                               EAP_SIM_AT_AUTN, 5, 0, 0xffffffff, 0xffffffff,
-                               0xd1f90322, 0x40514cb4)
+            logger.info("Test: Unexpected commit exchange")
+            payload = struct.pack(">B", 0x02)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            eap_proto_pwd_test_wait = True
+            logger.info("Test: Valid id exchange")
+            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unexpected Commit payload length")
+            payload = struct.pack(">B", 0x02)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid AT_KDF_INPUT length")
-            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_KDF_INPUT, 2, 0xffff, 0)
+            eap_proto_pwd_test_wait = True
+            logger.info("Test: Valid id exchange")
+            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Commit payload with all zeros values --> Shared key at infinity")
+            payload = struct.pack(">B", 0x02) + 96*'\0'
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid AT_KDF length")
-            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_IDENTITY, 0,
-                               EAP_SIM_AT_KDF, 2, 0, 0)
+            eap_proto_pwd_test_wait = True
+            logger.info("Test: Valid id exchange")
+            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            eap_proto_pwd_test_wait = True
+            logger.info("Test: Commit payload with valid values")
+            element = binascii.unhexlify("8dcab2862c5396839a6bac0c689ff03d962863108e7c275bbf1d6eedf634ee832a214db99f0d0a1a6317733eecdd97f0fc4cda19f57e1bb9bb9c8dcf8c60ba6f")
+            scalar = binascii.unhexlify("450f31e058cf2ac2636a5d6e2b3c70b1fcc301957f0716e77f13aa69f9a2e5bd")
+            payload = struct.pack(">B", 0x02) + element + scalar
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unexpected Confirm payload length 0")
+            payload = struct.pack(">B", 0x03)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Challenge with large number of KDF proposals")
-            return struct.pack(">BBHBBHBBHBBHBBHBBHBBHBBHBBHBBHBBHBBHBBHBBH",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 12 * 4,
-                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_KDF, 1, 255,
-                               EAP_SIM_AT_KDF, 1, 254,
-                               EAP_SIM_AT_KDF, 1, 253,
-                               EAP_SIM_AT_KDF, 1, 252,
-                               EAP_SIM_AT_KDF, 1, 251,
-                               EAP_SIM_AT_KDF, 1, 250,
-                               EAP_SIM_AT_KDF, 1, 249,
-                               EAP_SIM_AT_KDF, 1, 248,
-                               EAP_SIM_AT_KDF, 1, 247,
-                               EAP_SIM_AT_KDF, 1, 246,
-                               EAP_SIM_AT_KDF, 1, 245,
-                               EAP_SIM_AT_KDF, 1, 244)
+            eap_proto_pwd_test_wait = True
+            logger.info("Test: Valid id exchange")
+            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            eap_proto_pwd_test_wait = True
+            logger.info("Test: Commit payload with valid values")
+            element = binascii.unhexlify("8dcab2862c5396839a6bac0c689ff03d962863108e7c275bbf1d6eedf634ee832a214db99f0d0a1a6317733eecdd97f0fc4cda19f57e1bb9bb9c8dcf8c60ba6f")
+            scalar = binascii.unhexlify("450f31e058cf2ac2636a5d6e2b3c70b1fcc301957f0716e77f13aa69f9a2e5bd")
+            payload = struct.pack(">B", 0x02) + element + scalar
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Confirm payload with incorrect value")
+            payload = struct.pack(">B", 0x03) + 32*'\0'
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
 
-        return None
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Unexpected confirm exchange")
+            payload = struct.pack(">B", 0x03)
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
 
-    srv = start_radius_server(aka_prime_handler)
+        logger.info("No more test responses available - test case completed")
+        global eap_proto_pwd_test_done
+        eap_proto_pwd_test_done = True
+        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+    srv = start_radius_server(pwd_handler)
 
     try:
-        hapd = start_ap(apdev[0]['ifname'])
+        hapd = start_ap(apdev[0])
 
-        for i in range(0, 16):
+        i = 0
+        while not eap_proto_pwd_test_done:
+            i += 1
+            logger.info("Running connection iteration %d" % i)
             dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
-                           eap="AKA'", identity="6555444333222111",
-                           password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
+                           eap="PWD", identity="pwd user",
+                           password="secret password",
+                           wait_connect=False)
+            ok = False
+            for j in range(5):
+                ev = dev[0].wait_event(["CTRL-EVENT-EAP-STATUS",
+                                        "CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                       timeout=5)
+                if ev is None:
+                    raise Exception("Timeout on EAP start")
+                if "CTRL-EVENT-EAP-PROPOSED-METHOD" in ev:
+                    ok = True
+                    break
+                if "CTRL-EVENT-EAP-STATUS" in ev and "status='completion' parameter='failure'" in ev:
+                    ok = True
+                    break
+            if not ok:
+                raise Exception("Expected EAP event not seen")
+            if eap_proto_pwd_test_wait:
+                for k in range(10):
+                    time.sleep(0.1)
+                    if not eap_proto_pwd_test_wait:
+                        break
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected(timeout=1)
+            dev[0].dump_monitor()
+    finally:
+        stop_radius_server(srv)
+
+def test_eap_proto_pwd_errors(dev, apdev):
+    """EAP-pwd local error cases"""
+    check_eap_capa(dev[0], "PWD")
+    params = hostapd.wpa2_eap_params(ssid="eap-test")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    for i in range(1, 4):
+        with alloc_fail(dev[0], i, "eap_pwd_init"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PWD", identity="pwd user",
+                           password="secret password",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    with alloc_fail(dev[0], 1, "eap_pwd_get_session_id"):
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="PWD", identity="pwd user",
+                       fragment_size="0",
+                       password="secret password")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    funcs = [ "eap_pwd_getkey", "eap_pwd_get_emsk" ]
+    for func in funcs:
+        with alloc_fail(dev[0], 1, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PWD", identity="pwd user",
+                           password="secret password", erp="1",
+                           wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    for i in range(1, 7):
+        with alloc_fail(dev[0], i, "eap_pwd_perform_id_exchange"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PWD", identity="pwd user",
+                           password="secret password",
                            wait_connect=False)
             ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
                                    timeout=15)
             if ev is None:
                 raise Exception("Timeout on EAP start")
-            if i in [ 0 ]:
+            ok = False
+            for j in range(10):
+                state = dev[0].request('GET_ALLOC_FAIL')
+                if state.startswith('0:'):
+                    ok = True
+                    break
                 time.sleep(0.1)
-            else:
-                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
-                                       timeout=10)
-                if ev is None:
-                    raise Exception("Timeout on EAP failure")
+            if not ok:
+                raise Exception("No allocation failure seen")
             dev[0].request("REMOVE_NETWORK all")
-            dev[0].dump_monitor()
-    finally:
-        stop_radius_server(srv)
+            dev[0].wait_disconnected()
+
+    with alloc_fail(dev[0], 1, "wpabuf_alloc;eap_pwd_perform_id_exchange"):
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="PWD", identity="pwd user",
+                       password="secret password",
+                       wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                               timeout=15)
+        if ev is None:
+            raise Exception("Timeout on EAP start")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    for i in range(1, 4):
+        with alloc_fail(dev[0], i, "eap_pwd_perform_commit_exchange"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PWD", identity="pwd user",
+                           password="secret password",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            ok = False
+            for j in range(10):
+                state = dev[0].request('GET_ALLOC_FAIL')
+                if state.startswith('0:'):
+                    ok = True
+                    break
+                time.sleep(0.1)
+            if not ok:
+                raise Exception("No allocation failure seen")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    for i in range(1, 12):
+        with alloc_fail(dev[0], i, "eap_pwd_perform_confirm_exchange"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PWD", identity="pwd user",
+                           password="secret password",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            ok = False
+            for j in range(10):
+                state = dev[0].request('GET_ALLOC_FAIL')
+                if state.startswith('0:'):
+                    ok = True
+                    break
+                time.sleep(0.1)
+            if not ok:
+                raise Exception("No allocation failure seen")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    for i in range(1, 5):
+        with alloc_fail(dev[0], i, "eap_msg_alloc;=eap_pwd_process"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PWD", identity="pwd user",
+                           password="secret password", fragment_size="50",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    # No password configured
+    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="PWD", identity="pwd user",
+                   wait_connect=False)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=52"],
+                           timeout=15)
+    if ev is None:
+        raise Exception("EAP-pwd not started")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+    with fail_test(dev[0], 1,
+                   "hash_nt_password_hash;eap_pwd_perform_id_exchange"):
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="PWD", identity="pwd-hash",
+                       password_hex="hash:e3718ece8ab74792cbbfffd316d2d19a",
+                       wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=10)
+        if ev is None:
+            raise Exception("No EAP-Failure reported")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    params = { "ssid": "eap-test2", "wpa": "2", "wpa_key_mgmt": "WPA-EAP",
+               "rsn_pairwise": "CCMP", "ieee8021x": "1",
+               "eap_server": "1", "eap_user_file": "auth_serv/eap_user.conf",
+               "pwd_group": "19", "fragment_size": "40" }
+    hostapd.add_ap(apdev[1], params)
+
+    with alloc_fail(dev[0], 1, "wpabuf_alloc;=eap_pwd_process"):
+        dev[0].connect("eap-test2", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="PWD", identity="pwd user",
+                       password="secret password",
+                       wait_connect=False)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
 
-def test_eap_proto_sim(dev, apdev):
-    """EAP-SIM protocol tests"""
-    def sim_handler(ctx, req):
-        logger.info("sim_handler - RX " + req.encode("hex"))
+def test_eap_proto_erp(dev, apdev):
+    """ERP protocol tests"""
+    check_erp_capa(dev[0])
+
+    global eap_proto_erp_test_done
+    eap_proto_erp_test_done = False
+
+    def erp_handler(ctx, req):
+        logger.info("erp_handler - RX " + req.encode("hex"))
         if 'num' not in ctx:
             ctx['num'] = 0
-        ctx['num'] = ctx['num'] + 1
+        ctx['num'] += 1
         if 'id' not in ctx:
             ctx['id'] = 1
         ctx['id'] = (ctx['id'] + 1) % 256
-
         idx = 0
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Missing payload")
-            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1,
-                               EAP_TYPE_SIM)
+            logger.info("Test: Missing type")
+            return struct.pack(">BBH", EAP_CODE_INITIATE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected AT_AUTN")
-            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
-                               EAP_SIM_AT_AUTN, 2, 0, 0)
+            logger.info("Test: Unexpected type")
+            return struct.pack(">BBHB", EAP_CODE_INITIATE, ctx['id'], 4 + 1,
+                               255)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Missing Reserved field")
+            return struct.pack(">BBHB", EAP_CODE_INITIATE, ctx['id'], 4 + 1,
+                               EAP_ERP_TYPE_REAUTH_START)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Too short AT_VERSION_LIST")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
-                               EAP_SIM_AT_VERSION_LIST, 1, 0)
+            logger.info("Test: Zero-length TVs/TLVs")
+            payload = ""
+            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
+                               4 + 1 + 1 + len(payload),
+                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Too short TLV")
+            payload = struct.pack("B", 191)
+            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
+                               4 + 1 + 1 + len(payload),
+                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: AT_VERSION_LIST overflow")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
-                               EAP_SIM_AT_VERSION_LIST, 1, 0xffff)
+            logger.info("Test: Truncated TLV")
+            payload = struct.pack("BB", 191, 1)
+            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
+                               4 + 1 + 1 + len(payload),
+                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Ignored unknown TLV and unknown TV/TLV terminating parsing")
+            payload = struct.pack("BBB", 191, 0, 192)
+            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
+                               4 + 1 + 1 + len(payload),
+                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected AT_AUTS")
-            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
-                               EAP_SIM_AT_AUTS, 2, 0, 0)
+            logger.info("Test: More than one keyName-NAI")
+            payload = struct.pack("BBBB", EAP_ERP_TLV_KEYNAME_NAI, 0,
+                                  EAP_ERP_TLV_KEYNAME_NAI, 0)
+            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
+                               4 + 1 + 1 + len(payload),
+                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Too short TLV keyName-NAI")
+            payload = struct.pack("B", EAP_ERP_TLV_KEYNAME_NAI)
+            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
+                               4 + 1 + 1 + len(payload),
+                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected AT_CHECKCODE")
-            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
-                               EAP_SIM_AT_CHECKCODE, 2, 0, 0)
+            logger.info("Test: Truncated TLV keyName-NAI")
+            payload = struct.pack("BB", EAP_ERP_TLV_KEYNAME_NAI, 1)
+            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
+                               4 + 1 + 1 + len(payload),
+                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Valid rRK lifetime TV followed by too short rMSK lifetime TV")
+            payload = struct.pack(">BLBH", EAP_ERP_TV_RRK_LIFETIME, 0,
+                                  EAP_ERP_TV_RMSK_LIFETIME, 0)
+            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
+                               4 + 1 + 1 + len(payload),
+                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: No AT_VERSION_LIST in Start")
-            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0)
+            logger.info("Test: Missing type (Finish)")
+            return struct.pack(">BBH", EAP_CODE_FINISH, ctx['id'], 4)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Unexpected type (Finish)")
+            return struct.pack(">BBHB", EAP_CODE_FINISH, ctx['id'], 4 + 1,
+                               255)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: No support version in AT_VERSION_LIST")
-            return struct.pack(">BBHBBHBBH4B", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
-                               EAP_SIM_AT_VERSION_LIST, 2, 3, 2, 3, 4, 5)
+            logger.info("Test: Missing fields (Finish)")
+            return struct.pack(">BBHB", EAP_CODE_FINISH, ctx['id'], 4 + 1,
+                               EAP_ERP_TYPE_REAUTH)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Unexpected SEQ (Finish)")
+            return struct.pack(">BBHBBHB", EAP_CODE_FINISH, ctx['id'],
+                               4 + 1 + 4,
+                               EAP_ERP_TYPE_REAUTH, 0, 0xffff, 0)
 
+        logger.info("No more test responses available - test case completed")
+        global eap_proto_erp_test_done
+        eap_proto_erp_test_done = True
+        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request without ID type")
-            return struct.pack(">BBHBBHBBH2H", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
-                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request ANY_ID")
-            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 4,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
-                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
-                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request ANY_ID (duplicate)")
-            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 4,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
-                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
-                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+    srv = start_radius_server(erp_handler)
 
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request ANY_ID")
-            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 4,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
-                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
-                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request FULLAUTH_ID")
-            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 4,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
-                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
-                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request FULLAUTH_ID (duplicate)")
-            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 4,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
-                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
-                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+    try:
+        hapd = start_ap(apdev[0])
 
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request ANY_ID")
-            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 4,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
-                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
-                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request FULLAUTH_ID")
-            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 4,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
-                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
-                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request PERMANENT_ID")
-            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 4,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
-                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
-                               EAP_SIM_AT_PERMANENT_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Identity request PERMANENT_ID (duplicate)")
-            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 8 + 4,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
-                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
-                               EAP_SIM_AT_PERMANENT_ID_REQ, 1, 0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+        i = 0
+        while not eap_proto_erp_test_done:
+            i += 1
+            logger.info("Running connection iteration %d" % i)
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PAX", identity="pax.user@example.com",
+                           password_hex="0123456789abcdef0123456789abcdef",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            time.sleep(0.1)
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected(timeout=1)
+            dev[0].dump_monitor()
+    finally:
+        stop_radius_server(srv)
+
+def test_eap_proto_fast_errors(dev, apdev):
+    """EAP-FAST local error cases"""
+    check_eap_capa(dev[0], "FAST")
+    params = hostapd.wpa2_eap_params(ssid="eap-test")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    for i in range(1, 5):
+        with alloc_fail(dev[0], i, "eap_fast_init"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="FAST", anonymous_identity="FAST",
+                           identity="user", password="password",
+                           ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
+                           phase1="fast_provisioning=2",
+                           pac_file="blob://fast_pac_auth",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
+                                   timeout=5)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "wpabuf_alloc;eap_fast_tlv_eap_payload"),
+              (1, "eap_fast_derive_key;eap_fast_derive_key_auth"),
+              (1, "eap_msg_alloc;eap_peer_tls_phase2_nak"),
+              (1, "wpabuf_alloc;eap_fast_tlv_result"),
+              (1, "wpabuf_alloc;eap_fast_tlv_pac_ack"),
+              (1, "=eap_peer_tls_derive_session_id;eap_fast_process_crypto_binding"),
+              (1, "eap_peer_tls_decrypt;eap_fast_decrypt"),
+              (1, "eap_fast_getKey"),
+              (1, "eap_fast_get_session_id"),
+              (1, "eap_fast_get_emsk") ]
+    for count, func in tests:
+        dev[0].request("SET blob fast_pac_auth_errors ")
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="FAST", anonymous_identity="FAST",
+                           identity="user", password="password",
+                           ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
+                           phase1="fast_provisioning=2",
+                           pac_file="blob://fast_pac_auth_errors",
+                           erp="1",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "eap_fast_derive_key;eap_fast_derive_key_provisioning"),
+              (1, "eap_mschapv2_getKey;eap_fast_get_phase2_key"),
+              (1, "=eap_fast_use_pac_opaque"),
+              (1, "eap_fast_copy_buf"),
+              (1, "=eap_fast_add_pac"),
+              (1, "=eap_fast_init_pac_data"),
+              (1, "=eap_fast_write_pac"),
+              (2, "=eap_fast_write_pac") ]
+    for count, func in tests:
+        dev[0].request("SET blob fast_pac_errors ")
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="FAST", anonymous_identity="FAST",
+                           identity="user", password="password",
+                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                           phase1="fast_provisioning=1",
+                           pac_file="blob://fast_pac_errors",
+                           erp="1",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "eap_fast_get_cmk;eap_fast_process_crypto_binding"),
+              (1, "eap_fast_derive_eap_msk;eap_fast_process_crypto_binding"),
+              (1, "eap_fast_derive_eap_emsk;eap_fast_process_crypto_binding") ]
+    for count, func in tests:
+        dev[0].request("SET blob fast_pac_auth_errors ")
+        with fail_test(dev[0], count, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="FAST", anonymous_identity="FAST",
+                           identity="user", password="password",
+                           ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
+                           phase1="fast_provisioning=2",
+                           pac_file="blob://fast_pac_auth_errors",
+                           erp="1",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    dev[0].request("SET blob fast_pac_errors ")
+    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="FAST", anonymous_identity="FAST",
+                   identity="user", password="password",
+                   ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
+                   phase1="fast_provisioning=1",
+                   pac_file="blob://fast_pac_errors",
+                   wait_connect=False)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on EAP start")
+    # EAP-FAST: Only EAP-MSCHAPv2 is allowed during unauthenticated
+    # provisioning; reject phase2 type 6
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on EAP failure")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+    logger.info("Wrong password in Phase 2")
+    dev[0].request("SET blob fast_pac_errors ")
+    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="FAST", anonymous_identity="FAST",
+                   identity="user", password="wrong password",
+                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                   phase1="fast_provisioning=1",
+                   pac_file="blob://fast_pac_errors",
+                   wait_connect=False)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on EAP start")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on EAP failure")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+    tests = [ "FOOBAR\n",
+              "wpa_supplicant EAP-FAST PAC file - version 1\nFOOBAR\n",
+              "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\n",
+              "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nSTART\n",
+              "wpa_supplicant EAP-FAST PAC file - version 1\nEND\n",
+              "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nPAC-Type=12345\nEND\n"
+              "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nPAC-Key=12\nEND\n",
+              "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nPAC-Key=1\nEND\n",
+              "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nPAC-Key=1q\nEND\n",
+              "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nPAC-Opaque=1\nEND\n",
+              "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nA-ID=1\nEND\n",
+              "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nI-ID=1\nEND\n",
+              "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nA-ID-Info=1\nEND\n" ]
+    for pac in tests:
+        blob = binascii.hexlify(pac)
+        dev[0].request("SET blob fast_pac_errors " + blob)
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="FAST", anonymous_identity="FAST",
+                       identity="user", password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
+                       phase1="fast_provisioning=2",
+                       pac_file="blob://fast_pac_errors",
+                       wait_connect=False)
+        ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
+                               timeout=5)
+        if ev is None:
+            raise Exception("Timeout on EAP start")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    tests = [ "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nEND\n",
+              "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nEND\nSTART\nEND\nSTART\nEND\n" ]
+    for pac in tests:
+        blob = binascii.hexlify(pac)
+        dev[0].request("SET blob fast_pac_errors " + blob)
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="FAST", anonymous_identity="FAST",
+                       identity="user", password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
+                       phase1="fast_provisioning=2",
+                       pac_file="blob://fast_pac_errors")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    dev[0].request("SET blob fast_pac_errors ")
+
+def test_eap_proto_peap_errors(dev, apdev):
+    """EAP-PEAP local error cases"""
+    check_eap_capa(dev[0], "PEAP")
+    check_eap_capa(dev[0], "MSCHAPV2")
+    params = hostapd.wpa2_eap_params(ssid="eap-test")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    for i in range(1, 5):
+        with alloc_fail(dev[0], i, "eap_peap_init"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PEAP", anonymous_identity="peap",
+                           identity="user", password="password",
+                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
+                                   timeout=5)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "eap_mschapv2_getKey;eap_peap_get_isk;eap_peap_derive_cmk"),
+              (1, "eap_msg_alloc;eap_tlv_build_result"),
+              (1, "eap_mschapv2_init;eap_peap_phase2_request"),
+              (1, "eap_peer_tls_decrypt;eap_peap_decrypt"),
+              (1, "wpabuf_alloc;=eap_peap_decrypt"),
+              (1, "eap_peer_tls_encrypt;eap_peap_decrypt"),
+              (1, "eap_peer_tls_process_helper;eap_peap_process"),
+              (1, "eap_peer_tls_derive_key;eap_peap_process"),
+              (1, "eap_peer_tls_derive_session_id;eap_peap_process"),
+              (1, "eap_peap_getKey"),
+              (1, "eap_peap_get_session_id") ]
+    for count, func in tests:
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PEAP", anonymous_identity="peap",
+                           identity="user", password="password",
+                           phase1="peapver=0 crypto_binding=2",
+                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                           erp="1", wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "peap_prfplus;eap_peap_derive_cmk"),
+              (1, "eap_tlv_add_cryptobinding;eap_tlv_build_result"),
+              (1, "peap_prfplus;eap_peap_getKey") ]
+    for count, func in tests:
+        with fail_test(dev[0], count, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="PEAP", anonymous_identity="peap",
+                           identity="user", password="password",
+                           phase1="peapver=0 crypto_binding=2",
+                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                           erp="1", wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    with alloc_fail(dev[0], 1,
+                    "eap_peer_tls_phase2_nak;eap_peap_phase2_request"):
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="PEAP", anonymous_identity="peap",
+                       identity="cert user", password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                       wait_connect=False)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+def test_eap_proto_ttls_errors(dev, apdev):
+    """EAP-TTLS local error cases"""
+    check_eap_capa(dev[0], "TTLS")
+    check_eap_capa(dev[0], "MSCHAPV2")
+    params = hostapd.wpa2_eap_params(ssid="eap-test")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    for i in range(1, 5):
+        with alloc_fail(dev[0], i, "eap_ttls_init"):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="TTLS", anonymous_identity="ttls",
+                           identity="user", password="password",
+                           ca_cert="auth_serv/ca.pem",
+                           phase2="autheap=MSCHAPV2",
+                           wait_connect=False)
+            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
+                                   timeout=5)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "eap_peer_tls_derive_key;eap_ttls_v0_derive_key",
+               "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
+              (1, "eap_peer_tls_derive_session_id;eap_ttls_v0_derive_key",
+               "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
+              (1, "wpabuf_alloc;eap_ttls_phase2_request_mschapv2",
+               "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
+              (1, "eap_peer_tls_derive_key;eap_ttls_phase2_request_mschapv2",
+               "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
+              (1, "eap_peer_tls_encrypt;eap_ttls_encrypt_response;eap_ttls_implicit_identity_request",
+               "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
+              (1, "eap_peer_tls_decrypt;eap_ttls_decrypt",
+               "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
+              (1, "eap_ttls_getKey",
+               "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
+              (1, "eap_ttls_get_session_id",
+               "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
+              (1, "eap_ttls_get_emsk",
+               "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
+              (1, "wpabuf_alloc;eap_ttls_phase2_request_mschap",
+               "mschap user", "auth=MSCHAP"),
+              (1, "eap_peer_tls_derive_key;eap_ttls_phase2_request_mschap",
+               "mschap user", "auth=MSCHAP"),
+              (1, "wpabuf_alloc;eap_ttls_phase2_request_chap",
+               "chap user", "auth=CHAP"),
+              (1, "eap_peer_tls_derive_key;eap_ttls_phase2_request_chap",
+               "chap user", "auth=CHAP"),
+              (1, "wpabuf_alloc;eap_ttls_phase2_request_pap",
+               "pap user", "auth=PAP"),
+              (1, "wpabuf_alloc;eap_ttls_avp_encapsulate",
+               "user", "autheap=MSCHAPV2"),
+              (1, "eap_mschapv2_init;eap_ttls_phase2_request_eap_method",
+               "user", "autheap=MSCHAPV2"),
+              (1, "eap_sm_buildIdentity;eap_ttls_phase2_request_eap",
+               "user", "autheap=MSCHAPV2"),
+              (1, "eap_ttls_avp_encapsulate;eap_ttls_phase2_request_eap",
+               "user", "autheap=MSCHAPV2"),
+              (1, "eap_ttls_parse_attr_eap",
+               "user", "autheap=MSCHAPV2"),
+              (1, "eap_peer_tls_encrypt;eap_ttls_encrypt_response;eap_ttls_process_decrypted",
+               "user", "autheap=MSCHAPV2"),
+              (1, "eap_ttls_fake_identity_request",
+               "user", "autheap=MSCHAPV2"),
+              (1, "eap_msg_alloc;eap_tls_process_output",
+               "user", "autheap=MSCHAPV2"),
+              (1, "eap_msg_alloc;eap_peer_tls_build_ack",
+               "user", "autheap=MSCHAPV2"),
+              (1, "tls_connection_decrypt;eap_peer_tls_decrypt",
+               "user", "autheap=MSCHAPV2"),
+              (1, "eap_peer_tls_phase2_nak;eap_ttls_phase2_request_eap_method",
+               "cert user", "autheap=MSCHAPV2") ]
+    for count, func, identity, phase2 in tests:
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="TTLS", anonymous_identity="ttls",
+                           identity=identity, password="password",
+                           ca_cert="auth_serv/ca.pem", phase2=phase2,
+                           erp="1", wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL",
+                              note="Allocation failure not triggered for: %d:%s" % (count, func))
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    tests = [ (1, "os_get_random;eap_ttls_phase2_request_mschapv2"),
+              (1, "mschapv2_derive_response;eap_ttls_phase2_request_mschapv2") ]
+    for count, func in tests:
+        with fail_test(dev[0], count, func):
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="TTLS", anonymous_identity="ttls",
+                           identity="DOMAIN\mschapv2 user", password="password",
+                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                           erp="1", wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            wait_fail_trigger(dev[0], "GET_FAIL",
+                              note="Test failure not triggered for: %d:%s" % (count, func))
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+def test_eap_proto_expanded(dev, apdev):
+    """EAP protocol tests with expanded header"""
+    global eap_proto_expanded_test_done
+    eap_proto_expanded_test_done = False
+
+    def expanded_handler(ctx, req):
+        logger.info("expanded_handler - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] += 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+        idx = 0
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: No AT_MAC and AT_RAND in Challenge")
-            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0)
+            logger.info("Test: MD5 challenge in expanded header")
+            return struct.pack(">BBHB3BLBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 3,
+                               EAP_TYPE_EXPANDED, 0, 0, 0, EAP_TYPE_MD5,
+                               1, 0xaa, ord('n'))
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: No AT_RAND in Challenge")
-            return struct.pack(">BBHBBHBBH4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 20,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
+            logger.info("Test: Invalid expanded EAP length")
+            return struct.pack(">BBHB3BH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 2,
+                               EAP_TYPE_EXPANDED, 0, 0, 0, EAP_TYPE_MD5)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Insufficient number of challenges in Challenge")
-            return struct.pack(">BBHBBHBBH4LBBH4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 20 + 20,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_RAND, 5, 0, 0, 0, 0, 0,
-                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
+            logger.info("Test: Invalid expanded frame type")
+            return struct.pack(">BBHB3BL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_EXPANDED, 0, 0, 1, EAP_TYPE_MD5)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Too many challenges in Challenge")
-            return struct.pack(">BBHBBHBBH4L4L4L4LBBH4L", EAP_CODE_REQUEST,
-                               ctx['id'],
-                               4 + 1 + 3 + 4 + 4 * 16 + 20,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_RAND, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0,
-                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
+            logger.info("Test: MSCHAPv2 Challenge")
+            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 4 + 1 + 16 + 6,
+                               EAP_TYPE_MSCHAPV2,
+                               1, 0, 4 + 1 + 16 + 6, 16) + 16*'A' + 'foobar'
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Invalid expanded frame type")
+            return struct.pack(">BBHB3BL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4,
+                               EAP_TYPE_EXPANDED, 0, 0, 1, EAP_TYPE_MSCHAPV2)
+
+        logger.info("No more test responses available - test case completed")
+        global eap_proto_expanded_test_done
+        eap_proto_expanded_test_done = True
+        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+    srv = start_radius_server(expanded_handler)
+
+    try:
+        hapd = start_ap(apdev[0])
+
+        i = 0
+        while not eap_proto_expanded_test_done:
+            i += 1
+            logger.info("Running connection iteration %d" % i)
+            if i == 4:
+                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                               eap="MSCHAPV2", identity="user",
+                               password="password",
+                               wait_connect=False)
+            else:
+                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                               eap="MD5", identity="user", password="password",
+                               wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            if i in [ 1 ]:
+                ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
+                if ev is None:
+                    raise Exception("Timeout on EAP method start")
+                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+                if ev is None:
+                    raise Exception("Timeout on EAP failure")
+            elif i in [ 2, 3 ]:
+                ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                       timeout=5)
+                if ev is None:
+                    raise Exception("Timeout on EAP proposed method")
+                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+                if ev is None:
+                    raise Exception("Timeout on EAP failure")
+            else:
+                time.sleep(0.1)
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected(timeout=1)
+            dev[0].dump_monitor()
+    finally:
+        stop_radius_server(srv)
+
+def test_eap_proto_tls(dev, apdev):
+    """EAP-TLS protocol tests"""
+    check_eap_capa(dev[0], "TLS")
+    global eap_proto_tls_test_done, eap_proto_tls_test_wait
+    eap_proto_tls_test_done = False
+    eap_proto_tls_test_wait = False
+
+    def tls_handler(ctx, req):
+        logger.info("tls_handler - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] += 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+        idx = 0
+
+        global eap_proto_tls_test_wait
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Same RAND multiple times in Challenge")
-            return struct.pack(">BBHBBHBBH4L4L4LBBH4L", EAP_CODE_REQUEST,
-                               ctx['id'],
-                               4 + 1 + 3 + 4 + 3 * 16 + 20,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0,
-                               EAP_SIM_AT_RAND, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1,
-                               0, 0, 0, 0,
-                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
+            logger.info("Test: Too much payload in TLS/Start: TLS Message Length (0 bytes) smaller than this fragment (1 bytes)")
+            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 4 + 1,
+                               EAP_TYPE_TLS, 0xa0, 0, 1)
+
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
-
+            logger.info("Test: Fragmented TLS/Start")
+            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 4 + 1,
+                               EAP_TYPE_TLS, 0xe0, 2, 1)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Notification with no attributes")
-            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0)
+            logger.info("Test: Too long fragment of TLS/Start: Invalid reassembly state: tls_in_left=2 tls_in_len=0 in_len=0")
+            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2,
+                               EAP_TYPE_TLS, 0x00, 2, 3)
         idx += 1
         if ctx['num'] == idx:
             logger.info("Test: EAP-Failure")
@@ -3422,36 +7088,28 @@ def test_eap_proto_sim(dev, apdev):
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Notification indicating success, but no MAC")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
-                               EAP_SIM_AT_NOTIFICATION, 1, 32768)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
-
+            logger.info("Test: TLS/Start")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TLS, 0x20)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Notification indicating success, but invalid MAC value")
-            return struct.pack(">BBHBBHBBHBBH4L", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4 + 20,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
-                               EAP_SIM_AT_NOTIFICATION, 1, 32768,
-                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
+            logger.info("Test: Fragmented TLS message")
+            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 4 + 1,
+                               EAP_TYPE_TLS, 0xc0, 2, 1)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
-
+            logger.info("Test: Invalid TLS message: no Flags octet included + workaround")
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1,
+                               EAP_TYPE_TLS)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Notification before auth")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
-                               EAP_SIM_AT_NOTIFICATION, 1, 16384)
+            logger.info("Test: Too long fragment of TLS message: more data than TLS message length indicated")
+            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2,
+                               EAP_TYPE_TLS, 0x00, 2, 3)
         idx += 1
         if ctx['num'] == idx:
             logger.info("Test: EAP-Failure")
@@ -3459,53 +7117,54 @@ def test_eap_proto_sim(dev, apdev):
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Notification before auth")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
-                               EAP_SIM_AT_NOTIFICATION, 1, 16385)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Fragmented TLS/Start and truncated Message Length field")
+            return struct.pack(">BBHBB3B", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 3,
+                               EAP_TYPE_TLS, 0xe0, 1, 2, 3)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Notification with unrecognized non-failure")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
-                               EAP_SIM_AT_NOTIFICATION, 1, 0xc000)
+            logger.info("Test: TLS/Start")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TLS, 0x20)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Notification before auth (duplicate)")
-            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3 + 4,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
-                               EAP_SIM_AT_NOTIFICATION, 1, 0xc000)
+            logger.info("Test: Fragmented TLS message")
+            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 4 + 1,
+                               EAP_TYPE_TLS, 0xc0, 2, 1)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+            logger.info("Test: Invalid TLS message: no Flags octet included + workaround disabled")
+            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1,
+                               EAP_TYPE_TLS)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Re-authentication (unexpected) with no attributes")
-            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_REAUTHENTICATION,
-                               0)
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
-
+            logger.info("Test: TLS/Start")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TLS, 0x20)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Client Error")
-            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3,
-                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CLIENT_ERROR, 0)
+            logger.info("Test: Fragmented TLS message (long; first)")
+            payload = 1450*'A'
+            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 4 + len(payload),
+                               EAP_TYPE_TLS, 0xc0, 65536) + payload
+        # "Too long TLS fragment (size over 64 kB)" on the last one
+        for i in range(44):
+            idx += 1
+            if ctx['num'] == idx:
+                logger.info("Test: Fragmented TLS message (long; cont %d)" % i)
+                eap_proto_tls_test_wait = True
+                payload = 1470*'A'
+                return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                                   4 + 1 + 1 + len(payload),
+                                   EAP_TYPE_TLS, 0x40) + payload
+        eap_proto_tls_test_wait = False
         idx += 1
         if ctx['num'] == idx:
             logger.info("Test: EAP-Failure")
@@ -3513,501 +7172,1112 @@ def test_eap_proto_sim(dev, apdev):
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unknown subtype")
-            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 3,
-                               EAP_TYPE_SIM, 255, 0)
+            logger.info("Test: TLS/Start")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TLS, 0x20)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Non-ACK to more-fragment message")
+            return struct.pack(">BBHBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 1,
+                               EAP_TYPE_TLS, 0x00, 255)
         idx += 1
         if ctx['num'] == idx:
             logger.info("Test: EAP-Failure")
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
-        return None
+        logger.info("No more test responses available - test case completed")
+        global eap_proto_tls_test_done
+        eap_proto_tls_test_done = True
+        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
-    srv = start_radius_server(sim_handler)
+    srv = start_radius_server(tls_handler)
 
     try:
-        hapd = start_ap(apdev[0]['ifname'])
-
-        for i in range(0, 25):
+        hapd = start_ap(apdev[0])
+
+        i = 0
+        while not eap_proto_tls_test_done:
+            i += 1
+            logger.info("Running connection iteration %d" % i)
+            workaround = "0" if i == 6 else "1"
+            fragment_size = "100" if i == 8 else "1400"
             dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
-                           eap="SIM", identity="1232010000000000",
-                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
+                           eap="TLS", identity="tls user",
+                           ca_cert="auth_serv/ca.pem",
+                           client_cert="auth_serv/user.pem",
+                           private_key="auth_serv/user.key",
+                           eap_workaround=workaround,
+                           fragment_size=fragment_size,
                            wait_connect=False)
-            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
-                                   timeout=15)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
             if ev is None:
                 raise Exception("Timeout on EAP start")
-            if i in [ 0 ]:
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD",
+                                    "CTRL-EVENT-EAP-STATUS"], timeout=5)
+            if ev is None:
+                raise Exception("Timeout on EAP method start")
+            time.sleep(0.1)
+            start = os.times()[4]
+            while eap_proto_tls_test_wait:
+                now = os.times()[4]
+                if now - start > 10:
+                    break
                 time.sleep(0.1)
-            else:
-                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
-                                       timeout=10)
-                if ev is None:
-                    raise Exception("Timeout on EAP failure")
             dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected(timeout=1)
             dev[0].dump_monitor()
     finally:
         stop_radius_server(srv)
 
-def test_eap_proto_ikev2(dev, apdev):
-    """EAP-IKEv2 protocol tests"""
-    check_eap_capa(dev[0], "IKEV2")
-    def ikev2_handler(ctx, req):
-        logger.info("ikev2_handler - RX " + req.encode("hex"))
+def test_eap_proto_tnc(dev, apdev):
+    """EAP-TNC protocol tests"""
+    check_eap_capa(dev[0], "TNC")
+    global eap_proto_tnc_test_done
+    eap_proto_tnc_test_done = False
+
+    def tnc_handler(ctx, req):
+        logger.info("tnc_handler - RX " + req.encode("hex"))
         if 'num' not in ctx:
             ctx['num'] = 0
-        ctx['num'] = ctx['num'] + 1
+        ctx['num'] += 1
         if 'id' not in ctx:
             ctx['id'] = 1
         ctx['id'] = (ctx['id'] + 1) % 256
-
         idx = 0
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Missing payload")
+            logger.info("Test: TNC start with unsupported version")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x20)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: TNC without Flags field")
             return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1,
-                               EAP_TYPE_IKEV2)
+                               EAP_TYPE_TNC)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Message underflow due to missing Message Length")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0xa1)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid Message Length")
+            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 4 + 1,
+                               EAP_TYPE_TNC, 0xa1, 0, 0)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Invalid Message Length")
+            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 4,
+                               EAP_TYPE_TNC, 0xe1, 75001)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Start with Message Length")
+            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 4,
+                               EAP_TYPE_TNC, 0xa1, 1)
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: Server used start flag again")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x21)
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x21)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Truncated Message Length field")
-            return struct.pack(">BBHBB3B", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 3,
-                               EAP_TYPE_IKEV2, 0x80, 0, 0, 0)
+            logger.info("Test: Fragmentation and unexpected payload in ack")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x21)
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x01)
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBHBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 1,
+                               EAP_TYPE_TNC, 0x01, 0)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Too short Message Length value")
+            logger.info("Test: Server fragmenting and fragment overflow")
             return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 1 + 4 + 1,
-                               EAP_TYPE_IKEV2, 0x80, 0, 1)
-
+                               EAP_TYPE_TNC, 0xe1, 2, 1)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Truncated message")
-            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 4,
-                               EAP_TYPE_IKEV2, 0x80, 1)
+            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 2,
+                               EAP_TYPE_TNC, 0x01, 2, 3)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Truncated message(2)")
-            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 4,
-                               EAP_TYPE_IKEV2, 0x80, 0xffffffff)
+            logger.info("Test: Server fragmenting and no message length in a fragment")
+            return struct.pack(">BBHBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + 1,
+                               EAP_TYPE_TNC, 0x61, 2)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Truncated message(3)")
-            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 4,
-                               EAP_TYPE_IKEV2, 0xc0, 0xffffffff)
-
+            logger.info("Test: TNC start followed by invalid TNCCS-Batch")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x21)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Truncated message(4)")
-            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 4,
-                               EAP_TYPE_IKEV2, 0xc0, 10000000)
+            logger.info("Received TNCCS-Batch: " + req[6:])
+            resp = "FOO"
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + len(resp),
+                               EAP_TYPE_TNC, 0x01) + resp
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Too long fragments (first fragment)")
-            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 4 + 1,
-                               EAP_TYPE_IKEV2, 0xc0, 2, 1)
-
+            logger.info("Test: TNC start followed by invalid TNCCS-Batch (2)")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x21)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Too long fragments (second fragment)")
-            return struct.pack(">BBHBB2B", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 2,
-                               EAP_TYPE_IKEV2, 0x00, 2, 3)
+            logger.info("Received TNCCS-Batch: " + req[6:])
+            resp = "</TNCCS-Batch><TNCCS-Batch>"
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + len(resp),
+                               EAP_TYPE_TNC, 0x01) + resp
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: No Message Length field in first fragment")
-            return struct.pack(">BBHBBB", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 1,
-                               EAP_TYPE_IKEV2, 0x40, 1)
+            logger.info("Test: TNCCS-Batch missing BatchId attribute")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x21)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Received TNCCS-Batch: " + req[6:])
+            resp = "<TNCCS-Batch    foo=3></TNCCS-Batch>"
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + len(resp),
+                               EAP_TYPE_TNC, 0x01) + resp
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: ICV before keys")
+            logger.info("Test: Unexpected IF-TNCCS BatchId")
             return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
                                4 + 1 + 1,
-                               EAP_TYPE_IKEV2, 0x20)
-
+                               EAP_TYPE_TNC, 0x21)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unsupported IKEv2 header version")
-            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 28,
-                               EAP_TYPE_IKEV2, 0x00,
-                               0, 0, 0, 0,
-                               0, 0, 0, 0, 0, 0)
+            logger.info("Received TNCCS-Batch: " + req[6:])
+            resp = "<TNCCS-Batch    BatchId=123456789></TNCCS-Batch>"
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + len(resp),
+                               EAP_TYPE_TNC, 0x01) + resp
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Incorrect IKEv2 header Length")
-            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 28,
-                               EAP_TYPE_IKEV2, 0x00,
-                               0, 0, 0, 0,
-                               0, 0x20, 0, 0, 0, 0)
-
+            logger.info("Test: Missing IMC-IMV-Message and TNCC-TNCS-Message end tags")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x21)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected IKEv2 Exchange Type in SA_INIT state")
-            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 28,
-                               EAP_TYPE_IKEV2, 0x00,
-                               0, 0, 0, 0,
-                               0, 0x20, 0, 0, 0, 28)
+            logger.info("Received TNCCS-Batch: " + req[6:])
+            resp = "<TNCCS-Batch BatchId=2><IMC-IMV-Message><TNCC-TNCS-Message></TNCCS-Batch>"
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + len(resp),
+                               EAP_TYPE_TNC, 0x01) + resp
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected IKEv2 Message ID in SA_INIT state")
-            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 28,
-                               EAP_TYPE_IKEV2, 0x00,
-                               0, 0, 0, 0,
-                               0, 0x20, 34, 0, 1, 28)
+            logger.info("Test: Missing IMC-IMV-Message and TNCC-TNCS-Message Type")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x21)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Received TNCCS-Batch: " + req[6:])
+            resp = "<TNCCS-Batch BatchId=2><IMC-IMV-Message></IMC-IMV-Message><TNCC-TNCS-Message></TNCC-TNCS-Message></TNCCS-Batch>"
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + len(resp),
+                               EAP_TYPE_TNC, 0x01) + resp
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected IKEv2 Flags value")
-            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 28,
-                               EAP_TYPE_IKEV2, 0x00,
-                               0, 0, 0, 0,
-                               0, 0x20, 34, 0, 0, 28)
+            logger.info("Test: Missing TNCC-TNCS-Message XML end tag")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x21)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Received TNCCS-Batch: " + req[6:])
+            resp = "<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><XML></TNCC-TNCS-Message></TNCCS-Batch>"
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + len(resp),
+                               EAP_TYPE_TNC, 0x01) + resp
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected IKEv2 Flags value(2)")
-            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 28,
-                               EAP_TYPE_IKEV2, 0x00,
-                               0, 0, 0, 0,
-                               0, 0x20, 34, 0x20, 0, 28)
+            logger.info("Test: Missing TNCC-TNCS-Message Base64 start tag")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x21)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Received TNCCS-Batch: " + req[6:])
+            resp = "<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type></TNCC-TNCS-Message></TNCCS-Batch>"
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + len(resp),
+                               EAP_TYPE_TNC, 0x01) + resp
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: No SAi1 in SA_INIT")
-            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1 + 28,
-                               EAP_TYPE_IKEV2, 0x00,
-                               0, 0, 0, 0,
-                               0, 0x20, 34, 0x08, 0, 28)
+            logger.info("Test: Missing TNCC-TNCS-Message Base64 end tag")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x21)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Received TNCCS-Batch: " + req[6:])
+            resp = "<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><Base64>abc</TNCC-TNCS-Message></TNCCS-Batch>"
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + len(resp),
+                               EAP_TYPE_TNC, 0x01) + resp
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
-        def build_ike(id, next=0, exch_type=34, flags=0x00, ike=''):
-            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, id,
-                               4 + 1 + 1 + 28 + len(ike),
-                               EAP_TYPE_IKEV2, flags,
-                               0, 0, 0, 0,
-                               next, 0x20, exch_type, 0x08, 0,
-                               28 + len(ike)) + ike
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Test: TNCC-TNCS-Message Base64 message")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x21)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Received TNCCS-Batch: " + req[6:])
+            resp = "<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><Base64>aGVsbG8=</Base64></TNCC-TNCS-Message></TNCCS-Batch>"
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + len(resp),
+                               EAP_TYPE_TNC, 0x01) + resp
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected extra data after payloads")
-            return build_ike(ctx['id'], ike=struct.pack(">B", 1))
+            logger.info("Test: Invalid TNCC-TNCS-Message XML message")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x21)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Received TNCCS-Batch: " + req[6:])
+            resp = "<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><XML>hello</XML></TNCC-TNCS-Message></TNCCS-Batch>"
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + len(resp),
+                               EAP_TYPE_TNC, 0x01) + resp
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Truncated payload header")
-            return build_ike(ctx['id'], next=128, ike=struct.pack(">B", 1))
+            logger.info("Test: Missing TNCCS-Recommendation type")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x21)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Received TNCCS-Batch: " + req[6:])
+            resp = '<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><XML><TNCCS-Recommendation foo=1></TNCCS-Recommendation></XML></TNCC-TNCS-Message></TNCCS-Batch>'
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + len(resp),
+                               EAP_TYPE_TNC, 0x01) + resp
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Too small payload header length")
-            ike = struct.pack(">BBH", 0, 0, 3)
-            return build_ike(ctx['id'], next=128, ike=ike)
+            logger.info("Test: TNCCS-Recommendation type=none")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x21)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Received TNCCS-Batch: " + req[6:])
+            resp = '<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><XML><TNCCS-Recommendation type="none"></TNCCS-Recommendation></XML></TNCC-TNCS-Message></TNCCS-Batch>'
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + len(resp),
+                               EAP_TYPE_TNC, 0x01) + resp
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Too large payload header length")
-            ike = struct.pack(">BBH", 0, 0, 5)
-            return build_ike(ctx['id'], next=128, ike=ike)
+            logger.info("Test: TNCCS-Recommendation type=isolate")
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1,
+                               EAP_TYPE_TNC, 0x21)
+        idx += 1
+        if ctx['num'] == idx:
+            logger.info("Received TNCCS-Batch: " + req[6:])
+            resp = '<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><XML><TNCCS-Recommendation type="isolate"></TNCCS-Recommendation></XML></TNCC-TNCS-Message></TNCCS-Batch>'
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + len(resp),
+                               EAP_TYPE_TNC, 0x01) + resp
+        idx += 1
+        if ctx['num'] == idx:
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        logger.info("No more test responses available - test case completed")
+        global eap_proto_tnc_test_done
+        eap_proto_tnc_test_done = True
+        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+    srv = start_radius_server(tnc_handler)
+
+    try:
+        hapd = start_ap(apdev[0])
+
+        i = 0
+        while not eap_proto_tnc_test_done:
+            i += 1
+            logger.info("Running connection iteration %d" % i)
+            frag = 1400
+            if i == 8:
+                frag = 150
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                           eap="TNC", identity="tnc", fragment_size=str(frag),
+                           wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD",
+                                    "CTRL-EVENT-EAP-STATUS"], timeout=5)
+            if ev is None:
+                raise Exception("Timeout on EAP method start")
+            time.sleep(0.1)
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected(timeout=1)
+            dev[0].dump_monitor()
+    finally:
+        stop_radius_server(srv)
+
+def test_eap_canned_success_after_identity(dev, apdev):
+    """EAP protocol tests for canned EAP-Success after identity"""
+    check_eap_capa(dev[0], "MD5")
+    def eap_canned_success_handler(ctx, req):
+        logger.info("eap_canned_success_handler - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] = ctx['num'] + 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+        idx = 0
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unsupported payload (non-critical and critical)")
-            ike = struct.pack(">BBHBBH", 129, 0, 4, 0, 0x01, 4)
-            return build_ike(ctx['id'], next=128, ike=ike)
+            logger.info("Test: EAP-Success")
+            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Certificate and empty SAi1")
-            ike = struct.pack(">BBHBBH", 33, 0, 4, 0, 0, 4)
-            return build_ike(ctx['id'], next=37, ike=ike)
+            logger.info("Test: EAP-Success")
+            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
+
+        return None
+
+    srv = start_radius_server(eap_canned_success_handler)
+
+    try:
+        hapd = start_ap(apdev[0])
+
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       phase1="allow_canned_success=1",
+                       eap="MD5", identity="user", password="password",
+                       wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
+        if ev is None:
+            raise Exception("Timeout on EAP success")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="MD5", identity="user", password="password",
+                       wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
+        if ev is None:
+            raise Exception("Timeout on EAP start")
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=0.1)
+        if ev is not None:
+            raise Exception("Unexpected EAP success")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+    finally:
+        stop_radius_server(srv)
+
+def test_eap_proto_wsc(dev, apdev):
+    """EAP-WSC protocol tests"""
+    global eap_proto_wsc_test_done, eap_proto_wsc_wait_failure
+    eap_proto_wsc_test_done = False
 
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Too short proposal")
-            ike = struct.pack(">BBHBBHBBB", 0, 0, 4 + 7,
-                              0, 0, 7, 0, 0, 0)
-            return build_ike(ctx['id'], next=33, ike=ike)
+    def wsc_handler(ctx, req):
+        logger.info("wsc_handler - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] += 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+        idx = 0
 
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Too small proposal length in SAi1")
-            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
-                              0, 0, 7, 0, 0, 0, 0)
-            return build_ike(ctx['id'], next=33, ike=ike)
+        global eap_proto_wsc_wait_failure
+        eap_proto_wsc_wait_failure = False
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Too large proposal length in SAi1")
-            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
-                              0, 0, 9, 0, 0, 0, 0)
-            return build_ike(ctx['id'], next=33, ike=ike)
+            logger.info("Test: Missing Flags field")
+            return struct.pack(">BBHB3BLB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 1,
+                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
+                               1)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected proposal type in SAi1")
-            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
-                              1, 0, 8, 0, 0, 0, 0)
-            return build_ike(ctx['id'], next=33, ike=ike)
+            logger.info("Test: Message underflow (missing Message Length field)")
+            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 2,
+                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
+                               1, 0x02)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected Protocol ID in SAi1")
-            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
-                              0, 0, 8, 0, 0, 0, 0)
-            return build_ike(ctx['id'], next=33, ike=ike)
+            logger.info("Test: Invalid Message Length (> 50000)")
+            return struct.pack(">BBHB3BLBBH", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 4,
+                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
+                               1, 0x02, 65535)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected proposal number in SAi1")
-            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
-                              0, 0, 8, 0, 1, 0, 0)
-            return build_ike(ctx['id'], next=33, ike=ike)
+            logger.info("Test: Invalid Message Length (< current payload)")
+            return struct.pack(">BBHB3BLBBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 5,
+                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
+                               1, 0x02, 0, 0xff)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Not enough room for SPI in SAi1")
-            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
-                              0, 0, 8, 1, 1, 1, 0)
-            return build_ike(ctx['id'], next=33, ike=ike)
+            logger.info("Test: Unexpected Op-Code 5 in WAIT_START state")
+            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 2,
+                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
+                               5, 0x00)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected SPI in SAi1")
-            ike = struct.pack(">BBHBBHBBBBB", 0, 0, 4 + 9,
-                              0, 0, 9, 1, 1, 1, 0, 1)
-            return build_ike(ctx['id'], next=33, ike=ike)
-
+            logger.info("Test: Valid WSC Start to start the sequence")
+            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 2,
+                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
+                               1, 0x00)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: No transforms in SAi1")
-            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
-                              0, 0, 8, 1, 1, 0, 0)
-            return build_ike(ctx['id'], next=33, ike=ike)
+            logger.info("Test: No Message Length field in a fragmented packet")
+            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 2,
+                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
+                               4, 0x01)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Too short transform in SAi1")
-            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
-                              0, 0, 8, 1, 1, 0, 1)
-            return build_ike(ctx['id'], next=33, ike=ike)
-
+            logger.info("Test: Valid WSC Start to start the sequence")
+            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 2,
+                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
+                               1, 0x00)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Too small transform length in SAi1")
-            ike = struct.pack(">BBHBBHBBBBBBHBBH", 0, 0, 4 + 8 + 8,
-                              0, 0, 8 + 8, 1, 1, 0, 1,
-                              0, 0, 7, 0, 0, 0)
-            return build_ike(ctx['id'], next=33, ike=ike)
-
+            logger.info("Test: Valid first fragmented packet")
+            return struct.pack(">BBHB3BLBBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 5,
+                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
+                               4, 0x03, 10, 1)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Too large transform length in SAi1")
-            ike = struct.pack(">BBHBBHBBBBBBHBBH", 0, 0, 4 + 8 + 8,
-                              0, 0, 8 + 8, 1, 1, 0, 1,
-                              0, 0, 9, 0, 0, 0)
-            return build_ike(ctx['id'], next=33, ike=ike)
+            logger.info("Test: Unexpected Op-Code 5 in fragment (expected 4)")
+            return struct.pack(">BBHB3BLBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 3,
+                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
+                               5, 0x01, 2)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Unexpected Transform type in SAi1")
-            ike = struct.pack(">BBHBBHBBBBBBHBBH", 0, 0, 4 + 8 + 8,
-                              0, 0, 8 + 8, 1, 1, 0, 1,
-                              1, 0, 8, 0, 0, 0)
-            return build_ike(ctx['id'], next=33, ike=ike)
-
+            logger.info("Test: Valid WSC Start to start the sequence")
+            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 2,
+                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
+                               1, 0x00)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: No transform attributes in SAi1")
-            ike = struct.pack(">BBHBBHBBBBBBHBBH", 0, 0, 4 + 8 + 8,
-                              0, 0, 8 + 8, 1, 1, 0, 1,
-                              0, 0, 8, 0, 0, 0)
-            return build_ike(ctx['id'], next=33, ike=ike)
-
+            logger.info("Test: Valid first fragmented packet")
+            return struct.pack(">BBHB3BLBBHB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 5,
+                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
+                               4, 0x03, 2, 1)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: No transform attr for AES and unexpected data after transforms in SAi1")
-            tlen1 = 8 + 3
-            tlen2 = 8 + 4
-            tlen3 = 8 + 4
-            tlen = tlen1 + tlen2 + tlen3
-            ike = struct.pack(">BBHBBHBBBBBBHBBH3BBBHBBHHHBBHBBHHHB",
-                              0, 0, 4 + 8 + tlen + 1,
-                              0, 0, 8 + tlen + 1, 1, 1, 0, 3,
-                              3, 0, tlen1, 1, 0, 12, 1, 2, 3,
-                              3, 0, tlen2, 1, 0, 12, 0, 128,
-                              0, 0, tlen3, 1, 0, 12, 0x8000 | 14, 127,
-                              1)
-            return build_ike(ctx['id'], next=33, ike=ike)
-
-        def build_sa(next=0):
-            tlen = 5 * 8
-            return struct.pack(">BBHBBHBBBBBBHBBHBBHBBHBBHBBHBBHBBHBBHBBH",
-                               next, 0, 4 + 8 + tlen,
-                               0, 0, 8 + tlen, 1, 1, 0, 5,
-                               3, 0, 8, 1, 0, 3,
-                               3, 0, 8, 2, 0, 1,
-                               3, 0, 8, 3, 0, 1,
-                               3, 0, 8, 4, 0, 5,
-                               0, 0, 8, 241, 0, 0)
+            logger.info("Test: Fragment overflow")
+            return struct.pack(">BBHB3BLBBBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 4,
+                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
+                               4, 0x01, 2, 3)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Valid proposal, but no KEi in SAi1")
-            ike = build_sa()
-            return build_ike(ctx['id'], next=33, ike=ike)
-
+            logger.info("Test: Valid WSC Start to start the sequence")
+            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 2,
+                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
+                               1, 0x00)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Empty KEi in SAi1")
-            ike = build_sa(next=34) + struct.pack(">BBH", 0, 0, 4)
-            return build_ike(ctx['id'], next=33, ike=ike)
+            logger.info("Test: Unexpected Op-Code 5 in WAIT_FRAG_ACK state")
+            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 2,
+                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
+                               5, 0x00)
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Mismatch in DH Group in SAi1")
-            ike = build_sa(next=34)
-            ike += struct.pack(">BBHHH", 0, 0, 4 + 4 + 96, 12345, 0)
-            ike += 96*'\x00'
-            return build_ike(ctx['id'], next=33, ike=ike)
+            logger.info("Test: Valid WSC Start")
+            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 3 + 4 + 2,
+                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
+                               1, 0x00)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
+            logger.info("No more test responses available - test case completed")
+            global eap_proto_wsc_test_done
+            eap_proto_wsc_test_done = True
+            eap_proto_wsc_wait_failure = True
             return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Invalid DH public value length in SAi1")
-            ike = build_sa(next=34)
-            ike += struct.pack(">BBHHH", 0, 0, 4 + 4 + 96, 5, 0)
-            ike += 96*'\x00'
-            return build_ike(ctx['id'], next=33, ike=ike)
+        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
-        def build_ke(next=0):
-            ke = struct.pack(">BBHHH", next, 0, 4 + 4 + 192, 5, 0)
-            ke += 192*'\x00'
-            return ke
+    srv = start_radius_server(wsc_handler)
 
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Valid proposal and KEi, but no Ni in SAi1")
-            ike = build_sa(next=34)
-            ike += build_ke()
-            return build_ike(ctx['id'], next=33, ike=ike)
+    try:
+        hapd = start_ap(apdev[0])
+
+        i = 0
+        while not eap_proto_wsc_test_done:
+            i += 1
+            logger.info("Running connection iteration %d" % i)
+            fragment_size = 1398 if i != 9 else 50
+            dev[0].connect("eap-test", key_mgmt="WPA-EAP", eap="WSC",
+                           fragment_size=str(fragment_size),
+                           identity="WFA-SimpleConfig-Enrollee-1-0",
+                           phase1="pin=12345670",
+                           scan_freq="2412", wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
+            if ev is None:
+                raise Exception("Timeout on EAP method start")
+            if eap_proto_wsc_wait_failure:
+                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+                if ev is None:
+                    raise Exception("Timeout on EAP failure")
+            else:
+                time.sleep(0.1)
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected(timeout=1)
+            dev[0].dump_monitor()
+    finally:
+        stop_radius_server(srv)
 
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Too short Ni in SAi1")
-            ike = build_sa(next=34)
-            ike += build_ke(next=40)
-            ike += struct.pack(">BBH", 0, 0, 4)
-            return build_ike(ctx['id'], next=33, ike=ike)
+def test_eap_canned_success_before_method(dev, apdev):
+    """EAP protocol tests for canned EAP-Success before any method"""
+    params = int_eap_server_params()
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+    hapd.request("SET ext_eapol_frame_io 1")
+
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
+                   phase1="allow_canned_success=1",
+                   eap="MD5", identity="user", password="password",
+                   wait_connect=False)
+
+    ev = hapd.wait_event(["EAPOL-TX"], timeout=10)
+    if ev is None:
+        raise Exception("Timeout on EAPOL-TX from hostapd")
+
+    res = dev[0].request("EAPOL_RX " + bssid + " 0200000403020004")
+    if "OK" not in res:
+        raise Exception("EAPOL_RX to wpa_supplicant failed")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on EAP success")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+def test_eap_canned_failure_before_method(dev, apdev):
+    """EAP protocol tests for canned EAP-Failure before any method"""
+    params = int_eap_server_params()
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+    hapd.request("SET ext_eapol_frame_io 1")
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
+                   phase1="allow_canned_success=1",
+                   eap="MD5", identity="user", password="password",
+                   wait_connect=False)
+
+    ev = hapd.wait_event(["EAPOL-TX"], timeout=10)
+    if ev is None:
+        raise Exception("Timeout on EAPOL-TX from hostapd")
+
+    res = dev[0].request("EAPOL_RX " + bssid + " 0200000404020004")
+    if "OK" not in res:
+        raise Exception("EAPOL_RX to wpa_supplicant failed")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
+    if ev is None:
+        raise Exception("Timeout on EAP failure")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+def test_eap_nak_oom(dev, apdev):
+    """EAP-Nak OOM"""
+    check_eap_capa(dev[0], "MD5")
+    params = hostapd.wpa2_eap_params(ssid="eap-test")
+    hapd = hostapd.add_ap(apdev[0], params)
+    with alloc_fail(dev[0], 1, "eap_msg_alloc;eap_sm_buildNak"):
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="MD5", identity="sake user", password="password",
+                       wait_connect=False)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
 
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: Too long Ni in SAi1")
-            ike = build_sa(next=34)
-            ike += build_ke(next=40)
-            ike += struct.pack(">BBH", 0, 0, 4 + 257) + 257*'\x00'
-            return build_ike(ctx['id'], next=33, ike=ike)
+def test_eap_nak_expanded(dev, apdev):
+    """EAP-Nak with expanded method"""
+    check_eap_capa(dev[0], "MD5")
+    check_eap_capa(dev[0], "VENDOR-TEST")
+    params = hostapd.wpa2_eap_params(ssid="eap-test")
+    hapd = hostapd.add_ap(apdev[0], params)
+    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="VENDOR-TEST WSC",
+                   identity="sake user", password="password",
+                   wait_connect=False)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=10)
+    if ev is None or "NAK" not in ev:
+        raise Exception("No NAK event seen")
+
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=10)
+    if ev is None:
+        raise Exception("No EAP-Failure seen")
+
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+EAP_TLV_RESULT_TLV = 3
+EAP_TLV_NAK_TLV = 4
+EAP_TLV_ERROR_CODE_TLV = 5
+EAP_TLV_CONNECTION_BINDING_TLV = 6
+EAP_TLV_VENDOR_SPECIFIC_TLV = 7
+EAP_TLV_URI_TLV = 8
+EAP_TLV_EAP_PAYLOAD_TLV = 9
+EAP_TLV_INTERMEDIATE_RESULT_TLV = 10
+EAP_TLV_PAC_TLV = 11
+EAP_TLV_CRYPTO_BINDING_TLV = 12
+EAP_TLV_CALLING_STATION_ID_TLV = 13
+EAP_TLV_CALLED_STATION_ID_TLV = 14
+EAP_TLV_NAS_PORT_TYPE_TLV = 15
+EAP_TLV_SERVER_IDENTIFIER_TLV = 16
+EAP_TLV_IDENTITY_TYPE_TLV = 17
+EAP_TLV_SERVER_TRUSTED_ROOT_TLV = 18
+EAP_TLV_REQUEST_ACTION_TLV = 19
+EAP_TLV_PKCS7_TLV = 20
+
+EAP_TLV_RESULT_SUCCESS = 1
+EAP_TLV_RESULT_FAILURE = 2
+
+EAP_TLV_TYPE_MANDATORY = 0x8000
+EAP_TLV_TYPE_MASK = 0x3fff
+
+PAC_TYPE_PAC_KEY = 1
+PAC_TYPE_PAC_OPAQUE = 2
+PAC_TYPE_CRED_LIFETIME = 3
+PAC_TYPE_A_ID = 4
+PAC_TYPE_I_ID = 5
+PAC_TYPE_A_ID_INFO = 7
+PAC_TYPE_PAC_ACKNOWLEDGEMENT = 8
+PAC_TYPE_PAC_INFO = 9
+PAC_TYPE_PAC_TYPE = 10
+
+def eap_fast_start(ctx):
+    logger.info("Send EAP-FAST/Start")
+    return struct.pack(">BBHBBHH", EAP_CODE_REQUEST, ctx['id'],
+                       4 + 1 + 1 + 4 + 16,
+                       EAP_TYPE_FAST, 0x21, 4, 16) + 16*'A'
+
+def test_eap_fast_proto(dev, apdev):
+    """EAP-FAST Phase protocol testing"""
+    check_eap_capa(dev[0], "FAST")
+    global eap_fast_proto_ctx
+    eap_fast_proto_ctx = None
 
-        def build_ni(next=0):
-            return struct.pack(">BBH", next, 0, 4 + 256) + 256*'\x00'
+    def eap_handler(ctx, req):
+        logger.info("eap_handler - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] = ctx['num'] + 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+        idx = 0
 
-        def build_sai1(id):
-            ike = build_sa(next=34)
-            ike += build_ke(next=40)
-            ike += build_ni()
-            return build_ike(ctx['id'], next=33, ike=ike)
+        global eap_fast_proto_ctx
+        eap_fast_proto_ctx = ctx
+        ctx['test_done'] = False
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Valid proposal, KEi, and Ni in SAi1")
-            return build_sai1(ctx['id'])
-        idx += 1
-        if ctx['num'] == idx:
-            logger.info("Test: EAP-Failure")
-            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
-
+            return eap_fast_start(ctx)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Valid proposal, KEi, and Ni in SAi1")
-            return build_sai1(ctx['id'])
+            logger.info("EAP-FAST: TLS processing failed")
+            data = 'ABCDEFGHIK'
+            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                               4 + 1 + 1 + len(data),
+                               EAP_TYPE_FAST, 0x01) + data
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: No integrity checksum")
-            ike = ''
-            return build_ike(ctx['id'], next=37, ike=ike)
+            ctx['test_done'] = True
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+        logger.info("Past last test case")
+        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
+
+    srv = start_radius_server(eap_handler)
+    try:
+        hapd = start_ap(apdev[0])
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="FAST", anonymous_identity="FAST",
+                       identity="user", password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                       phase1="fast_provisioning=1",
+                       pac_file="blob://fast_pac_proto",
+                       wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
+        if ev is None:
+            raise Exception("Could not start EAP-FAST")
+        ok = False
+        for i in range(100):
+            if eap_fast_proto_ctx:
+                if eap_fast_proto_ctx['test_done']:
+                    ok = True
+                    break
+            time.sleep(0.05)
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+    finally:
+        stop_radius_server(srv)
+
+def run_eap_fast_phase2(dev, test_payload, test_failure=True):
+    global eap_fast_proto_ctx
+    eap_fast_proto_ctx = None
+
+    def ssl_info_callback(conn, where, ret):
+        logger.debug("SSL: info where=%d ret=%d" % (where, ret))
+
+    def process_clienthello(ctx, payload):
+        logger.info("Process ClientHello")
+        ctx['sslctx'] = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD)
+        ctx['sslctx'].set_info_callback(ssl_info_callback)
+        ctx['sslctx'].load_tmp_dh("auth_serv/dh.conf")
+        ctx['sslctx'].set_cipher_list("ADH-AES128-SHA")
+        ctx['conn'] = OpenSSL.SSL.Connection(ctx['sslctx'], None)
+        ctx['conn'].set_accept_state()
+        logger.info("State: " + ctx['conn'].state_string())
+        ctx['conn'].bio_write(payload)
+        try:
+            ctx['conn'].do_handshake()
+        except OpenSSL.SSL.WantReadError:
+            pass
+        logger.info("State: " + ctx['conn'].state_string())
+        data = ctx['conn'].bio_read(4096)
+        logger.info("State: " + ctx['conn'].state_string())
+        return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                           4 + 1 + 1 + len(data),
+                           EAP_TYPE_FAST, 0x01) + data
+
+    def process_clientkeyexchange(ctx, payload, appl_data):
+        logger.info("Process ClientKeyExchange")
+        logger.info("State: " + ctx['conn'].state_string())
+        ctx['conn'].bio_write(payload)
+        try:
+            ctx['conn'].do_handshake()
+        except OpenSSL.SSL.WantReadError:
+            pass
+        ctx['conn'].send(appl_data)
+        logger.info("State: " + ctx['conn'].state_string())
+        data = ctx['conn'].bio_read(4096)
+        logger.info("State: " + ctx['conn'].state_string())
+        return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
+                           4 + 1 + 1 + len(data),
+                           EAP_TYPE_FAST, 0x01) + data
+
+    def eap_handler(ctx, req):
+        logger.info("eap_handler - RX " + req.encode("hex"))
+        if 'num' not in ctx:
+            ctx['num'] = 0
+        ctx['num'] = ctx['num'] + 1
+        if 'id' not in ctx:
+            ctx['id'] = 1
+        ctx['id'] = (ctx['id'] + 1) % 256
+        idx = 0
+
+        global eap_fast_proto_ctx
+        eap_fast_proto_ctx = ctx
+        ctx['test_done'] = False
+        logger.debug("ctx['num']=%d" % ctx['num'])
 
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Valid proposal, KEi, and Ni in SAi1")
-            return build_sai1(ctx['id'])
+            return eap_fast_start(ctx)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Truncated integrity checksum")
-            return struct.pack(">BBHBB",
-                               EAP_CODE_REQUEST, ctx['id'],
-                               4 + 1 + 1,
-                               EAP_TYPE_IKEV2, 0x20)
-
+            return process_clienthello(ctx, req[6:])
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Valid proposal, KEi, and Ni in SAi1")
-            return build_sai1(ctx['id'])
+            if not test_failure:
+                ctx['test_done'] = True
+            return process_clientkeyexchange(ctx, req[6:], test_payload)
         idx += 1
         if ctx['num'] == idx:
-            logger.info("Test: Invalid integrity checksum")
-            ike = ''
-            return build_ike(ctx['id'], next=37, flags=0x20, ike=ike)
-
-        return None
+            ctx['test_done'] = True
+            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
-    srv = start_radius_server(ikev2_handler)
+        logger.info("Past last test case")
+        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
 
+    srv = start_radius_server(eap_handler)
     try:
-        hapd = start_ap(apdev[0]['ifname'])
-
-        for i in range(49):
-            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
-                           eap="IKEV2", identity="user",
-                           password="password",
-                           wait_connect=False)
-            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
-                                   timeout=15)
-            if ev is None:
-                raise Exception("Timeout on EAP start")
-            if i in [ 40, 45 ]:
-                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
-                                       timeout=10)
-                if ev is None:
-                    raise Exception("Timeout on EAP failure")
-            else:
-                time.sleep(0.05)
-            dev[0].request("REMOVE_NETWORK all")
+        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
+                       eap="FAST", anonymous_identity="FAST",
+                       identity="user", password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+                       phase1="fast_provisioning=1",
+                       pac_file="blob://fast_pac_proto",
+                       wait_connect=False)
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
+        if ev is None:
+            raise Exception("Could not start EAP-FAST")
+        dev[0].dump_monitor()
+        ok = False
+        for i in range(100):
+            if eap_fast_proto_ctx:
+                if eap_fast_proto_ctx['test_done']:
+                    ok = True
+                    break
+            time.sleep(0.05)
+        time.sleep(0.1)
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+        if not ok:
+            raise Exception("EAP-FAST TLS exchange did not complete")
+        for i in range(3):
+            dev[i].dump_monitor()
     finally:
         stop_radius_server(srv)
+
+def test_eap_fast_proto_phase2(dev, apdev):
+    """EAP-FAST Phase 2 protocol testing"""
+    if not openssl_imported:
+        raise HwsimSkip("OpenSSL python method not available")
+    check_eap_capa(dev[0], "FAST")
+    hapd = start_ap(apdev[0])
+
+    tests = [ ("Too short Phase 2 TLV frame (len=3)",
+               "ABC",
+               False),
+              ("EAP-FAST: TLV overflow",
+               struct.pack(">HHB", 0, 2, 0xff),
+               False),
+              ("EAP-FAST: Unknown TLV (optional and mandatory)",
+               struct.pack(">HHB", 0, 1, 0xff) +
+               struct.pack(">HHB", EAP_TLV_TYPE_MANDATORY, 1, 0xff),
+               True),
+              ("EAP-FAST: More than one EAP-Payload TLV in the message",
+               struct.pack(">HHBHHB",
+                           EAP_TLV_EAP_PAYLOAD_TLV, 1, 0xff,
+                           EAP_TLV_EAP_PAYLOAD_TLV, 1, 0xff),
+               True),
+              ("EAP-FAST: Unknown Result 255 and More than one Result TLV in the message",
+               struct.pack(">HHHHHH",
+                           EAP_TLV_RESULT_TLV, 2, 0xff,
+                           EAP_TLV_RESULT_TLV, 2, 0xff),
+               True),
+              ("EAP-FAST: Too short Result TLV",
+               struct.pack(">HHB", EAP_TLV_RESULT_TLV, 1, 0xff),
+               True),
+              ("EAP-FAST: Unknown Intermediate Result 255 and More than one Intermediate-Result TLV in the message",
+               struct.pack(">HHHHHH",
+                           EAP_TLV_INTERMEDIATE_RESULT_TLV, 2, 0xff,
+                           EAP_TLV_INTERMEDIATE_RESULT_TLV, 2, 0xff),
+               True),
+              ("EAP-FAST: Too short Intermediate-Result TLV",
+               struct.pack(">HHB", EAP_TLV_INTERMEDIATE_RESULT_TLV, 1, 0xff),
+               True),
+              ("EAP-FAST: More than one Crypto-Binding TLV in the message",
+               struct.pack(">HH", EAP_TLV_CRYPTO_BINDING_TLV, 60) + 60*'A' +
+               struct.pack(">HH", EAP_TLV_CRYPTO_BINDING_TLV, 60) + 60*'A',
+               True),
+              ("EAP-FAST: Too short Crypto-Binding TLV",
+               struct.pack(">HHB", EAP_TLV_CRYPTO_BINDING_TLV, 1, 0xff),
+               True),
+              ("EAP-FAST: More than one Request-Action TLV in the message",
+               struct.pack(">HHBBHHBB",
+                           EAP_TLV_REQUEST_ACTION_TLV, 2, 0xff, 0xff,
+                           EAP_TLV_REQUEST_ACTION_TLV, 2, 0xff, 0xff),
+               True),
+              ("EAP-FAST: Too short Request-Action TLV",
+               struct.pack(">HHB", EAP_TLV_REQUEST_ACTION_TLV, 1, 0xff),
+               True),
+              ("EAP-FAST: More than one PAC TLV in the message",
+               struct.pack(">HHBHHB",
+                           EAP_TLV_PAC_TLV, 1, 0xff,
+                           EAP_TLV_PAC_TLV, 1, 0xff),
+               True),
+              ("EAP-FAST: Too short EAP Payload TLV (Len=3)",
+               struct.pack(">HH3B",
+                           EAP_TLV_EAP_PAYLOAD_TLV, 3, 0, 0, 0),
+               False),
+              ("EAP-FAST: Too short Phase 2 request (Len=0)",
+               struct.pack(">HHBBH",
+                           EAP_TLV_EAP_PAYLOAD_TLV, 4,
+                           EAP_CODE_REQUEST, 0, 0),
+               False),
+              ("EAP-FAST: EAP packet overflow in EAP Payload TLV",
+               struct.pack(">HHBBH",
+                           EAP_TLV_EAP_PAYLOAD_TLV, 4,
+                           EAP_CODE_REQUEST, 0, 4 + 1),
+               False),
+              ("EAP-FAST: Unexpected code=0 in Phase 2 EAP header",
+               struct.pack(">HHBBH",
+                           EAP_TLV_EAP_PAYLOAD_TLV, 4,
+                           0, 0, 0),
+               False),
+              ("EAP-FAST: PAC TLV without Result TLV acknowledging success",
+               struct.pack(">HHB", EAP_TLV_PAC_TLV, 1, 0xff),
+               True),
+              ("EAP-FAST: PAC TLV does not include all the required fields",
+               struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
+                           EAP_TLV_RESULT_SUCCESS) +
+               struct.pack(">HHB", EAP_TLV_PAC_TLV, 1, 0xff),
+               True),
+              ("EAP-FAST: Invalid PAC-Key length 0, Ignored unknown PAC type 0, and PAC TLV overrun (type=0 len=2 left=1)",
+               struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
+                           EAP_TLV_RESULT_SUCCESS) +
+               struct.pack(">HHHHHHHHB", EAP_TLV_PAC_TLV, 4 + 4 + 5,
+                           PAC_TYPE_PAC_KEY, 0, 0, 0, 0, 2, 0),
+               True),
+              ("EAP-FAST: PAC-Info does not include all the required fields",
+               struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
+                           EAP_TLV_RESULT_SUCCESS) +
+               struct.pack(">HHHHHHHH", EAP_TLV_PAC_TLV, 4 + 4 + 4 + 32,
+                           PAC_TYPE_PAC_OPAQUE, 0,
+                           PAC_TYPE_PAC_INFO, 0,
+                           PAC_TYPE_PAC_KEY, 32) + 32*'A',
+               True),
+              ("EAP-FAST: Invalid CRED_LIFETIME length, Ignored unknown PAC-Info type 0, and Invalid PAC-Type length 1",
+               struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
+                           EAP_TLV_RESULT_SUCCESS) +
+               struct.pack(">HHHHHHHHHHHHBHH", EAP_TLV_PAC_TLV, 4 + 4 + 13 + 4 + 32,
+                           PAC_TYPE_PAC_OPAQUE, 0,
+                           PAC_TYPE_PAC_INFO, 13, PAC_TYPE_CRED_LIFETIME, 0,
+                           0, 0, PAC_TYPE_PAC_TYPE, 1, 0,
+                           PAC_TYPE_PAC_KEY, 32) + 32*'A',
+               True),
+              ("EAP-FAST: Unsupported PAC-Type 0",
+               struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
+                           EAP_TLV_RESULT_SUCCESS) +
+               struct.pack(">HHHHHHHHHHH", EAP_TLV_PAC_TLV, 4 + 4 + 6 + 4 + 32,
+                           PAC_TYPE_PAC_OPAQUE, 0,
+                           PAC_TYPE_PAC_INFO, 6, PAC_TYPE_PAC_TYPE, 2, 0,
+                           PAC_TYPE_PAC_KEY, 32) + 32*'A',
+               True),
+              ("EAP-FAST: PAC-Info overrun (type=0 len=2 left=1)",
+               struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
+                           EAP_TLV_RESULT_SUCCESS) +
+               struct.pack(">HHHHHHHHBHH", EAP_TLV_PAC_TLV, 4 + 4 + 5 + 4 + 32,
+                           PAC_TYPE_PAC_OPAQUE, 0,
+                           PAC_TYPE_PAC_INFO, 5, 0, 2, 1,
+                           PAC_TYPE_PAC_KEY, 32) + 32*'A',
+               True),
+              ("EAP-FAST: Valid PAC",
+               struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
+                           EAP_TLV_RESULT_SUCCESS) +
+               struct.pack(">HHHHHHHHBHHBHH", EAP_TLV_PAC_TLV,
+                           4 + 4 + 10 + 4 + 32,
+                           PAC_TYPE_PAC_OPAQUE, 0,
+                           PAC_TYPE_PAC_INFO, 10, PAC_TYPE_A_ID, 1, 0x41,
+                           PAC_TYPE_A_ID_INFO, 1, 0x42,
+                           PAC_TYPE_PAC_KEY, 32) + 32*'A',
+               True),
+              ("EAP-FAST: Invalid version/subtype in Crypto-Binding TLV",
+               struct.pack(">HH", EAP_TLV_CRYPTO_BINDING_TLV, 60) + 60*'A',
+               True) ]
+    for title, payload, failure in tests:
+        logger.info("Phase 2 test: " + title)
+        run_eap_fast_phase2(dev, payload, failure)
+
+def test_eap_fast_tlv_nak_oom(dev, apdev):
+    """EAP-FAST Phase 2 TLV NAK OOM"""
+    if not openssl_imported:
+        raise HwsimSkip("OpenSSL python method not available")
+    check_eap_capa(dev[0], "FAST")
+    hapd = start_ap(apdev[0])
+
+    with alloc_fail(dev[0], 1, "eap_fast_tlv_nak"):
+        run_eap_fast_phase2(dev, struct.pack(">HHB", EAP_TLV_TYPE_MANDATORY,
+                                             1, 0xff), False)
index c4f2fa5..f41b4ba 100644 (file)
@@ -11,7 +11,7 @@ import os
 import time
 
 import hostapd
-from utils import HwsimSkip
+from utils import HwsimSkip, alloc_fail, fail_test, wait_fail_trigger
 from test_ap_eap import int_eap_server_params
 from test_ap_psk import find_wpas_process, read_process_memory, verify_not_present, get_key_locations
 
@@ -25,7 +25,7 @@ def test_erp_initiate_reauth_start(dev, apdev):
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params['erp_send_reauth_start'] = '1'
     params['erp_domain'] = 'example.com'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].request("ERP_FLUSH")
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
@@ -39,7 +39,7 @@ def test_erp_enabled_on_server(dev, apdev):
     params['erp_send_reauth_start'] = '1'
     params['erp_domain'] = 'example.com'
     params['eap_server_erp'] = '1'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].request("ERP_FLUSH")
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
@@ -55,7 +55,7 @@ def test_erp(dev, apdev):
     params['erp_domain'] = 'example.com'
     params['eap_server_erp'] = '1'
     params['disable_pmksa_caching'] = '1'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].request("ERP_FLUSH")
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
@@ -81,7 +81,7 @@ def test_erp_server_no_match(dev, apdev):
     params['erp_domain'] = 'example.com'
     params['eap_server_erp'] = '1'
     params['disable_pmksa_caching'] = '1'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].request("ERP_FLUSH")
     id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
@@ -123,7 +123,7 @@ def start_erp_as(apdev):
                "eap_fast_a_id_info": "test server",
                "eap_server_erp": "1",
                "erp_domain": "example.com" }
-    hostapd.add_ap(apdev['ifname'], params)
+    hostapd.add_ap(apdev, params)
 
 def test_erp_radius(dev, apdev):
     """ERP enabled on RADIUS server and peer"""
@@ -134,7 +134,7 @@ def test_erp_radius(dev, apdev):
     params['erp_send_reauth_start'] = '1'
     params['erp_domain'] = 'example.com'
     params['disable_pmksa_caching'] = '1'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].request("ERP_FLUSH")
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
@@ -187,7 +187,7 @@ def test_erp_radius_eap_methods(dev, apdev):
     params['erp_send_reauth_start'] = '1'
     params['erp_domain'] = 'example.com'
     params['disable_pmksa_caching'] = '1'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     erp_test(dev[0], hapd, eap="AKA", identity="0232010000000000@example.com",
              password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123")
@@ -235,7 +235,7 @@ def test_erp_key_lifetime_in_memory(dev, apdev, params):
     p['erp_domain'] = 'example.com'
     p['eap_server_erp'] = '1'
     p['disable_pmksa_caching'] = '1'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], p)
+    hapd = hostapd.add_ap(apdev[0], p)
     password = "63d2d21ac3c09ed567ee004a34490f1d16e7fa5835edf17ddba70a63f1a90a25"
 
     pid = find_wpas_process(dev[0])
@@ -246,7 +246,11 @@ def test_erp_key_lifetime_in_memory(dev, apdev, params):
                    ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
                    erp="1", scan_freq="2412")
 
+    # The decrypted copy of GTK is freed only after the CTRL-EVENT-CONNECTED
+    # event has been delivered, so verify that wpa_supplicant has returned to
+    # eloop before reading process memory.
     time.sleep(1)
+    dev[0].ping()
     buf = read_process_memory(pid, password)
 
     dev[0].request("DISCONNECT")
@@ -313,6 +317,7 @@ def test_erp_key_lifetime_in_memory(dev, apdev, params):
     if tk in buf:
         raise Exception("TK found from memory")
     if gtk in buf:
+        get_key_locations(buf, gtk, "GTK")
         raise Exception("GTK found from memory")
 
     logger.info("Checking keys in memory after disassociation")
@@ -410,3 +415,207 @@ def test_erp_key_lifetime_in_memory(dev, apdev, params):
     get_key_locations(buf, rIK, "rIK")
     verify_not_present(buf, rRK, fname, "rRK")
     verify_not_present(buf, rIK, fname, "rIK")
+
+def test_erp_anonymous_identity(dev, apdev):
+    """ERP and anonymous identity"""
+    check_erp_capa(dev[0])
+    params = int_eap_server_params()
+    params['erp_send_reauth_start'] = '1'
+    params['erp_domain'] = 'example.com'
+    params['eap_server_erp'] = '1'
+    params['disable_pmksa_caching'] = '1'
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].request("ERP_FLUSH")
+    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                   identity="erp-ttls",
+                   anonymous_identity="anonymous@example.com",
+                   password="password",
+                   ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
+                   erp="1", scan_freq="2412")
+    for i in range(3):
+        dev[0].request("DISCONNECT")
+        dev[0].wait_disconnected(timeout=15)
+        dev[0].request("RECONNECT")
+        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
+        if ev is None:
+            raise Exception("EAP success timed out")
+        if "EAP re-authentication completed successfully" not in ev:
+            raise Exception("Did not use ERP")
+        dev[0].wait_connected(timeout=15, error="Reconnection timed out")
+
+def test_erp_home_realm_oom(dev, apdev):
+    """ERP and home realm OOM"""
+    check_erp_capa(dev[0])
+    params = int_eap_server_params()
+    params['erp_send_reauth_start'] = '1'
+    params['erp_domain'] = 'example.com'
+    params['eap_server_erp'] = '1'
+    params['disable_pmksa_caching'] = '1'
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    for count in range(1, 3):
+        with alloc_fail(dev[0], count, "eap_home_realm"):
+            dev[0].request("ERP_FLUSH")
+            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                           identity="erp-ttls@example.com",
+                           anonymous_identity="anonymous@example.com",
+                           password="password",
+                           ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
+                           erp="1", scan_freq="2412", wait_connect=False)
+            dev[0].wait_connected(timeout=10)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    for count in range(1, 3):
+        with alloc_fail(dev[0], count, "eap_home_realm"):
+            dev[0].request("ERP_FLUSH")
+            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                           identity="erp-ttls",
+                           anonymous_identity="anonymous@example.com",
+                           password="password",
+                           ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
+                           erp="1", scan_freq="2412", wait_connect=False)
+            dev[0].wait_connected(timeout=10)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    for count in range(1, 3):
+        dev[0].request("ERP_FLUSH")
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                       identity="erp-ttls@example.com",
+                       anonymous_identity="anonymous@example.com",
+                       password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
+                       erp="1", scan_freq="2412", wait_connect=False)
+        dev[0].wait_connected(timeout=10)
+        if range > 1:
+            continue
+        with alloc_fail(dev[0], count, "eap_home_realm"):
+            dev[0].request("DISCONNECT")
+            dev[0].wait_disconnected(timeout=15)
+            dev[0].request("RECONNECT")
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+def test_erp_local_errors(dev, apdev):
+    """ERP and local error cases"""
+    check_erp_capa(dev[0])
+    params = int_eap_server_params()
+    params['erp_send_reauth_start'] = '1'
+    params['erp_domain'] = 'example.com'
+    params['eap_server_erp'] = '1'
+    params['disable_pmksa_caching'] = '1'
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].request("ERP_FLUSH")
+    with alloc_fail(dev[0], 1, "eap_peer_erp_init"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                       identity="erp-ttls@example.com",
+                       anonymous_identity="anonymous@example.com",
+                       password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
+                       erp="1", scan_freq="2412")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    for count in range(1, 6):
+        dev[0].request("ERP_FLUSH")
+        with fail_test(dev[0], count, "hmac_sha256_kdf;eap_peer_erp_init"):
+            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                           identity="erp-ttls@example.com",
+                           anonymous_identity="anonymous@example.com",
+                           password="password",
+                           ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
+                           erp="1", scan_freq="2412")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    dev[0].request("ERP_FLUSH")
+    with alloc_fail(dev[0], 1, "eap_msg_alloc;eap_peer_erp_reauth_start"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                       identity="erp-ttls@example.com",
+                       anonymous_identity="anonymous@example.com",
+                       password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
+                       erp="1", scan_freq="2412")
+        dev[0].request("DISCONNECT")
+        dev[0].wait_disconnected(timeout=15)
+        dev[0].request("RECONNECT")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    dev[0].request("ERP_FLUSH")
+    with fail_test(dev[0], 1, "hmac_sha256;eap_peer_erp_reauth_start"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                       identity="erp-ttls@example.com",
+                       anonymous_identity="anonymous@example.com",
+                       password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
+                       erp="1", scan_freq="2412")
+        dev[0].request("DISCONNECT")
+        dev[0].wait_disconnected(timeout=15)
+        dev[0].request("RECONNECT")
+        wait_fail_trigger(dev[0], "GET_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    dev[0].request("ERP_FLUSH")
+    with fail_test(dev[0], 1, "hmac_sha256;eap_peer_finish"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                       identity="erp-ttls@example.com",
+                       anonymous_identity="anonymous@example.com",
+                       password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
+                       erp="1", scan_freq="2412")
+        dev[0].request("DISCONNECT")
+        dev[0].wait_disconnected(timeout=15)
+        dev[0].request("RECONNECT")
+        wait_fail_trigger(dev[0], "GET_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    dev[0].request("ERP_FLUSH")
+    with alloc_fail(dev[0], 1, "eap_peer_erp_init"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                       identity="erp-ttls@example.com",
+                       anonymous_identity="anonymous@example.com",
+                       password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
+                       erp="1", scan_freq="2412")
+        dev[0].request("DISCONNECT")
+        dev[0].wait_disconnected(timeout=15)
+
+    dev[0].request("ERP_FLUSH")
+    with alloc_fail(dev[0], 1, "eap_peer_finish"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                       identity="erp-ttls@example.com",
+                       anonymous_identity="anonymous@example.com",
+                       password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
+                       erp="1", scan_freq="2412")
+        dev[0].request("DISCONNECT")
+        dev[0].wait_disconnected(timeout=15)
+        dev[0].request("RECONNECT")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    dev[0].request("ERP_FLUSH")
+    with fail_test(dev[0], 1, "hmac_sha256_kdf;eap_peer_finish"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                       identity="erp-ttls@example.com",
+                       anonymous_identity="anonymous@example.com",
+                       password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
+                       erp="1", scan_freq="2412")
+        dev[0].request("DISCONNECT")
+        dev[0].wait_disconnected(timeout=15)
+        dev[0].request("RECONNECT")
+        wait_fail_trigger(dev[0], "GET_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
index c70895c..e89e51d 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 
@@ -14,17 +15,18 @@ from test_ap_hs20 import hs20_ap_params
 from test_ap_hs20 import interworking_select
 from test_ap_hs20 import interworking_connect
 
+@remote_compatible
 def test_ext_password_psk(dev, apdev):
     """External password storage for PSK"""
     params = hostapd.wpa2_params(ssid="ext-pw-psk", passphrase="12345678")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].request("SET ext_password_backend test:psk1=12345678")
     dev[0].connect("ext-pw-psk", raw_psk="ext:psk1", scan_freq="2412")
 
 def test_ext_password_psk_not_found(dev, apdev):
     """External password storage for PSK and PSK not found"""
     params = hostapd.wpa2_params(ssid="ext-pw-psk", passphrase="12345678")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].request("SET ext_password_backend test:psk1=12345678")
     dev[0].connect("ext-pw-psk", raw_psk="ext:psk2", scan_freq="2412",
                    wait_connect=False)
@@ -56,7 +58,7 @@ def test_ext_password_psk_not_found(dev, apdev):
 def test_ext_password_eap(dev, apdev):
     """External password storage for EAP password"""
     params = hostapd.wpa2_eap_params(ssid="ext-pw-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].request("SET ext_password_backend test:pw0=hello|pw1=password|pw2=secret")
     dev[0].connect("ext-pw-eap", key_mgmt="WPA-EAP", eap="PEAP",
                    identity="user", password_hex="ext:pw1",
@@ -68,7 +70,7 @@ def test_ext_password_interworking(dev, apdev):
     skip_with_fips(dev[0])
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].hs20_enable()
     dev[0].request("SET ext_password_backend test:pw1=password")
index 938cf9a..03287b2 100644 (file)
@@ -147,7 +147,7 @@ class FstLauncher:
             self.nof_aps -= 1
         else:
             self.nof_stas -= 1
-        config_file = self.get_cfg_pathname(cfg);
+        config_file = self.get_cfg_pathname(cfg)
         if os.path.exists(config_file):
             os.remove(config_file)
 
@@ -162,7 +162,7 @@ class FstLauncher:
                            'alt-hostapd/hostapd/hostapd')
         if not os.path.exists(prg):
             prg = '../../hostapd/hostapd'
-        cmd = [ prg, '-B', '-ddd',
+        cmd = [ prg, '-B', '-dddt',
                 '-P', pidfile, '-f', mylogfile, '-g', self.hapd_fst_global]
         for i in range(0, len(self.cfgs_to_run)):
             cfg = self.cfgs_to_run[i]
@@ -189,7 +189,7 @@ class FstLauncher:
                            'alt-wpa_supplicant/wpa_supplicant/wpa_supplicant')
         if not os.path.exists(prg):
             prg = '../../wpa_supplicant/wpa_supplicant'
-        cmd = [ prg, '-B', '-ddd',
+        cmd = [ prg, '-B', '-dddt',
                 '-P' + pidfile, '-f', mylogfile, '-g', self.wsup_fst_global ]
         sta_no = 0
         for i in range(0, len(self.cfgs_to_run)):
@@ -212,23 +212,39 @@ class FstLauncher:
         """Terminates hostapd/wpa_supplicant processes previously launched with
         run_hostapd/run_wpa_supplicant"""
         pidfile = self.fst_logpath + '/' + 'myhostapd.pid'
-        self.kill_pid(pidfile)
+        self.kill_pid(pidfile, self.nof_aps > 0)
         pidfile = self.fst_logpath + '/' + 'mywpa_supplicant.pid'
-        self.kill_pid(pidfile)
+        self.kill_pid(pidfile, self.nof_stas > 0)
         self.reg_ctrl.stop()
         while len(self.cfgs_to_run) != 0:
             cfg = self.cfgs_to_run[0]
             self.remove_cfg(cfg)
 
-    def kill_pid(self, pidfile):
+    def kill_pid(self, pidfile, try_again=False):
         """Kills process by PID file"""
         if not os.path.exists(pidfile):
-            return
+            if not try_again:
+                return
+            # It might take some time for the process to write the PID file,
+            # so wait a bit longer before giving up.
+            self.logger.info("kill_pid: pidfile %s does not exist - try again after a second" % pidfile)
+            time.sleep(1)
+            if not os.path.exists(pidfile):
+                self.logger.info("kill_pid: pidfile %s does not exist - could not kill the process" % pidfile)
+                return
         pid = -1
         try:
-            pf = file(pidfile, 'r')
-            pid = int(pf.read().strip())
-            pf.close()
+            for i in range(3):
+                pf = file(pidfile, 'r')
+                pidtxt = pf.read().strip()
+                self.logger.debug("kill_pid: %s: '%s'" % (pidfile, pidtxt))
+                pf.close()
+                try:
+                    pid = int(pidtxt)
+                    break
+                except Exception, e:
+                    self.logger.debug("kill_pid: No valid PID found: %s" % str(e))
+                    time.sleep(1)
             self.logger.debug("kill_pid %s --> pid %d" % (pidfile, pid))
             os.kill(pid, signal.SIGTERM)
             for i in range(10):
index 1f62db1..68a9685 100644 (file)
@@ -188,7 +188,7 @@ def fst_start_session(apdev, test_params, bad_param_type, start_on_ap,
                         exception_text = "Failure. Bad parameter was not detected (%s)" % bad_param_names[bad_param_type]
                     raise Exception(exception_text)
         else:
-            print "Failure. Unexpected exception"
+            logger.info("Failure. Unexpected exception")
 
 def fst_initiate_session(apdev, test_params, bad_param_type, init_on_ap):
     """This function makes the necessary preparations and then adds, sets and
@@ -326,7 +326,7 @@ def fst_initiate_session(apdev, test_params, bad_param_type, init_on_ap):
                 else:
                     raise Exception("Failure. Bad parameter was not detected (%s)" % bad_param_names[bad_param_type])
         else:
-            print "Failure. Unexpected exception"
+            logger.info("Failure. Unexpected exception")
 
 def fst_transfer_session(apdev, test_params, bad_param_type, init_on_ap,
                          rsn=False):
@@ -385,7 +385,7 @@ def fst_transfer_session(apdev, test_params, bad_param_type, init_on_ap,
                 else:
                     raise Exception("Failure. Bad parameter was not detected (%s)" % bad_param_names[bad_param_type])
         else:
-            print "Failure. Unexpected exception"
+            logger.info("Failure. Unexpected exception")
 
 
 def fst_tear_down_session(apdev, test_params, bad_param_type, init_on_ap):
@@ -453,7 +453,7 @@ def fst_tear_down_session(apdev, test_params, bad_param_type, init_on_ap):
                 else:
                     raise Exception("Failure. Bad parameter was not detected (%s)" % bad_param_names[bad_param_type])
         else:
-            print "Failure. Unexpected exception"
+            logger.info("Failure. Unexpected exception")
 
 
 #enum - remove session scenarios
@@ -528,7 +528,7 @@ def fst_remove_session(apdev, test_params, remove_session_scenario, init_on_ap):
                 else:
                     raise Exception("Failure. Remove scenario ended in an unexpected way (%s)" % remove_scenario_names[remove_session_scenario])
         else:
-            print "Failure. Unexpected exception"
+            logger.info("Failure. Unexpected exception")
 
 
 #enum - frame types
@@ -612,7 +612,7 @@ def fst_send_unexpected_frame(apdev, test_params, frame_type, send_from_ap, addi
                 else:
                     raise Exception("Failure. Frame was not ignored (%s)" % frame_type_names[frame_type])
         else:
-            print "Failure. Unexpected exception"
+            logger.info("Failure. Unexpected exception")
 
 
 #enum - bad session transfer scenarios
@@ -733,7 +733,7 @@ def fst_bad_transfer(apdev, test_params, bad_scenario_type, init_on_ap):
             else:
                 raise Exception("Failure. Bad scenario was handled incorrectly (%s)" % bad_scenario_names[bad_scenario_type])
         else:
-            print "Failure. Unexpected exception"
+            logger.info("Failure. Unexpected exception")
 
 def test_fst_sta_connect_to_non_fst_ap(dev, apdev, test_params):
     """FST STA connecting to non-FST AP"""
@@ -752,9 +752,9 @@ def test_fst_sta_connect_to_non_fst_ap(dev, apdev, test_params):
             res_sta2_mbies = sta2.get_local_mbies()
             if (orig_sta1_mbies.startswith("FAIL") or
                 orig_sta2_mbies.startswith("FAIL") or
-                not res_sta1_mbies.startswith("FAIL") or
-                not res_sta2_mbies.startswith("FAIL")):
-                raise Exception("Failure. MB IEs have not been removed on the stations")
+                res_sta1_mbies.startswith("FAIL") or
+                res_sta2_mbies.startswith("FAIL")):
+                raise Exception("Failure. MB IEs must be present on the stations")
         except Exception, e:
             logger.info(e)
             raise
@@ -839,9 +839,9 @@ def test_fst_second_sta_connect_to_non_fst_ap(dev, apdev, test_params):
             res_sta2_mbies = sta2.get_local_mbies()
             if (orig_sta1_mbies.startswith("FAIL") or
                 orig_sta2_mbies.startswith("FAIL") or
-                not res_sta1_mbies.startswith("FAIL") or
-                not res_sta2_mbies.startswith("FAIL")):
-                raise Exception("Failure. MB IEs have not been removed on the stations")
+                res_sta1_mbies.startswith("FAIL") or
+                res_sta2_mbies.startswith("FAIL")):
+                raise Exception("Failure. MB IEs must be present on the stations")
         except Exception, e:
             logger.info(e)
             raise
@@ -868,11 +868,11 @@ def test_fst_second_sta_connect_to_fst_ap(dev, apdev, test_params):
             time.sleep(2)
             res_sta1_mbies = sta1.get_local_mbies()
             res_sta2_mbies = sta2.get_local_mbies()
-            if (not orig_sta1_mbies.startswith("FAIL") or
-                not orig_sta2_mbies.startswith("FAIL") or
-                not res_sta1_mbies.startswith("FAIL") or
-                not res_sta2_mbies.startswith("FAIL")):
-                raise Exception("Failure. MB IEs should have stayed non-present on the stations")
+            if (orig_sta1_mbies.startswith("FAIL") or
+                orig_sta2_mbies.startswith("FAIL") or
+                res_sta1_mbies.startswith("FAIL") or
+                res_sta2_mbies.startswith("FAIL")):
+                raise Exception("Failure. MB IEs must be present on the stations")
         except Exception, e:
             logger.info(e)
             raise
@@ -900,11 +900,11 @@ def test_fst_disconnect_1_of_2_stas_from_non_fst_ap(dev, apdev, test_params):
             time.sleep(2)
             res_sta1_mbies = sta1.get_local_mbies()
             res_sta2_mbies = sta2.get_local_mbies()
-            if (not orig_sta1_mbies.startswith("FAIL") or
-                not orig_sta2_mbies.startswith("FAIL") or
+            if (orig_sta1_mbies.startswith("FAIL") or
+                orig_sta2_mbies.startswith("FAIL") or
                 res_sta1_mbies.startswith("FAIL") or
                 res_sta2_mbies.startswith("FAIL")):
-                raise Exception("Failure. MB IEs haven't reappeared on the stations")
+                raise Exception("Failure. MB IEs must be present on the stations")
         except Exception, e:
             logger.info(e)
             raise
@@ -932,11 +932,11 @@ def test_fst_disconnect_1_of_2_stas_from_fst_ap(dev, apdev, test_params):
             time.sleep(2)
             res_sta1_mbies = sta1.get_local_mbies()
             res_sta2_mbies = sta2.get_local_mbies()
-            if (not orig_sta1_mbies.startswith("FAIL") or
-                not orig_sta2_mbies.startswith("FAIL") or
-                not res_sta1_mbies.startswith("FAIL") or
-                not res_sta2_mbies.startswith("FAIL")):
-                raise Exception("Failure. MB IEs should have stayed non-present on the stations")
+            if (orig_sta1_mbies.startswith("FAIL") or
+                orig_sta2_mbies.startswith("FAIL") or
+                res_sta1_mbies.startswith("FAIL") or
+                res_sta2_mbies.startswith("FAIL")):
+                raise Exception("Failure. MB IEs must be present on the stations")
         except Exception, e:
             logger.info(e)
             raise
@@ -966,11 +966,11 @@ def test_fst_disconnect_2_of_2_stas_from_non_fst_ap(dev, apdev, test_params):
             time.sleep(2)
             res_sta1_mbies = sta1.get_local_mbies()
             res_sta2_mbies = sta2.get_local_mbies()
-            if (not orig_sta1_mbies.startswith("FAIL") or
-                not orig_sta2_mbies.startswith("FAIL") or
+            if (orig_sta1_mbies.startswith("FAIL") or
+                orig_sta2_mbies.startswith("FAIL") or
                 res_sta1_mbies.startswith("FAIL") or
                 res_sta2_mbies.startswith("FAIL")):
-                raise Exception("Failure. MB IEs haven't reappeared on the stations")
+                raise Exception("Failure. MB IEs must be present on the stations")
         except Exception, e:
             logger.info(e)
             raise
@@ -1065,7 +1065,7 @@ def test_fst_disconnect_non_fst_sta(dev, apdev, test_params):
 def test_fst_disconnect_fst_sta(dev, apdev, test_params):
     """FST disconnect FST STA"""
     ap1, ap2, fst_sta1, fst_sta2 = fst_module_aux.start_two_ap_sta_pairs(apdev)
-    external_sta_connected = False;
+    external_sta_connected = False
     try:
         vals = fst_sta1.scan(freq=fst_test_common.fst_test_def_freq_a)
         fst_sta1.connect(ap1, key_mgmt="NONE",
@@ -1527,6 +1527,12 @@ def test_fst_ap_start_session_oom(dev, apdev, test_params):
                                fst_test_common.fst_test_def_prio_low,
                                fst_test_common.fst_test_def_llt)
     ap1.start()
+    try:
+        run_fst_ap_start_session_oom(apdev, ap1)
+    finally:
+        ap1.stop()
+
+def run_fst_ap_start_session_oom(apdev, ap1):
     with alloc_fail(ap1, 1, "fst_iface_create"):
         ap2_started = False
         try:
@@ -1541,7 +1547,6 @@ def test_fst_ap_start_session_oom(dev, apdev, test_params):
             except:
                 pass
         finally:
-            ap1.stop()
             try:
                 ap2.stop()
             except:
@@ -2339,7 +2344,7 @@ def fst_start_and_connect(apdev, group, sgroup):
 
     params = { "ssid": "fst_11a", "hw_mode": "a", "channel": "36",
                "country_code": "US" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     fst_attach_ap(hglobal, apdev[0]['ifname'], group)
 
@@ -2349,7 +2354,7 @@ def fst_start_and_connect(apdev, group, sgroup):
 
     params = { "ssid": "fst_11g", "hw_mode": "g", "channel": "1",
                "country_code": "US" }
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd2 = hostapd.add_ap(apdev[1], params)
     fst_attach_ap(hglobal, apdev[1]['ifname'], group)
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
@@ -2534,9 +2539,20 @@ def _test_fst_setup_mbie_diff(dev, apdev, test_params):
     req = "1200011a060000"
     stie = "a40b0100000000020001040001"
     mbie = "9e16040200010200000004000000000000000000000000ff"
-    with alloc_fail(hapd, 1, "mb_ies_by_info"):
-        fst_setup_req(wpas, hglobal, 5180, apdev[0]['bssid'], req, stie, mbie,
-                      no_wait=True)
+    try:
+        with alloc_fail(hapd, 1, "mb_ies_by_info"):
+            fst_setup_req(wpas, hglobal, 5180, apdev[0]['bssid'], req, stie,
+                          mbie, no_wait=True)
+    except HwsimSkip, e:
+        # Skip exception to allow proper cleanup
+        pass
+
+    # Remove sessions to avoid causing issues to following test ases
+    s = hglobal.request("FST-MANAGER LIST_SESSIONS " + group)
+    if not s.startswith("FAIL"):
+        for sid in s.split(' '):
+            if len(sid):
+                hglobal.request("FST-MANAGER SESSION_REMOVE " + sid)
 
 def test_fst_many_setup(dev, apdev, test_params):
     """FST setup multiple times"""
index 416d616..2ac610f 100644 (file)
@@ -5,16 +5,20 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import time
 import binascii
 import logging
 logger = logging.getLogger()
+import os
 import re
 import struct
 
 import hostapd
 from wpasupplicant import WpaSupplicant
-from utils import alloc_fail, skip_with_fips
+from tshark import run_tshark
+from utils import alloc_fail, wait_fail_trigger, skip_with_fips
+from hwsim import HWSimRadio
 
 def hs20_ap_params():
     params = hostapd.wpa2_params(ssid="test-gas")
@@ -51,8 +55,7 @@ def hs20_ap_params():
 def start_ap(ap):
     params = hs20_ap_params()
     params['hessid'] = ap['bssid']
-    hostapd.add_ap(ap['ifname'], params)
-    return hostapd.Hostapd(ap['ifname'])
+    return hostapd.add_ap(ap, params)
 
 def get_gas_response(dev, bssid, info, allow_fetch_failure=False,
                      extra_test=False):
@@ -105,7 +108,7 @@ def test_gas_generic(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     cmds = [ "foo",
              "00:11:22:33:44:55",
@@ -140,7 +143,7 @@ def test_gas_concurrent_scan(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     # get BSS entry available to allow GAS query
     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
@@ -179,7 +182,7 @@ def test_gas_concurrent_connect(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
 
@@ -234,28 +237,54 @@ def test_gas_concurrent_connect(dev, apdev):
     if "CTRL-EVENT-CONNECTED" not in ev:
         raise Exception("Unexpected operation order")
 
-def test_gas_fragment(dev, apdev):
-    """GAS fragmentation"""
-    hapd = start_ap(apdev[0])
-    hapd.set("gas_frag_limit", "50")
+def gas_fragment_and_comeback(dev, apdev, frag_limit=0, comeback_delay=0):
+    hapd = start_ap(apdev)
+    if frag_limit:
+        hapd.set("gas_frag_limit", str(frag_limit))
+    if comeback_delay:
+        hapd.set("gas_comeback_delay", str(comeback_delay))
 
-    dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412", force_scan=True)
-    dev[0].request("FETCH_ANQP")
-    ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=1)
+    dev.scan_for_bss(apdev['bssid'], freq="2412", force_scan=True)
+    dev.request("FETCH_ANQP")
+    ev = dev.wait_event(["GAS-QUERY-DONE"], timeout=5)
     if ev is None:
         raise Exception("No GAS-QUERY-DONE event")
     if "result=SUCCESS" not in ev:
         raise Exception("Unexpected GAS result: " + ev)
     for i in range(0, 13):
-        ev = dev[0].wait_event(["RX-ANQP", "RX-HS20-ANQP"], timeout=5)
+        ev = dev.wait_event(["RX-ANQP", "RX-HS20-ANQP"], timeout=5)
         if ev is None:
             raise Exception("Operation timed out")
-    ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=1)
+    ev = dev.wait_event(["ANQP-QUERY-DONE"], timeout=1)
     if ev is None:
         raise Exception("No ANQP-QUERY-DONE event")
     if "result=SUCCESS" not in ev:
         raise Exception("Unexpected ANQP result: " + ev)
 
+def test_gas_fragment(dev, apdev):
+    """GAS fragmentation"""
+    gas_fragment_and_comeback(dev[0], apdev[0], frag_limit=50)
+
+def test_gas_fragment_mcc(dev, apdev):
+    """GAS fragmentation with mac80211_hwsim MCC enabled"""
+    with HWSimRadio(n_channels=2) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+        gas_fragment_and_comeback(wpas, apdev[0], frag_limit=50)
+
+def test_gas_fragment_with_comeback_delay(dev, apdev):
+    """GAS fragmentation and comeback delay"""
+    gas_fragment_and_comeback(dev[0], apdev[0], frag_limit=50,
+                              comeback_delay=500)
+
+def test_gas_fragment_with_comeback_delay_mcc(dev, apdev):
+    """GAS fragmentation and comeback delay with mac80211_hwsim MCC enabled"""
+    with HWSimRadio(n_channels=2) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+        gas_fragment_and_comeback(wpas, apdev[0], frag_limit=50,
+                                  comeback_delay=500)
+
 def test_gas_comeback_delay(dev, apdev):
     """GAS comeback delay"""
     hapd = start_ap(apdev[0])
@@ -270,6 +299,7 @@ def test_gas_comeback_delay(dev, apdev):
         if ev is None:
             raise Exception("Operation timed out")
 
+@remote_compatible
 def test_gas_stop_fetch_anqp(dev, apdev):
     """Stop FETCH_ANQP operation"""
     hapd = start_ap(apdev[0])
@@ -335,6 +365,18 @@ def test_gas_anqp_get(dev, apdev):
     if ev is None or "WAN Metrics" not in ev:
         raise Exception("Did not receive WAN Metrics")
 
+    logger.info("Attempt an MBO request with an AP that does not support MBO")
+    if "OK" not in dev[0].request("ANQP_GET " + bssid + " 272,mbo:1"):
+        raise Exception("ANQP_GET command failed (2)")
+
+    ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
+    if ev is None:
+        raise Exception("GAS query start timed out (2)")
+
+    ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
+    if ev is None:
+        raise Exception("GAS query timed out (2)")
+
     cmds = [ "",
              "foo",
              "00:11:22:33:44:55 258,hs20:-1",
@@ -343,9 +385,13 @@ def test_gas_anqp_get(dev, apdev):
              "00:11:22:33:44:55 hs20:-1",
              "00:11:22:33:44:55 hs20:0",
              "00:11:22:33:44:55 hs20:32",
+             "00:11:22:33:44:55 mbo:-1",
+             "00:11:22:33:44:55 mbo:0",
+             "00:11:22:33:44:55 mbo:999",
              "00:11:22:33:44:55",
              "00:11:22:33:44:55 ",
-             "00:11:22:33:44:55 0" ]
+             "00:11:22:33:44:55 0",
+             "00:11:22:33:44:55 1" ]
     for cmd in cmds:
         if "FAIL" not in dev[0].request("ANQP_GET " + cmd):
             raise Exception("Invalid ANQP_GET accepted")
@@ -357,11 +403,78 @@ def test_gas_anqp_get(dev, apdev):
              "00:11:22:33:44:55 32",
              "00:11:22:33:44:55",
              "00:11:22:33:44:55 ",
-             "00:11:22:33:44:55 0" ]
+             "00:11:22:33:44:55 0",
+             "00:11:22:33:44:55 1" ]
     for cmd in cmds:
         if "FAIL" not in dev[0].request("HS20_ANQP_GET " + cmd):
             raise Exception("Invalid HS20_ANQP_GET accepted")
 
+def test_gas_anqp_get_oom(dev, apdev):
+    """GAS/ANQP query OOM"""
+    hapd = start_ap(apdev[0])
+    bssid = apdev[0]['bssid']
+
+    dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
+    with alloc_fail(dev[0], 1, "wpabuf_alloc;anqp_send_req"):
+        if "FAIL" not in dev[0].request("ANQP_GET " + bssid + " 258,268,hs20:3,hs20:4"):
+            raise Exception("ANQP_GET command accepted during OOM")
+    with alloc_fail(dev[0], 1, "hs20_build_anqp_req;hs20_anqp_send_req"):
+        if "FAIL" not in dev[0].request("HS20_ANQP_GET " + bssid + " 1"):
+            raise Exception("HS20_ANQP_GET command accepted during OOM")
+    with alloc_fail(dev[0], 1, "gas_query_req;hs20_anqp_send_req"):
+        if "FAIL" not in dev[0].request("HS20_ANQP_GET " + bssid + " 1"):
+            raise Exception("HS20_ANQP_GET command accepted during OOM")
+    with alloc_fail(dev[0], 1, "=hs20_anqp_send_req"):
+        if "FAIL" not in dev[0].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
+            raise Exception("REQ_HS20_ICON command accepted during OOM")
+    with alloc_fail(dev[0], 2, "=hs20_anqp_send_req"):
+        if "FAIL" not in dev[0].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
+            raise Exception("REQ_HS20_ICON command accepted during OOM")
+
+def test_gas_anqp_icon_binary_proto(dev, apdev):
+    """GAS/ANQP and icon binary protocol testing"""
+    hapd = start_ap(apdev[0])
+    bssid = apdev[0]['bssid']
+
+    dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
+    hapd.set("ext_mgmt_frame_handling", "1")
+
+    tests = [ '010000', '01000000', '00000000', '00030000', '00020000',
+              '00000100', '0001ff0100ee', '0001ff0200ee' ]
+    for test in tests:
+        dev[0].request("HS20_ICON_REQUEST " + bssid + " w1fi_logo")
+        query = gas_rx(hapd)
+        gas = parse_gas(query['payload'])
+        resp = action_response(query)
+        data = binascii.unhexlify(test)
+        data = binascii.unhexlify('506f9a110b00') + data
+        data = struct.pack('<HHH', len(data) + 4, 0xdddd, len(data)) + data
+        resp['payload'] = anqp_initial_resp(gas['dialog_token'], 0) + data
+        send_gas_resp(hapd, resp)
+        expect_gas_result(dev[0], "SUCCESS")
+
+def test_gas_anqp_hs20_proto(dev, apdev):
+    """GAS/ANQP and Hotspot 2.0 element protocol testing"""
+    hapd = start_ap(apdev[0])
+    bssid = apdev[0]['bssid']
+
+    dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
+    hapd.set("ext_mgmt_frame_handling", "1")
+
+    tests = [ '00', '0100', '0201', '0300', '0400', '0500', '0600', '0700',
+              '0800', '0900', '0a00', '0b0000000000' ]
+    for test in tests:
+        dev[0].request("HS20_ANQP_GET " + bssid + " 3,4")
+        query = gas_rx(hapd)
+        gas = parse_gas(query['payload'])
+        resp = action_response(query)
+        data = binascii.unhexlify(test)
+        data = binascii.unhexlify('506f9a11') + data
+        data = struct.pack('<HHH', len(data) + 4, 0xdddd, len(data)) + data
+        resp['payload'] = anqp_initial_resp(gas['dialog_token'], 0) + data
+        send_gas_resp(hapd, resp)
+        expect_gas_result(dev[0], "SUCCESS")
+
 def expect_gas_result(dev, result, status=None):
     ev = dev.wait_event(["GAS-QUERY-DONE"], timeout=10)
     if ev is None:
@@ -612,6 +725,13 @@ def init_gas(hapd, bssid, dev):
         raise Exception("Unexpected dialog token change")
     return query, dialog_token
 
+def allow_gas_initial_req(hapd, dialog_token):
+    msg = hapd.mgmt_rx(timeout=1)
+    if msg is not None:
+        gas = parse_gas(msg['payload'])
+        if gas['action'] != GAS_INITIAL_REQUEST or dialog_token == gas['dialog_token']:
+            raise Exception("Unexpected management frame")
+
 def test_gas_malformed_comeback_resp(dev, apdev):
     """GAS malformed comeback response frames"""
     hapd = start_ap(apdev[0])
@@ -671,9 +791,7 @@ def test_gas_malformed_comeback_resp(dev, apdev):
     resp = action_response(query)
     resp['payload'] = anqp_initial_resp(dialog_token, 0) + struct.pack('<H', 0)
     send_gas_resp(hapd, resp)
-    ev = hapd.wait_event(["MGMT-RX"], timeout=1)
-    if ev is not None:
-        raise Exception("Unexpected management frame")
+    allow_gas_initial_req(hapd, dialog_token)
     expect_gas_result(dev[0], "TIMEOUT")
 
     logger.debug("Too short comeback response")
@@ -682,9 +800,7 @@ def test_gas_malformed_comeback_resp(dev, apdev):
     resp['payload'] = struct.pack('<BBBH', ACTION_CATEG_PUBLIC,
                                   GAS_COMEBACK_RESPONSE, dialog_token, 0)
     send_gas_resp(hapd, resp)
-    ev = hapd.wait_event(["MGMT-RX"], timeout=1)
-    if ev is not None:
-        raise Exception("Unexpected management frame")
+    allow_gas_initial_req(hapd, dialog_token)
     expect_gas_result(dev[0], "TIMEOUT")
 
     logger.debug("Too short comeback response(2)")
@@ -694,9 +810,7 @@ def test_gas_malformed_comeback_resp(dev, apdev):
                                   GAS_COMEBACK_RESPONSE, dialog_token, 0, 0x80,
                                   0)
     send_gas_resp(hapd, resp)
-    ev = hapd.wait_event(["MGMT-RX"], timeout=1)
-    if ev is not None:
-        raise Exception("Unexpected management frame")
+    allow_gas_initial_req(hapd, dialog_token)
     expect_gas_result(dev[0], "TIMEOUT")
 
     logger.debug("Maximum comeback response fragment claiming more fragments")
@@ -745,7 +859,7 @@ def test_gas_unknown_adv_proto(dev, apdev):
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
     req = dev[0].request("GAS_REQUEST " + bssid + " 42 000102000101")
@@ -765,6 +879,32 @@ def test_gas_unknown_adv_proto(dev, apdev):
     if status != "59":
         raise Exception("Unexpected GAS-RESPONSE-INFO status")
 
+def test_gas_request_oom(dev, apdev):
+    """GAS_REQUEST OOM"""
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+    hostapd.add_ap(apdev[0], params)
+
+    dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
+
+    with alloc_fail(dev[0], 1, "gas_build_req;gas_send_request"):
+        if "FAIL" not in dev[0].request("GAS_REQUEST " + bssid + " 42"):
+            raise Exception("GAS query request rejected")
+
+    with alloc_fail(dev[0], 1, "gas_query_req;gas_send_request"):
+        if "FAIL" not in dev[0].request("GAS_REQUEST " + bssid + " 42"):
+            raise Exception("GAS query request rejected")
+
+    with alloc_fail(dev[0], 1, "wpabuf_dup;gas_resp_cb"):
+        if "OK" not in dev[0].request("GAS_REQUEST " + bssid + " 00 000102000101"):
+            raise Exception("GAS query request rejected")
+        ev = dev[0].wait_event(["GAS-RESPONSE-INFO"], timeout=10)
+        if ev is None:
+            raise Exception("No GAS response")
+        if "status_code=0" not in ev:
+            raise Exception("GAS response indicated a failure")
+
 def test_gas_max_pending(dev, apdev):
     """GAS and maximum pending query limit"""
     hapd = start_ap(apdev[0])
@@ -831,12 +971,31 @@ def test_gas_no_pending(dev, apdev):
     if status_code != 60:
         raise Exception("Unexpected status code {} (expected 60)".format(status_code))
 
+def test_gas_delete_at_deinit(dev, apdev):
+    """GAS query deleted at deinit"""
+    hapd = start_ap(apdev[0])
+    hapd.set("gas_comeback_delay", "1000")
+    bssid = apdev[0]['bssid']
+
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    wpas.interface_add("wlan5")
+    wpas.scan_for_bss(apdev[0]['bssid'], freq="2412", force_scan=True)
+    wpas.request("ANQP_GET " + bssid + " 258")
+
+    wpas.global_request("INTERFACE_REMOVE " + wpas.ifname)
+    ev = wpas.wait_event(["GAS-QUERY-DONE"], timeout=2)
+    del wpas
+    if ev is None:
+        raise Exception("GAS-QUERY-DONE not seen")
+    if "result=DELETED_AT_DEINIT" not in ev:
+        raise Exception("Unexpected result code: " + ev)
+
 def test_gas_missing_payload(dev, apdev):
     """No action code in the query frame"""
     bssid = apdev[0]['bssid']
     params = hs20_ap_params()
     params['hessid'] = bssid
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
 
@@ -882,6 +1041,7 @@ def test_gas_query_deinit(dev, apdev):
     # GAS query has not yet been started.
     wpas.interface_remove("wlan5")
 
+@remote_compatible
 def test_gas_anqp_oom_wpas(dev, apdev):
     """GAS/ANQP query and OOM in wpa_supplicant"""
     hapd = start_ap(apdev[0])
@@ -889,6 +1049,13 @@ def test_gas_anqp_oom_wpas(dev, apdev):
 
     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
 
+    with alloc_fail(dev[0], 1, "wpa_bss_anqp_alloc"):
+        if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
+            raise Exception("ANQP_GET command failed")
+        ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
+        if ev is None:
+            raise Exception("ANQP query did not complete")
+
     with alloc_fail(dev[0], 1, "gas_build_req"):
         if "FAIL" not in dev[0].request("ANQP_GET " + bssid + " 258"):
             raise Exception("Unexpected ANQP_GET command success (OOM)")
@@ -924,8 +1091,9 @@ def test_gas_anqp_oom_hapd(dev, apdev):
     with alloc_fail(hapd, 1, "gas_anqp_build_comeback_resp"):
         hapd.set("gas_frag_limit", "50")
 
-        # This query will time out due to the AP not sending a response (OOM).
-        print dev[0].request("FETCH_ANQP")
+        # The first attempt of this query will time out due to the AP not
+        # sending a response (OOM), but the retry succeeds.
+        dev[0].request("FETCH_ANQP")
         ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
         if ev is None:
             raise Exception("GAS query start timed out")
@@ -933,11 +1101,367 @@ def test_gas_anqp_oom_hapd(dev, apdev):
         ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
         if ev is None:
             raise Exception("GAS query timed out")
-        if "result=TIMEOUT" not in ev:
+        if "result=SUCCESS" not in ev:
             raise Exception("Unexpected result: " + ev)
 
         ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
         if ev is None:
             raise Exception("ANQP-QUERY-DONE event not seen")
-        if "result=FAILURE" not in ev:
+        if "result=SUCCESS" not in ev:
             raise Exception("Unexpected result: " + ev)
+
+def test_gas_anqp_extra_elements(dev, apdev):
+    """GAS/ANQP and extra ANQP elements"""
+    geo_loc = "001052834d12efd2b08b9b4bf1cc2c00004104050000000000060100"
+    civic_loc = "0000f9555302f50102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5"
+    held_uri = "https://held.example.com/location"
+    held = struct.pack('BBB', 0, 1 + len(held_uri), 1) + held_uri
+    supl_fqdn = "supl.example.com"
+    supl = struct.pack('BBB', 0, 1 + len(supl_fqdn), 1) + supl_fqdn
+    public_id = binascii.hexlify(held + supl)
+    params = { "ssid": "gas/anqp",
+               "interworking": "1",
+               "anqp_elem": [ "265:" + geo_loc,
+                              "266:" + civic_loc,
+                              "262:1122334455",
+                              "267:" + public_id,
+                              "275:01020304",
+                              "60000:01",
+                              "299:0102" ] }
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+
+    dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
+    if "OK" not in dev[0].request("ANQP_GET " + bssid + " 265,266"):
+        raise Exception("ANQP_GET command failed")
+
+    ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
+    if ev is None:
+        raise Exception("GAS query timed out")
+
+    bss = dev[0].get_bss(bssid)
+
+    if 'anqp[265]' not in bss:
+        raise Exception("AP Geospatial Location ANQP-element not seen")
+    if bss['anqp[265]'] != geo_loc:
+        raise Exception("Unexpected AP Geospatial Location ANQP-element value: " + bss['anqp[265]'])
+
+    if 'anqp[266]' not in bss:
+        raise Exception("AP Civic Location ANQP-element not seen")
+    if bss['anqp[266]'] != civic_loc:
+        raise Exception("Unexpected AP Civic Location ANQP-element value: " + bss['anqp[266]'])
+
+    dev[1].scan_for_bss(bssid, freq="2412", force_scan=True)
+    if "OK" not in dev[1].request("ANQP_GET " + bssid + " 257,258,259,260,261,262,263,264,265,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299"):
+        raise Exception("ANQP_GET command failed")
+
+    ev = dev[1].wait_event(["GAS-QUERY-DONE"], timeout=10)
+    if ev is None:
+        raise Exception("GAS query timed out")
+
+    bss = dev[1].get_bss(bssid)
+
+    if 'anqp[265]' not in bss:
+        raise Exception("AP Geospatial Location ANQP-element not seen")
+    if bss['anqp[265]'] != geo_loc:
+        raise Exception("Unexpected AP Geospatial Location ANQP-element value: " + bss['anqp[265]'])
+
+    if 'anqp[266]' in bss:
+        raise Exception("AP Civic Location ANQP-element unexpectedly seen")
+
+    if 'anqp[267]' not in bss:
+        raise Exception("AP Location Public Identifier ANQP-element not seen")
+    if bss['anqp[267]'] != public_id:
+        raise Exception("Unexpected AP Location Public Identifier ANQP-element value: " + bss['anqp[267]'])
+
+    if 'anqp[275]' not in bss:
+        raise Exception("ANQP-element Info ID 275 not seen")
+    if bss['anqp[275]'] != "01020304":
+        raise Exception("Unexpected AP ANQP-element Info ID 299 value: " + bss['anqp[299]'])
+
+    if 'anqp[299]' not in bss:
+        raise Exception("ANQP-element Info ID 299 not seen")
+    if bss['anqp[299]'] != "0102":
+        raise Exception("Unexpected AP ANQP-element Info ID 299 value: " + bss['anqp[299]'])
+
+    if 'anqp_ip_addr_type_availability' not in bss:
+        raise Exception("ANQP-element Info ID 292 not seen")
+    if bss['anqp_ip_addr_type_availability'] != "1122334455":
+        raise Exception("Unexpected AP ANQP-element Info ID 262 value: " + bss['anqp_ip_addr_type_availability'])
+
+def test_gas_anqp_address3_not_assoc(dev, apdev, params):
+    """GAS/ANQP query using IEEE 802.11 compliant Address 3 value when not associated"""
+    try:
+        _test_gas_anqp_address3_not_assoc(dev, apdev, params)
+    finally:
+        dev[0].request("SET gas_address3 0")
+
+def _test_gas_anqp_address3_not_assoc(dev, apdev, params):
+    hapd = start_ap(apdev[0])
+    bssid = apdev[0]['bssid']
+
+    if "OK" not in dev[0].request("SET gas_address3 1"):
+        raise Exception("Failed to set gas_address3")
+
+    dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
+    if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
+        raise Exception("ANQP_GET command failed")
+
+    ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
+    if ev is None:
+        raise Exception("GAS query start timed out")
+
+    ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
+    if ev is None:
+        raise Exception("GAS query timed out")
+
+    ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
+    if ev is None or "Venue Name" not in ev:
+        raise Exception("Did not receive Venue Name")
+
+    ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
+    if ev is None:
+        raise Exception("ANQP-QUERY-DONE event not seen")
+    if "result=SUCCESS" not in ev:
+        raise Exception("Unexpected result: " + ev)
+
+    out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
+                     "wlan_mgt.fixed.category_code == 4 && (wlan_mgt.fixed.publicact == 0x0a || wlan_mgt.fixed.publicact == 0x0b)",
+                     display=["wlan.bssid"])
+    res = out.splitlines()
+    if len(res) != 2:
+        raise Exception("Unexpected number of GAS frames")
+    if res[0] != 'ff:ff:ff:ff:ff:ff':
+        raise Exception("GAS request used unexpected Address3 field value: " + res[0])
+    if res[1] != 'ff:ff:ff:ff:ff:ff':
+        raise Exception("GAS response used unexpected Address3 field value: " + res[1])
+
+def test_gas_anqp_address3_assoc(dev, apdev, params):
+    """GAS/ANQP query using IEEE 802.11 compliant Address 3 value when associated"""
+    try:
+        _test_gas_anqp_address3_assoc(dev, apdev, params)
+    finally:
+        dev[0].request("SET gas_address3 0")
+
+def _test_gas_anqp_address3_assoc(dev, apdev, params):
+    hapd = start_ap(apdev[0])
+    bssid = apdev[0]['bssid']
+
+    if "OK" not in dev[0].request("SET gas_address3 1"):
+        raise Exception("Failed to set gas_address3")
+
+    dev[0].scan_for_bss(bssid, freq="2412")
+    dev[0].connect("test-gas", key_mgmt="WPA-EAP", eap="TTLS",
+                   identity="DOMAIN\mschapv2 user", anonymous_identity="ttls",
+                   password="password", phase2="auth=MSCHAPV2",
+                   ca_cert="auth_serv/ca.pem", scan_freq="2412")
+
+    if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
+        raise Exception("ANQP_GET command failed")
+
+    ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
+    if ev is None:
+        raise Exception("GAS query start timed out")
+
+    ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
+    if ev is None:
+        raise Exception("GAS query timed out")
+
+    ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
+    if ev is None or "Venue Name" not in ev:
+        raise Exception("Did not receive Venue Name")
+
+    ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
+    if ev is None:
+        raise Exception("ANQP-QUERY-DONE event not seen")
+    if "result=SUCCESS" not in ev:
+        raise Exception("Unexpected result: " + ev)
+
+    out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
+                     "wlan_mgt.fixed.category_code == 4 && (wlan_mgt.fixed.publicact == 0x0a || wlan_mgt.fixed.publicact == 0x0b)",
+                     display=["wlan.bssid"])
+    res = out.splitlines()
+    if len(res) != 2:
+        raise Exception("Unexpected number of GAS frames")
+    if res[0] != bssid:
+        raise Exception("GAS request used unexpected Address3 field value: " + res[0])
+    if res[1] != bssid:
+        raise Exception("GAS response used unexpected Address3 field value: " + res[1])
+
+def test_gas_anqp_address3_ap_forced(dev, apdev, params):
+    """GAS/ANQP query using IEEE 802.11 compliant Address 3 value on AP"""
+    hapd = start_ap(apdev[0])
+    bssid = apdev[0]['bssid']
+    hapd.set("gas_address3", "1")
+
+    dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
+    if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
+        raise Exception("ANQP_GET command failed")
+
+    ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
+    if ev is None:
+        raise Exception("GAS query start timed out")
+
+    ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
+    if ev is None:
+        raise Exception("GAS query timed out")
+
+    ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
+    if ev is None or "Venue Name" not in ev:
+        raise Exception("Did not receive Venue Name")
+
+    ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
+    if ev is None:
+        raise Exception("ANQP-QUERY-DONE event not seen")
+    if "result=SUCCESS" not in ev:
+        raise Exception("Unexpected result: " + ev)
+
+    out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
+                     "wlan_mgt.fixed.category_code == 4 && (wlan_mgt.fixed.publicact == 0x0a || wlan_mgt.fixed.publicact == 0x0b)",
+                     display=["wlan.bssid"])
+    res = out.splitlines()
+    if len(res) != 2:
+        raise Exception("Unexpected number of GAS frames")
+    if res[0] != bssid:
+        raise Exception("GAS request used unexpected Address3 field value: " + res[0])
+    if res[1] != 'ff:ff:ff:ff:ff:ff':
+        raise Exception("GAS response used unexpected Address3 field value: " + res[1])
+
+def test_gas_anqp_address3_ap_non_compliant(dev, apdev, params):
+    """GAS/ANQP query using IEEE 802.11 non-compliant Address 3 (AP)"""
+    try:
+        _test_gas_anqp_address3_ap_non_compliant(dev, apdev, params)
+    finally:
+        dev[0].request("SET gas_address3 0")
+
+def _test_gas_anqp_address3_ap_non_compliant(dev, apdev, params):
+    hapd = start_ap(apdev[0])
+    bssid = apdev[0]['bssid']
+    hapd.set("gas_address3", "2")
+
+    if "OK" not in dev[0].request("SET gas_address3 1"):
+        raise Exception("Failed to set gas_address3")
+
+    dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
+    if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
+        raise Exception("ANQP_GET command failed")
+
+    ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
+    if ev is None:
+        raise Exception("GAS query start timed out")
+
+    ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
+    if ev is None:
+        raise Exception("GAS query timed out")
+
+    ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
+    if ev is None or "Venue Name" not in ev:
+        raise Exception("Did not receive Venue Name")
+
+    ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
+    if ev is None:
+        raise Exception("ANQP-QUERY-DONE event not seen")
+    if "result=SUCCESS" not in ev:
+        raise Exception("Unexpected result: " + ev)
+
+    out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
+                     "wlan_mgt.fixed.category_code == 4 && (wlan_mgt.fixed.publicact == 0x0a || wlan_mgt.fixed.publicact == 0x0b)",
+                     display=["wlan.bssid"])
+    res = out.splitlines()
+    if len(res) != 2:
+        raise Exception("Unexpected number of GAS frames")
+    if res[0] != 'ff:ff:ff:ff:ff:ff':
+        raise Exception("GAS request used unexpected Address3 field value: " + res[0])
+    if res[1] != bssid:
+        raise Exception("GAS response used unexpected Address3 field value: " + res[1])
+
+def test_gas_prot_vs_not_prot(dev, apdev, params):
+    """GAS/ANQP query protected vs. not protected"""
+    hapd = start_ap(apdev[0])
+    bssid = apdev[0]['bssid']
+
+    dev[0].scan_for_bss(bssid, freq="2412")
+    dev[0].connect("test-gas", key_mgmt="WPA-EAP", eap="TTLS",
+                   identity="DOMAIN\mschapv2 user", anonymous_identity="ttls",
+                   password="password", phase2="auth=MSCHAPV2",
+                   ca_cert="auth_serv/ca.pem", scan_freq="2412",
+                   ieee80211w="2")
+
+    if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
+        raise Exception("ANQP_GET command failed")
+
+    ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=5)
+    if ev is None:
+        raise Exception("No GAS-QUERY-DONE event")
+    if "result=SUCCESS" not in ev:
+        raise Exception("Unexpected GAS result: " + ev)
+
+    # GAS: Drop unexpected unprotected GAS frame when PMF is enabled
+    dev[0].request("SET ext_mgmt_frame_handling 1")
+    res = dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=d0003a010200000000000200000003000200000003001000040b00000005006c027f000000")
+    dev[0].request("SET ext_mgmt_frame_handling 0")
+    if "OK" not in res:
+        raise Exception("MGMT_RX_PROCESS failed")
+
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+    # GAS: No pending query found for 02:00:00:00:03:00 dialog token 0
+    dev[0].request("SET ext_mgmt_frame_handling 1")
+    res = dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=d0003a010200000000000200000003000200000003001000040b00000005006c027f000000")
+    dev[0].request("SET ext_mgmt_frame_handling 0")
+    if "OK" not in res:
+        raise Exception("MGMT_RX_PROCESS failed")
+
+    # GAS: Drop unexpected protected GAS frame when PMF is disabled
+    dev[0].request("SET ext_mgmt_frame_handling 1")
+    res = dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=d0003a010200000000000200000003000200000003001000090b00000005006c027f000000")
+    dev[0].request("SET ext_mgmt_frame_handling 0")
+    if "OK" not in res:
+        raise Exception("MGMT_RX_PROCESS failed")
+
+def test_gas_failures(dev, apdev):
+    """GAS failure cases"""
+    hapd = start_ap(apdev[0])
+    hapd.set("gas_comeback_delay", "5")
+    bssid = apdev[0]['bssid']
+
+    hapd2 = start_ap(apdev[1])
+    bssid2 = apdev[1]['bssid']
+
+    dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
+    dev[0].scan_for_bss(bssid2, freq="2412")
+
+    tests = [ (bssid, "gas_build_req;gas_query_tx_comeback_req"),
+              (bssid, "gas_query_tx;gas_query_tx_comeback_req"),
+              (bssid, "gas_query_append;gas_query_rx_comeback"),
+              (bssid2, "gas_query_append;gas_query_rx_initial"),
+              (bssid2, "wpabuf_alloc_copy;gas_query_rx_initial"),
+              (bssid, "gas_query_tx;gas_query_tx_initial_req") ]
+    for addr,func in tests:
+        with alloc_fail(dev[0], 1, func):
+            dev[0].request("ANQP_GET " + addr + " 258")
+            ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=5)
+            if ev is None:
+                raise Exception("No GAS-QUERY-DONE seen")
+            if "result=INTERNAL_ERROR" not in ev:
+                raise Exception("Unexpected result code: " + ev)
+        dev[0].dump_monitor()
+
+    tests = [ "=gas_query_req", "radio_add_work;gas_query_req" ]
+    for func in tests:
+        with alloc_fail(dev[0], 1, func):
+            if "FAIL" not in dev[0].request("ANQP_GET " + bssid + " 258"):
+                raise Exception("ANQP_GET succeeded unexpectedly during OOM")
+        dev[0].dump_monitor()
+
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    wpas.interface_add("wlan5")
+    wpas.scan_for_bss(bssid2, freq="2412")
+    wpas.request("SET preassoc_mac_addr 1111")
+    wpas.request("ANQP_GET " + bssid2 + " 258")
+    ev = wpas.wait_event(["Failed to assign random MAC address for GAS"],
+                         timeout=5)
+    wpas.request("SET preassoc_mac_addr 0")
+    if ev is None:
+        raise Exception("No random MAC address error seen")
index e45eca0..d1f6f39 100644 (file)
@@ -4,15 +4,18 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import hostapd
+import hwsim_utils
 from utils import skip_with_fips
 
+@remote_compatible
 def test_hapd_ctrl_status(dev, apdev):
     """hostapd ctrl_iface STATUS commands"""
     ssid = "hapd-ctrl"
     bssid = apdev[0]['bssid']
     params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     status = hapd.get_status()
     driver = hapd.get_driver_status()
 
@@ -30,6 +33,7 @@ def test_hapd_ctrl_status(dev, apdev):
     if driver['addr'] != bssid:
         raise Exception("Unexpected addr")
 
+@remote_compatible
 def test_hapd_ctrl_p2p_manager(dev, apdev):
     """hostapd as P2P Device manager"""
     ssid = "hapd-p2p-mgr"
@@ -37,7 +41,7 @@ def test_hapd_ctrl_p2p_manager(dev, apdev):
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     params['manage_p2p'] = '1'
     params['allow_cross_connection'] = '0'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     addr = dev[0].own_addr()
     if "OK" not in hapd.request("DEAUTHENTICATE " + addr + " p2p=2"):
@@ -50,12 +54,13 @@ def test_hapd_ctrl_p2p_manager(dev, apdev):
     dev[0].wait_disconnected(timeout=5)
     dev[0].wait_connected(timeout=10, error="Re-connection timed out")
 
+@remote_compatible
 def test_hapd_ctrl_sta(dev, apdev):
     """hostapd and STA ctrl_iface commands"""
     ssid = "hapd-ctrl-sta"
     passphrase = "12345678"
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     addr = dev[0].own_addr()
     if "FAIL" in hapd.request("STA " + addr):
@@ -72,12 +77,13 @@ def test_hapd_ctrl_sta(dev, apdev):
     if "FAIL" not in hapd.request("STA-NEXT 00:11:22:33:44"):
         raise Exception("Unexpected STA-NEXT success")
 
+@remote_compatible
 def test_hapd_ctrl_disconnect(dev, apdev):
     """hostapd and disconnection ctrl_iface commands"""
     ssid = "hapd-ctrl"
     passphrase = "12345678"
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     addr = dev[0].p2p_dev_addr()
 
@@ -97,11 +103,12 @@ def test_hapd_ctrl_disconnect(dev, apdev):
     dev[0].wait_disconnected(timeout=5)
     dev[0].wait_connected(timeout=10, error="Re-connection timed out")
 
+@remote_compatible
 def test_hapd_ctrl_chan_switch(dev, apdev):
     """hostapd and CHAN_SWITCH ctrl_iface command"""
     ssid = "hapd-ctrl"
     params = { "ssid": ssid }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     if "FAIL" not in hapd.request("CHAN_SWITCH "):
         raise Exception("Unexpected CHAN_SWITCH success")
     if "FAIL" not in hapd.request("CHAN_SWITCH qwerty 2422"):
@@ -111,19 +118,21 @@ def test_hapd_ctrl_chan_switch(dev, apdev):
     if "FAIL" not in hapd.request("CHAN_SWITCH 0 2432 center_freq1=123 center_freq2=234 bandwidth=1000 sec_channel_offset=20 ht vht"):
         raise Exception("Unexpected CHAN_SWITCH success")
 
+@remote_compatible
 def test_hapd_ctrl_level(dev, apdev):
     """hostapd and LEVEL ctrl_iface command"""
     ssid = "hapd-ctrl"
     params = { "ssid": ssid }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     if "FAIL" not in hapd.request("LEVEL 0"):
         raise Exception("Unexpected LEVEL success on non-monitor interface")
 
+@remote_compatible
 def test_hapd_ctrl_new_sta(dev, apdev):
     """hostapd and NEW_STA ctrl_iface command"""
     ssid = "hapd-ctrl"
     params = { "ssid": ssid }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     if "FAIL" not in hapd.request("NEW_STA 00:11:22:33:44"):
         raise Exception("Unexpected NEW_STA success")
     if "OK" not in hapd.request("NEW_STA 00:11:22:33:44:55"):
@@ -131,39 +140,43 @@ def test_hapd_ctrl_new_sta(dev, apdev):
     if "AUTHORIZED" not in hapd.request("STA 00:11:22:33:44:55"):
         raise Exception("Unexpected NEW_STA STA status")
 
+@remote_compatible
 def test_hapd_ctrl_get(dev, apdev):
     """hostapd and GET ctrl_iface command"""
     ssid = "hapd-ctrl"
     params = { "ssid": ssid }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     if "FAIL" not in hapd.request("GET foo"):
         raise Exception("Unexpected GET success")
     if "FAIL" in hapd.request("GET version"):
         raise Exception("Unexpected GET version failure")
 
+@remote_compatible
 def test_hapd_ctrl_unknown(dev, apdev):
     """hostapd and unknown ctrl_iface command"""
     ssid = "hapd-ctrl"
     params = { "ssid": ssid }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     if "UNKNOWN COMMAND" not in hapd.request("FOO"):
         raise Exception("Unexpected response")
 
+@remote_compatible
 def test_hapd_ctrl_hs20_wnm_notif(dev, apdev):
     """hostapd and HS20_WNM_NOTIF ctrl_iface command"""
     ssid = "hapd-ctrl"
     params = { "ssid": ssid }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     if "FAIL" not in hapd.request("HS20_WNM_NOTIF 00:11:22:33:44 http://example.com/"):
         raise Exception("Unexpected HS20_WNM_NOTIF success")
     if "FAIL" not in hapd.request("HS20_WNM_NOTIF 00:11:22:33:44:55http://example.com/"):
         raise Exception("Unexpected HS20_WNM_NOTIF success")
 
+@remote_compatible
 def test_hapd_ctrl_hs20_deauth_req(dev, apdev):
     """hostapd and HS20_DEAUTH_REQ ctrl_iface command"""
     ssid = "hapd-ctrl"
     params = { "ssid": ssid }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     if "FAIL" not in hapd.request("HS20_DEAUTH_REQ 00:11:22:33:44 1 120 http://example.com/"):
         raise Exception("Unexpected HS20_DEAUTH_REQ success")
     if "FAIL" not in hapd.request("HS20_DEAUTH_REQ 00:11:22:33:44:55"):
@@ -171,11 +184,12 @@ def test_hapd_ctrl_hs20_deauth_req(dev, apdev):
     if "FAIL" not in hapd.request("HS20_DEAUTH_REQ 00:11:22:33:44:55 1"):
         raise Exception("Unexpected HS20_DEAUTH_REQ success")
 
+@remote_compatible
 def test_hapd_ctrl_disassoc_imminent(dev, apdev):
     """hostapd and DISASSOC_IMMINENT ctrl_iface command"""
     ssid = "hapd-ctrl"
     params = { "ssid": ssid }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     if "FAIL" not in hapd.request("DISASSOC_IMMINENT 00:11:22:33:44"):
         raise Exception("Unexpected DISASSOC_IMMINENT success")
     if "FAIL" not in hapd.request("DISASSOC_IMMINENT 00:11:22:33:44:55"):
@@ -190,11 +204,12 @@ def test_hapd_ctrl_disassoc_imminent(dev, apdev):
     if ev is None:
         raise Exception("Scan timed out")
 
+@remote_compatible
 def test_hapd_ctrl_ess_disassoc(dev, apdev):
     """hostapd and ESS_DISASSOC ctrl_iface command"""
     ssid = "hapd-ctrl"
     params = { "ssid": ssid }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     if "FAIL" not in hapd.request("ESS_DISASSOC 00:11:22:33:44"):
         raise Exception("Unexpected ESS_DISASSOCT success")
     if "FAIL" not in hapd.request("ESS_DISASSOC 00:11:22:33:44:55"):
@@ -217,7 +232,7 @@ def test_hapd_ctrl_set_deny_mac_file(dev, apdev):
     """hostapd and SET deny_mac_file ctrl_iface command"""
     ssid = "hapd-ctrl"
     params = { "ssid": ssid }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
     dev[1].connect(ssid, key_mgmt="NONE", scan_freq="2412")
     if "OK" not in hapd.request("SET deny_mac_file hostapd.macaddr"):
@@ -231,7 +246,7 @@ def test_hapd_ctrl_set_accept_mac_file(dev, apdev):
     """hostapd and SET accept_mac_file ctrl_iface command"""
     ssid = "hapd-ctrl"
     params = { "ssid": ssid }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
     dev[1].connect(ssid, key_mgmt="NONE", scan_freq="2412")
     hapd.request("SET macaddr_acl 1")
@@ -242,11 +257,12 @@ def test_hapd_ctrl_set_accept_mac_file(dev, apdev):
     if ev is not None:
         raise Exception("Unexpected disconnection")
 
+@remote_compatible
 def test_hapd_ctrl_set_error_cases(dev, apdev):
     """hostapd and SET error cases"""
     ssid = "hapd-ctrl"
     params = { "ssid": ssid }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     errors = [ "wpa_key_mgmt FOO",
                "wpa_key_mgmt WPA-PSK   \t  FOO",
                "wpa_key_mgmt    \t  ",
@@ -354,9 +370,9 @@ def test_hapd_ctrl_set_error_cases(dev, apdev):
                "beacon_int 65536",
                "acs_num_scans 0",
                "acs_num_scans 101",
-               "rts_threshold -1",
-               "rts_threshold 2348",
-               "fragm_threshold -1",
+               "rts_threshold -2",
+               "rts_threshold 65536",
+               "fragm_threshold -2",
                "fragm_threshold 2347",
                "send_probe_response -1",
                "send_probe_response 2",
@@ -391,6 +407,8 @@ def test_hapd_ctrl_set_error_cases(dev, apdev):
                "bss_load_test 12:80",
                "vendor_elements 0",
                "vendor_elements 0q",
+               "assocresp_elements 0",
+               "assocresp_elements 0q",
                "local_pwr_constraint -1",
                "local_pwr_constraint 256",
                "wmm_ac_bk_cwmin -1",
@@ -437,13 +455,14 @@ def test_hapd_ctrl_set_error_cases(dev, apdev):
         if "OK" not in hapd.request("SET " + e):
             raise Exception("Unexpected SET failure: '%s'" % e)
 
+@remote_compatible
 def test_hapd_ctrl_global(dev, apdev):
     """hostapd and GET ctrl_iface command"""
     ssid = "hapd-ctrl"
     params = { "ssid": ssid }
     ifname = apdev[0]['ifname']
-    hapd = hostapd.add_ap(ifname, params)
-    hapd_global = hostapd.HostapdGlobal()
+    hapd = hostapd.add_ap(apdev[0], params)
+    hapd_global = hostapd.HostapdGlobal(apdev[0])
     res = hapd_global.request("IFNAME=" + ifname + " PING")
     if "PONG" not in res:
             raise Exception("Could not ping hostapd interface " + ifname + " via global control interface")
@@ -465,11 +484,11 @@ def test_hapd_dup_network_global_wpa2(dev, apdev):
 
     src_params = hostapd.wpa2_params(ssid=src_ssid, passphrase=passphrase)
     src_ifname = apdev[0]['ifname']
-    src_hapd = hostapd.add_ap(src_ifname, src_params)
+    src_hapd = hostapd.add_ap(apdev[0], src_params)
 
     dst_params = { "ssid": dst_ssid }
     dst_ifname = apdev[1]['ifname']
-    dst_hapd = hostapd.add_ap(dst_ifname, dst_params, no_enable=True)
+    dst_hapd = hostapd.add_ap(apdev[1], dst_params, no_enable=True)
 
     hapd_global = hostapd.HostapdGlobal()
 
@@ -494,11 +513,11 @@ def test_hapd_dup_network_global_wpa(dev, apdev):
     src_params = hostapd.wpa_params(ssid=src_ssid)
     src_params['wpa_psk'] = psk
     src_ifname = apdev[0]['ifname']
-    src_hapd = hostapd.add_ap(src_ifname, src_params)
+    src_hapd = hostapd.add_ap(apdev[0], src_params)
 
     dst_params = { "ssid": dst_ssid }
     dst_ifname = apdev[1]['ifname']
-    dst_hapd = hostapd.add_ap(dst_ifname, dst_params, no_enable=True)
+    dst_hapd = hostapd.add_ap(apdev[1], dst_params, no_enable=True)
 
     hapd_global = hostapd.HostapdGlobal()
 
@@ -513,9 +532,10 @@ def test_hapd_dup_network_global_wpa(dev, apdev):
     if "FAIL" in dst_hapd.request("STA " + addr):
             raise Exception("Could not connect using duplicated wpa params")
 
+@remote_compatible
 def test_hapd_ctrl_log_level(dev, apdev):
     """hostapd ctrl_iface LOG_LEVEL"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     level = hapd.request("LOG_LEVEL")
     if "Current level: MSGDUMP" not in level:
         raise Exception("Unexpected debug level(1): " + level)
@@ -555,3 +575,136 @@ def test_hapd_ctrl_log_level(dev, apdev):
         raise Exception("Unexpected debug level(3): " + level)
     if "Timestamp: 1" not in level:
         raise Exception("Unexpected timestamp(3): " + level)
+
+@remote_compatible
+def test_hapd_ctrl_disconnect_no_tx(dev, apdev):
+    """hostapd disconnecting STA without transmitting Deauth/Disassoc"""
+    ssid = "hapd-test"
+    passphrase = "12345678"
+    params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+    dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
+    addr0 = dev[0].own_addr()
+    dev[1].connect(ssid, psk=passphrase, scan_freq="2412")
+    addr1 = dev[1].own_addr()
+
+    # Disconnect the STA without sending out Deauthentication frame
+    if "OK" not in hapd.request("DEAUTHENTICATE " + addr0 + " tx=0"):
+        raise Exception("DEAUTHENTICATE command failed")
+    # Force disconnection due to AP receiving a frame from not-asssociated STA
+    dev[0].request("DATA_TEST_CONFIG 1")
+    dev[0].request("DATA_TEST_TX " + bssid + " " + addr0)
+    ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=5)
+    dev[0].request("DATA_TEST_CONFIG 0")
+    if ev is None:
+        raise Exception("Disconnection event not seen after TX attempt")
+    if "reason=7" not in ev:
+        raise Exception("Unexpected disconnection reason: " + ev)
+
+    # Disconnect the STA without sending out Disassociation frame
+    if "OK" not in hapd.request("DISASSOCIATE " + addr1 + " tx=0"):
+        raise Exception("DISASSOCIATE command failed")
+    # Force disconnection due to AP receiving a frame from not-asssociated STA
+    dev[1].request("DATA_TEST_CONFIG 1")
+    dev[1].request("DATA_TEST_TX " + bssid + " " + addr1)
+    ev = dev[1].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=5)
+    dev[1].request("DATA_TEST_CONFIG 0")
+    if ev is None:
+        raise Exception("Disconnection event not seen after TX attempt")
+    if "reason=7" not in ev:
+        raise Exception("Unexpected disconnection reason: " + ev)
+
+def test_hapd_ctrl_mib(dev, apdev):
+    """hostapd and MIB ctrl_iface command with open network"""
+    ssid = "hapd-ctrl"
+    params = { "ssid": ssid }
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    mib = hapd.request("MIB")
+    if len(mib) != 0:
+        raise Exception("Unexpected MIB response: " + mib)
+
+    mib = hapd.request("MIB radius_server")
+    if len(mib) != 0:
+        raise Exception("Unexpected 'MIB radius_server' response: " + mib)
+
+    if "FAIL" not in hapd.request("MIB foo"):
+        raise Exception("'MIB foo' succeeded")
+
+    dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
+
+    mib = hapd.request("MIB")
+    if "FAIL" in mib:
+        raise Exception("Unexpected MIB response: " + mib)
+
+    mib = hapd.request("MIB radius_server")
+    if len(mib) != 0:
+        raise Exception("Unexpected 'MIB radius_server' response: " + mib)
+
+    if "FAIL" not in hapd.request("MIB foo"):
+        raise Exception("'MIB foo' succeeded")
+
+def test_hapd_ctrl_not_yet_fully_enabled(dev, apdev):
+    """hostapd and ctrl_iface commands when BSS not yet fully enabled"""
+    ssid = "hapd-ctrl"
+    params = { "ssid": ssid }
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
+
+    if not hapd.ping():
+        raise Exception("PING failed")
+    if "FAIL" in hapd.request("MIB"):
+        raise Exception("MIB failed")
+    if len(hapd.request("MIB radius_server")) != 0:
+        raise Exception("Unexpected 'MIB radius_server' response")
+    if "state=UNINITIALIZED" not in hapd.request("STATUS"):
+        raise Exception("Unexpected STATUS response")
+    if "FAIL" not in hapd.request("STATUS-DRIVER"):
+        raise Exception("Unexpected response to STATUS-DRIVER")
+    if len(hapd.request("STA-FIRST")) != 0:
+        raise Exception("Unexpected response to STA-FIRST")
+    if "FAIL" not in hapd.request("STA ff:ff:ff:ff:ff:ff"):
+        raise Exception("Unexpected response to STA")
+    cmds = [ "NEW_STA 02:ff:ff:ff:ff:ff",
+             "DEAUTHENTICATE 02:ff:ff:ff:ff:ff",
+             "DEAUTHENTICATE 02:ff:ff:ff:ff:ff test=0",
+             "DEAUTHENTICATE 02:ff:ff:ff:ff:ff p2p=0",
+             "DEAUTHENTICATE 02:ff:ff:ff:ff:ff tx=0",
+             "DISASSOCIATE 02:ff:ff:ff:ff:ff",
+             "DISASSOCIATE 02:ff:ff:ff:ff:ff test=0",
+             "DISASSOCIATE 02:ff:ff:ff:ff:ff p2p=0",
+             "DISASSOCIATE 02:ff:ff:ff:ff:ff tx=0",
+             "SA_QUERY 02:ff:ff:ff:ff:ff",
+             "WPS_PIN any 12345670",
+             "WPS_PBC",
+             "WPS_CANCEL",
+             "WPS_AP_PIN random",
+             "WPS_AP_PIN disable",
+             "WPS_CHECK_PIN 123456789",
+             "WPS_GET_STATUS",
+             "WPS_NFC_TAG_READ 00",
+             "WPS_NFC_CONFIG_TOKEN NDEF",
+             "WPS_NFC_TOKEN WPS",
+             "NFC_GET_HANDOVER_SEL NDEF WPS-CR",
+             "NFC_REPORT_HANDOVER RESP WPS 00 00",
+             "SET_QOS_MAP_SET 22,6,8,15,0,7,255,255,16,31,32,39,255,255,40,47,48,55",
+             "SEND_QOS_MAP_CONF 02:ff:ff:ff:ff:ff",
+             "HS20_WNM_NOTIF 02:ff:ff:ff:ff:ff https://example.com/",
+             "HS20_DEAUTH_REQ 02:ff:ff:ff:ff:ff 1 120 https://example.com/",
+             "DISASSOC_IMMINENT 02:ff:ff:ff:ff:ff 10",
+             "ESS_DISASSOC 02:ff:ff:ff:ff:ff 10 https://example.com/",
+             "BSS_TM_REQ 02:ff:ff:ff:ff:ff",
+             "GET_CONFIG",
+             "RADAR DETECTED freq=5260 ht_enabled=1 chan_width=1",
+             "CHAN_SWITCH 5 5200 ht sec_channel_offset=-1 bandwidth=40",
+             "TRACK_STA_LIST",
+             "PMKSA",
+             "PMKSA_FLUSH",
+             "SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\"",
+             "REMOVE_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\"",
+             "REQ_LCI 00:11:22:33:44:55",
+             "REQ_RANGE 00:11:22:33:44:55",
+             "DRIVER_FLAGS",
+             "STOP_AP" ]
+    for cmd in cmds:
+        hapd.request(cmd)
index cb91225..a3c0296 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 import time
@@ -12,17 +13,16 @@ import hostapd
 from utils import HwsimSkip
 
 def hostapd_oom_loop(apdev, params, start_func="main"):
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "ctrl" })
-    hapd_global = hostapd.HostapdGlobal()
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "ctrl" })
 
     count = 0
     for i in range(1, 1000):
         if "OK" not in hapd.request("TEST_ALLOC_FAIL %d:%s" % (i, start_func)):
             raise HwsimSkip("TEST_ALLOC_FAIL not supported")
         try:
-            hostapd.add_ap(apdev[1]['ifname'], params)
+            hostapd.add_ap(apdev[1], params, timeout=2.5)
             logger.info("Iteration %d - success" % i)
-            hapd_global.remove(apdev[1]['ifname'])
+            hostapd.remove_bss(apdev[1])
 
             state = hapd.request('GET_ALLOC_FAIL')
             logger.info("GET_ALLOC_FAIL: " + state)
@@ -38,6 +38,7 @@ def hostapd_oom_loop(apdev, params, start_func="main"):
         except Exception, e:
             logger.info("Iteration %d - %s" % (i, str(e)))
 
+@remote_compatible
 def test_hostapd_oom_open(dev, apdev):
     """hostapd failing to setup open mode due to OOM"""
     params = { "ssid": "open" }
@@ -49,6 +50,7 @@ def test_hostapd_oom_wpa2_psk(dev, apdev):
     params['wpa_psk_file'] = 'hostapd.wpa_psk'
     hostapd_oom_loop(apdev, params)
 
+@remote_compatible
 def test_hostapd_oom_wpa2_eap(dev, apdev):
     """hostapd failing to setup WPA2-EAP mode due to OOM"""
     params = hostapd.wpa2_eap_params(ssid="test")
@@ -57,6 +59,7 @@ def test_hostapd_oom_wpa2_eap(dev, apdev):
     params['acct_server_shared_secret'] = "radius"
     hostapd_oom_loop(apdev, params)
 
+@remote_compatible
 def test_hostapd_oom_wpa2_eap_radius(dev, apdev):
     """hostapd failing to setup WPA2-EAP mode due to OOM in RADIUS"""
     params = hostapd.wpa2_eap_params(ssid="test")
@@ -68,7 +71,7 @@ def test_hostapd_oom_wpa2_eap_radius(dev, apdev):
 def test_hostapd_oom_wpa2_psk_connect(dev, apdev):
     """hostapd failing during WPA2-PSK mode connection due to OOM"""
     params = hostapd.wpa2_params(ssid="test-wpa2-psk", passphrase="12345678")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].request("SCAN_INTERVAL 1")
     count = 0
@@ -114,7 +117,7 @@ def test_hostapd_oom_wpa2_eap_connect(dev, apdev, params):
     params['acct_server_addr'] = "127.0.0.1"
     params['acct_server_port'] = "1813"
     params['acct_server_shared_secret'] = "radius"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].request("SCAN_INTERVAL 1")
     count = 0
index 59faa8c..0640ef7 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 import time
@@ -11,7 +12,7 @@ import re
 import subprocess
 
 import hwsim_utils
-from utils import alloc_fail
+from utils import alloc_fail, wait_fail_trigger
 
 def connect_ibss_cmd(dev, id, freq=2412):
     dev.dump_monitor()
@@ -49,10 +50,12 @@ def wait_4way_handshake2(dev1, dev2, dev3):
 
 def add_ibss(dev, ssid, psk=None, proto=None, key_mgmt=None, pairwise=None,
              group=None, beacon_int=None, bssid=None, scan_freq=None,
-             wep_key0=None, freq=2412):
+             wep_key0=None, freq=2412, chwidth=0, group_rekey=0):
     id = dev.add_network()
     dev.set_network(id, "mode", "1")
     dev.set_network(id, "frequency", str(freq))
+    if chwidth > 0:
+        dev.set_network(id, "max_oper_chwidth", str(chwidth))
     if scan_freq:
         dev.set_network(id, "scan_freq", str(scan_freq))
     dev.set_network_quoted(id, "ssid", ssid)
@@ -72,11 +75,14 @@ def add_ibss(dev, ssid, psk=None, proto=None, key_mgmt=None, pairwise=None,
         dev.set_network(id, "bssid", bssid)
     if wep_key0:
         dev.set_network(id, "wep_key0", wep_key0)
+    if group_rekey:
+        dev.set_network(id, "group_rekey", str(group_rekey))
     dev.request("ENABLE_NETWORK " + str(id) + " no-connect")
     return id
 
-def add_ibss_rsn(dev, ssid):
-    return add_ibss(dev, ssid, "12345678", "RSN", "WPA-PSK", "CCMP", "CCMP")
+def add_ibss_rsn(dev, ssid, group_rekey=0, scan_freq=None):
+    return add_ibss(dev, ssid, "12345678", "RSN", "WPA-PSK", "CCMP", "CCMP",
+                    group_rekey=group_rekey, scan_freq=scan_freq)
 
 def add_ibss_rsn_tkip(dev, ssid):
     return add_ibss(dev, ssid, "12345678", "RSN", "WPA-PSK", "TKIP", "TKIP")
@@ -141,6 +147,39 @@ def test_ibss_rsn(dev):
     if "OK" not in dev[0].request("IBSS_RSN " + dev[1].p2p_interface_addr()):
         raise Exception("IBSS_RSN command failed")
 
+    key_mgmt = dev[0].get_status_field("key_mgmt")
+    if key_mgmt != "WPA2-PSK":
+        raise Exception("Unexpected STATUS key_mgmt: " + key_mgmt)
+
+def test_ibss_rsn_group_rekey(dev):
+    """IBSS RSN group rekeying"""
+    ssid="ibss-rsn"
+
+    logger.info("Start IBSS on the first STA")
+    id = add_ibss_rsn(dev[0], ssid, group_rekey=4, scan_freq=2412)
+    connect_ibss_cmd(dev[0], id)
+    bssid0 = wait_ibss_connection(dev[0])
+    dev[0].dump_monitor()
+
+    logger.info("Join two STAs to the IBSS")
+
+    dev[1].scan_for_bss(bssid0, freq=2412)
+    id = add_ibss_rsn(dev[1], ssid, scan_freq=2412)
+    connect_ibss_cmd(dev[1], id)
+    bssid1 = wait_ibss_connection(dev[1])
+    if bssid0 != bssid1:
+        raise Exception("STA0 BSSID " + bssid0 + " differs from STA1 BSSID " + bssid1)
+    wait_4way_handshake(dev[0], dev[1])
+    wait_4way_handshake(dev[1], dev[0])
+    dev[0].dump_monitor()
+    dev[1].dump_monitor()
+
+    hwsim_utils.test_connectivity(dev[0], dev[1])
+    ev = dev[1].wait_event(["WPA: Group rekeying completed"], timeout=10)
+    if ev is None:
+        raise Exception("No group rekeying reported")
+    hwsim_utils.test_connectivity(dev[0], dev[1])
+
 def test_ibss_wpa_none(dev):
     """IBSS WPA-None"""
     ssid="ibss-wpa-none"
@@ -205,6 +244,10 @@ def test_ibss_wpa_none(dev):
     except Exception, e:
         logger.info("Ignoring known connectivity failure: " + str(e))
 
+    key_mgmt = dev[0].get_status_field("key_mgmt")
+    if key_mgmt != "WPA-NONE":
+        raise Exception("Unexpected STATUS key_mgmt: " + key_mgmt)
+
 def test_ibss_wpa_none_ccmp(dev):
     """IBSS WPA-None/CCMP"""
     ssid="ibss-wpa-none"
@@ -272,6 +315,15 @@ def test_ibss_open(dev):
     if "[IBSS]" not in bss['flags']:
         raise Exception("Unexpected BSS flags: " + bss['flags'])
 
+    freq0 = dev[0].get_status_field("freq")
+    freq1 = dev[1].get_status_field("freq")
+    if freq0 != "2412" or freq1 != "2412":
+        raise Exception("IBSS operating frequency not reported correctly (%s %s)" % (freq0, freq1))
+
+    key_mgmt = dev[0].get_status_field("key_mgmt")
+    if key_mgmt != "NONE":
+        raise Exception("Unexpected STATUS key_mgmt: " + key_mgmt)
+
 def test_ibss_open_fixed_bssid(dev):
     """IBSS open (no security) and fixed BSSID"""
     ssid="ibss"
@@ -346,6 +398,7 @@ def test_ibss_wep(dev):
     connect_ibss_cmd(dev[1], id)
     bssid1 = wait_ibss_connection(dev[1])
 
+@remote_compatible
 def test_ibss_rsn_error_case(dev):
     """IBSS RSN regression test for IBSS_RSN prior IBSS setup"""
     if "FAIL" not in dev[0].request("IBSS_RSN 02:03:04:05:06:07"):
@@ -388,10 +441,144 @@ def _test_ibss_5ghz(dev):
     dev[0].dump_monitor()
     dev[1].dump_monitor()
 
+def test_ibss_vht_80p80(dev):
+    """IBSS on VHT 80+80 MHz channel"""
+    try:
+        _test_ibss_vht_80p80(dev)
+    finally:
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        dev[0].flush_scan_cache()
+        dev[1].flush_scan_cache()
+
+def _test_ibss_vht_80p80(dev):
+    subprocess.call(['iw', 'reg', 'set', 'US'])
+    for i in range(2):
+        for j in range(5):
+            ev = dev[i].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=5)
+            if ev is None:
+                raise Exception("No regdom change event")
+            if "alpha2=US" in ev:
+                break
+        dev[i].dump_monitor()
+
+    ssid="ibss"
+    id = add_ibss(dev[0], ssid, key_mgmt="NONE", freq=5180, chwidth=3)
+    connect_ibss_cmd(dev[0], id, freq=5180)
+    bssid0 = wait_ibss_connection(dev[0])
+    sig = dev[0].request("SIGNAL_POLL").splitlines()
+    if "FREQUENCY=5180" not in sig:
+        raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
+    if "WIDTH=80+80 MHz" not in sig:
+        raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
+    if "CENTER_FRQ1=5210" not in sig:
+        raise Exception("Unexpected SIGNAL_POLL value(3): " + str(sig))
+    if "CENTER_FRQ2=5775" not in sig:
+        raise Exception("Unexpected SIGNAL_POLL value(4): " + str(sig))
+
+    dev[1].scan_for_bss(bssid0, freq=5180)
+    id = add_ibss(dev[1], ssid, key_mgmt="NONE", freq=5180, chwidth=3)
+    connect_ibss_cmd(dev[1], id, freq=5180)
+    bssid1 = wait_ibss_connection(dev[1])
+    if bssid0 != bssid1:
+        logger.info("STA0 BSSID " + bssid0 + " differs from STA1 BSSID " + bssid1)
+
+    sig = dev[1].request("SIGNAL_POLL").splitlines()
+    if "FREQUENCY=5180" not in sig:
+        raise Exception("Unexpected SIGNAL_POLL value(1b): " + str(sig))
+    logger.info("STA1 SIGNAL_POLL: " + str(sig))
+    # For now, don't report errors on joining STA failing to get 80+80 MHZ
+    # since mac80211 missed functionality for that to work.
+
+    dev[0].request("DISCONNECT")
+    dev[1].request("DISCONNECT")
+    dev[0].dump_monitor()
+    dev[1].dump_monitor()
+
 def test_ibss_rsn_oom(dev):
     """IBSS RSN OOM during wpa_init"""
     with alloc_fail(dev[0], 1, "wpa_init"):
         ssid="ibss-rsn"
-        id = add_ibss_rsn(dev[0], ssid)
+        id = add_ibss_rsn(dev[0], ssid, scan_freq=2412)
         connect_ibss_cmd(dev[0], id)
         bssid0 = wait_ibss_connection(dev[0])
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].dump_monitor()
+
+    with alloc_fail(dev[0], 1, "=ibss_rsn_init"):
+        ssid="ibss-rsn"
+        id = add_ibss_rsn(dev[0], ssid, scan_freq=2412)
+        connect_ibss_cmd(dev[0], id)
+        bssid0 = wait_ibss_connection(dev[0])
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].dump_monitor()
+
+def send_eapol_rx(dev, dst):
+    if "OK" not in dev.request("EAPOL_RX %s 0203005f02008a001000000000000000013a54fb19d8a785f5986bdc2ba800553550bc9513e6603eb50809154588c22b110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" % dst):
+        raise Exception("EAPOL_RX for %s failed" % dst)
+
+def test_ibss_rsn_eapol_trigger(dev):
+    """IBSS RSN and EAPOL trigger for a new peer"""
+    ssid="ibss-rsn"
+
+    id = add_ibss_rsn(dev[0], ssid, scan_freq=2412)
+    connect_ibss_cmd(dev[0], id)
+    bssid0 = wait_ibss_connection(dev[0])
+
+    send_eapol_rx(dev[0], "02:ff:00:00:00:01")
+    send_eapol_rx(dev[0], "02:ff:00:00:00:01")
+
+    dst = "02:ff:00:00:00:01"
+    logger.info("Too short EAPOL frame")
+    if "OK" not in dev[0].request("EAPOL_RX %s 0203005e02008a001000000000000000013a54fb19d8a785f5986bdc2ba800553550bc9513e6603eb50809154588c22b1100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" % dst):
+        raise Exception("EAPOL_RX for %s failed" % dst)
+    logger.info("RSN: EAPOL frame (type 255) discarded, not a Key frame")
+    if "OK" not in dev[0].request("EAPOL_RX %s 02ff005f02008a001000000000000000013a54fb19d8a785f5986bdc2ba800553550bc9513e6603eb50809154588c22b110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" % dst):
+        raise Exception("EAPOL_RX for %s failed" % dst)
+    logger.info("RSN: EAPOL frame payload size 96 invalid (frame size 99)")
+    if "OK" not in dev[0].request("EAPOL_RX %s 0203006002008a001000000000000000013a54fb19d8a785f5986bdc2ba800553550bc9513e6603eb50809154588c22b110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" % dst):
+        raise Exception("EAPOL_RX for %s failed" % dst)
+    logger.info("RSN: EAPOL-Key type (255) unknown, discarded")
+    if "OK" not in dev[0].request("EAPOL_RX %s 0203005fff008a001000000000000000013a54fb19d8a785f5986bdc2ba800553550bc9513e6603eb50809154588c22b110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" % dst):
+        raise Exception("EAPOL_RX for %s failed" % dst)
+
+    with alloc_fail(dev[0], 1, "ibss_rsn_rx_eapol"):
+        send_eapol_rx(dev[0], "02:ff:00:00:00:02")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+    with alloc_fail(dev[0], 1, "wpa_auth_sta_init;ibss_rsn_auth_init"):
+        send_eapol_rx(dev[0], "02:ff:00:00:00:03")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+    with alloc_fail(dev[0], 1, "=ibss_rsn_peer_init"):
+        send_eapol_rx(dev[0], "02:ff:00:00:00:04")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+    with alloc_fail(dev[0], 1, "ibss_rsn_process_rx_eapol"):
+        send_eapol_rx(dev[0], "02:ff:00:00:00:05")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+    with alloc_fail(dev[0], 1,
+                    "wpa_sm_set_assoc_wpa_ie_default;ibss_rsn_supp_init"):
+        send_eapol_rx(dev[0], "02:ff:00:00:00:06")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+    with alloc_fail(dev[0], 1, "wpa_sm_init;ibss_rsn_supp_init"):
+        send_eapol_rx(dev[0], "02:ff:00:00:00:07")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+    with alloc_fail(dev[0], 1, "=ibss_rsn_supp_init"):
+        send_eapol_rx(dev[0], "02:ff:00:00:00:08")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+    with alloc_fail(dev[0], 1, "supp_alloc_eapol"):
+        send_eapol_rx(dev[0], "02:ff:00:00:00:09")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+    with alloc_fail(dev[0], 1, "wpa_validate_wpa_ie;ibss_rsn_auth_init"):
+        send_eapol_rx(dev[0], "02:ff:00:00:00:0a")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+    logger.info("RSN: Timeout on waiting Authentication frame response")
+    if "OK" not in dev[0].request("IBSS_RSN 02:ff:00:00:00:0b"):
+        raise Exception("Unexpected IBSS_RSN result")
+    time.sleep(1.1)
index d35a4d4..92b1cb7 100644 (file)
@@ -4,14 +4,17 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import binascii
 import hmac
 import logging
+import os
 import time
 
 import hostapd
 import hwsim_utils
 from utils import skip_with_fips
+from tshark import run_tshark
 
 logger = logging.getLogger()
 
@@ -23,7 +26,7 @@ def test_ieee8021x_wep104(dev, apdev):
     params["ieee8021x"] = "1"
     params["wep_key_len_broadcast"] = "13"
     params["wep_key_len_unicast"] = "13"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("ieee8021x-wep", key_mgmt="IEEE8021X", eap="PSK",
                    identity="psk.user@example.com",
@@ -39,7 +42,7 @@ def test_ieee8021x_wep40(dev, apdev):
     params["ieee8021x"] = "1"
     params["wep_key_len_broadcast"] = "5"
     params["wep_key_len_unicast"] = "5"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("ieee8021x-wep", key_mgmt="IEEE8021X", eap="PSK",
                    identity="psk.user@example.com",
@@ -52,7 +55,7 @@ def test_ieee8021x_open(dev, apdev):
     params = hostapd.radius_params()
     params["ssid"] = "ieee8021x-open"
     params["ieee8021x"] = "1"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     id = dev[0].connect("ieee8021x-open", key_mgmt="IEEE8021X", eapol_flags="0",
                         eap="PSK", identity="psk.user@example.com",
@@ -78,7 +81,7 @@ def test_ieee8021x_static_wep40(dev, apdev):
     params["ssid"] = "ieee8021x-wep"
     params["ieee8021x"] = "1"
     params["wep_key0"] = '"hello"'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("ieee8021x-wep", key_mgmt="IEEE8021X", eap="PSK",
                    identity="psk.user@example.com",
@@ -92,7 +95,7 @@ def test_ieee8021x_proto(dev, apdev):
     params = hostapd.radius_params()
     params["ssid"] = "ieee8021x-open"
     params["ieee8021x"] = "1"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
 
     dev[1].request("SET ext_eapol_frame_io 1")
@@ -133,12 +136,13 @@ def test_ieee8021x_proto(dev, apdev):
         if int(stop[val]) <= int(start[val]):
             raise Exception(val + " did not increase")
 
+@remote_compatible
 def test_ieee8021x_eapol_start(dev, apdev):
     """IEEE 802.1X and EAPOL-Start retransmissions"""
     params = hostapd.radius_params()
     params["ssid"] = "ieee8021x-open"
     params["ieee8021x"] = "1"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
     addr0 = dev[0].own_addr()
 
@@ -172,7 +176,7 @@ def test_ieee8021x_held(dev, apdev):
     params = hostapd.radius_params()
     params["ssid"] = "ieee8021x-open"
     params["ieee8021x"] = "1"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
 
     hapd.set("ext_eapol_frame_io", "1")
@@ -231,7 +235,7 @@ def test_ieee8021x_eapol_key(dev, apdev):
     params["ieee8021x"] = "1"
     params["wep_key_len_broadcast"] = "5"
     params["wep_key_len_unicast"] = "5"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
 
     dev[0].connect("ieee8021x-wep", key_mgmt="IEEE8021X", eap="VENDOR-TEST",
@@ -271,7 +275,7 @@ def test_ieee8021x_reauth(dev, apdev):
     params = hostapd.radius_params()
     params["ssid"] = "ieee8021x-open"
     params["ieee8021x"] = "1"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("ieee8021x-open", key_mgmt="IEEE8021X", eapol_flags="0",
                    eap="PSK", identity="psk.user@example.com",
@@ -288,12 +292,65 @@ def test_ieee8021x_reauth(dev, apdev):
     time.sleep(0.1)
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+def test_ieee8021x_reauth_wep(dev, apdev, params):
+    """IEEE 802.1X and EAPOL_REAUTH request with WEP"""
+    logdir = params['logdir']
+
+    params = hostapd.radius_params()
+    params["ssid"] = "ieee8021x-open"
+    params["ieee8021x"] = "1"
+    params["wep_key_len_broadcast"] = "13"
+    params["wep_key_len_unicast"] = "13"
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].connect("ieee8021x-open", key_mgmt="IEEE8021X",
+                   eap="PSK", identity="psk.user@example.com",
+                   password_hex="0123456789abcdef0123456789abcdef",
+                   scan_freq="2412")
+    hwsim_utils.test_connectivity(dev[0], hapd)
+
+    hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
+    if ev is None:
+        raise Exception("EAP authentication did not start")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=5)
+    if ev is None:
+        raise Exception("EAP authentication did not succeed")
+    time.sleep(0.1)
+    hwsim_utils.test_connectivity(dev[0], hapd)
+
+    out = run_tshark(os.path.join(logdir, "hwsim0.pcapng"),
+                     "llc.type == 0x888e", ["eapol.type", "eap.code"])
+    if out is None:
+        raise Exception("Could not find EAPOL frames in capture")
+    num_eapol_key = 0
+    num_eap_req = 0
+    num_eap_resp = 0
+    for line in out.splitlines():
+        vals = line.split()
+        if vals[0] == '3':
+            num_eapol_key += 1
+        if vals[0] == '0' and len(vals) == 2:
+            if vals[1] == '1':
+                num_eap_req += 1
+            elif vals[1] == '2':
+                num_eap_resp += 1
+    logger.info("num_eapol_key: %d" % num_eapol_key)
+    logger.info("num_eap_req: %d" % num_eap_req)
+    logger.info("num_eap_resp: %d" % num_eap_resp)
+    if num_eapol_key < 4:
+        raise Exception("Did not see four unencrypted EAPOL-Key frames")
+    if num_eap_req < 6:
+        raise Exception("Did not see six unencrypted EAP-Request frames")
+    if num_eap_resp < 6:
+        raise Exception("Did not see six unencrypted EAP-Response frames")
+
 def test_ieee8021x_set_conf(dev, apdev):
     """IEEE 802.1X and EAPOL_SET command"""
     params = hostapd.radius_params()
     params["ssid"] = "ieee8021x-open"
     params["ieee8021x"] = "1"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("ieee8021x-open", key_mgmt="IEEE8021X", eapol_flags="0",
                    eap="PSK", identity="psk.user@example.com",
@@ -346,7 +403,7 @@ def test_ieee8021x_auth_awhile(dev, apdev):
     params["ssid"] = "ieee8021x-open"
     params["ieee8021x"] = "1"
     params['auth_server_port'] = "18129"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
     addr0 = dev[0].own_addr()
 
@@ -360,7 +417,7 @@ def test_ieee8021x_auth_awhile(dev, apdev):
     params['ca_cert'] = 'auth_serv/ca.pem'
     params['server_cert'] = 'auth_serv/server.pem'
     params['private_key'] = 'auth_serv/server.key'
-    hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd1 = hostapd.add_ap(apdev[1], params)
 
     dev[0].connect("ieee8021x-open", key_mgmt="IEEE8021X", eapol_flags="0",
                    eap="PSK", identity="psk.user@example.com",
@@ -391,3 +448,37 @@ def test_ieee8021x_auth_awhile(dev, apdev):
     ev = hapd.wait_event(["CTRL-EVENT-EAP-PROPOSED"], timeout=10)
     if ev is None:
         raise Exception("Authentication restart not seen")
+
+def test_ieee8021x_open_leap(dev, apdev):
+    """IEEE 802.1X connection with LEAP included in configuration"""
+    params = hostapd.radius_params()
+    params["ssid"] = "ieee8021x-open"
+    params["ieee8021x"] = "1"
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[1].connect("ieee8021x-open", key_mgmt="IEEE8021X", eapol_flags="0",
+                   eap="LEAP", identity="psk.user@example.com",
+                   password_hex="0123456789abcdef0123456789abcdef",
+                   scan_freq="2412", wait_connect=False)
+    dev[0].connect("ieee8021x-open", key_mgmt="IEEE8021X", eapol_flags="0",
+                   eap="PSK LEAP", identity="psk.user@example.com",
+                   password_hex="0123456789abcdef0123456789abcdef",
+                   scan_freq="2412")
+    ev = dev[1].wait_event(["CTRL-EVENT-AUTH-REJECT"], timeout=5)
+    dev[1].request("DISCONNECT")
+
+def test_ieee8021x_and_wpa_enabled(dev, apdev):
+    """IEEE 802.1X connection using dynamic WEP104 when WPA enabled"""
+    skip_with_fips(dev[0])
+    params = hostapd.radius_params()
+    params["ssid"] = "ieee8021x-wep"
+    params["ieee8021x"] = "1"
+    params["wep_key_len_broadcast"] = "13"
+    params["wep_key_len_unicast"] = "13"
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].connect("ieee8021x-wep", key_mgmt="IEEE8021X WPA-EAP", eap="PSK",
+                   identity="psk.user@example.com",
+                   password_hex="0123456789abcdef0123456789abcdef",
+                   scan_freq="2412")
+    hwsim_utils.test_connectivity(dev[0], hapd)
index 7af8724..bfc9a15 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 import time
@@ -45,11 +46,12 @@ def test_monitor_iface_wpa2_psk(dev, apdev):
 def test_monitor_iface_multi_bss(dev, apdev):
     """AP mode mmonitor interface with hostapd multi-BSS setup"""
     params = { "ssid": "monitor-iface", "driver_params": "use_monitor=1" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-    hostapd.add_bss('phy3', apdev[0]['ifname'] + '-2', 'bss-2.conf')
+    hapd = hostapd.add_ap(apdev[0], params)
+    hostapd.add_bss(apdev[0], apdev[0]['ifname'] + '-2', 'bss-2.conf')
     dev[0].connect("monitor-iface", key_mgmt="NONE", scan_freq="2412")
     dev[1].connect("bss-2", key_mgmt="NONE", scan_freq="2412")
 
+@remote_compatible
 def test_monitor_iface_unknown_sta(dev, apdev):
     """AP mode monitor interface and Data frame from unknown STA"""
     ssid = "monitor-iface-pmf"
@@ -58,7 +60,7 @@ def test_monitor_iface_unknown_sta(dev, apdev):
     params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
     params["ieee80211w"] = "2"
     params['driver_params'] = "use_monitor=1"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     bssid = apdev[0]['bssid']
     addr = dev[0].p2p_interface_addr()
index 7b5ddae..3139dc4 100644 (file)
@@ -4,8 +4,8 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import time
-import subprocess
 import logging
 logger = logging.getLogger(__name__)
 
@@ -41,8 +41,14 @@ def check_ip_addr(res):
 
 def test_nfc_p2p_go_neg(dev):
     """NFC connection handover to form a new P2P group (initiator becomes GO)"""
+    try:
+        _test_nfc_p2p_go_neg(dev)
+    finally:
+        dev[0].global_request("SET p2p_go_intent 7")
+
+def _test_nfc_p2p_go_neg(dev):
     set_ip_addr_info(dev[0])
-    ip = dev[0].request("GET ip_addr_go")
+    ip = dev[0].p2pdev_request("GET ip_addr_go")
     if ip != "192.168.42.1":
         raise Exception("Unexpected ip_addr_go returned: " + ip)
     dev[0].global_request("SET p2p_go_intent 10")
@@ -86,8 +92,14 @@ def test_nfc_p2p_go_neg(dev):
 
 def test_nfc_p2p_go_neg_ip_pool_oom(dev):
     """NFC connection handover to form a new P2P group and IP pool OOM"""
+    try:
+        _test_nfc_p2p_go_neg_ip_pool_oom(dev)
+    finally:
+        dev[0].global_request("SET p2p_go_intent 7")
+
+def _test_nfc_p2p_go_neg_ip_pool_oom(dev):
     set_ip_addr_info(dev[0])
-    ip = dev[0].request("GET ip_addr_go")
+    ip = dev[0].p2pdev_request("GET ip_addr_go")
     if ip != "192.168.42.1":
         raise Exception("Unexpected ip_addr_go returned: " + ip)
     dev[0].global_request("SET p2p_go_intent 10")
@@ -132,6 +144,12 @@ def test_nfc_p2p_go_neg_ip_pool_oom(dev):
 
 def test_nfc_p2p_go_neg_reverse(dev):
     """NFC connection handover to form a new P2P group (responder becomes GO)"""
+    try:
+        _test_nfc_p2p_go_neg_reverse(dev)
+    finally:
+        dev[0].global_request("SET p2p_go_intent 7")
+
+def _test_nfc_p2p_go_neg_reverse(dev):
     set_ip_addr_info(dev[1])
     dev[0].global_request("SET p2p_go_intent 3")
     logger.info("Perform NFC connection handover")
@@ -267,11 +285,12 @@ def test_nfc_p2p_both_go(dev):
 def test_nfc_p2p_client(dev):
     """NFC connection handover when one device is P2P client"""
     logger.info("Start autonomous GOs")
-    dev[0].p2p_start_go()
+    go_res = dev[0].p2p_start_go()
     logger.info("Connect one device as a P2P client")
     pin = dev[1].wps_read_pin()
     dev[0].p2p_go_authorize_client(pin)
-    dev[1].p2p_connect_group(dev[0].p2p_dev_addr(), pin, timeout=60)
+    dev[1].p2p_connect_group(dev[0].p2p_dev_addr(), pin,
+                             freq=int(go_res['freq']), timeout=60)
     logger.info("Client connected")
     hwsim_utils.test_connectivity_p2p(dev[0], dev[1])
 
@@ -301,7 +320,8 @@ def test_nfc_p2p_client(dev):
     logger.info("Connect to group based on upper layer trigger")
     pin = dev[2].wps_read_pin()
     dev[0].p2p_go_authorize_client(pin)
-    dev[2].p2p_connect_group(dev[0].p2p_dev_addr(), pin, timeout=60)
+    dev[2].p2p_connect_group(dev[0].p2p_dev_addr(), pin,
+                             freq=int(go_res['freq']), timeout=60)
     logger.info("Client connected")
     hwsim_utils.test_connectivity_p2p(dev[0], dev[1])
     hwsim_utils.test_connectivity_p2p(dev[1], dev[2])
@@ -311,7 +331,12 @@ def test_nfc_p2p_client(dev):
 
 def test_nfc_p2p_static_handover_tagdev_client(dev):
     """NFC static handover to form a new P2P group (NFC Tag device becomes P2P Client)"""
+    try:
+        _test_nfc_p2p_static_handover_tagdev_client(dev)
+    finally:
+        dev[0].global_request("SET p2p_go_intent 7")
 
+def _test_nfc_p2p_static_handover_tagdev_client(dev):
     set_ip_addr_info(dev[0])
 
     logger.info("Perform NFC connection handover")
@@ -358,7 +383,12 @@ def test_nfc_p2p_static_handover_tagdev_client(dev):
 
 def test_nfc_p2p_static_handover_tagdev_client_group_iface(dev):
     """NFC static handover to form a new P2P group (NFC Tag device becomes P2P Client with group iface)"""
+    try:
+        _test_nfc_p2p_static_handover_tagdev_client_group_iface(dev)
+    finally:
+        dev[0].global_request("SET p2p_go_intent 7")
 
+def _test_nfc_p2p_static_handover_tagdev_client_group_iface(dev):
     set_ip_addr_info(dev[0])
 
     logger.info("Perform NFC connection handover")
@@ -406,7 +436,12 @@ def test_nfc_p2p_static_handover_tagdev_client_group_iface(dev):
 
 def test_nfc_p2p_static_handover_tagdev_go(dev):
     """NFC static handover to form a new P2P group (NFC Tag device becomes GO)"""
+    try:
+        _test_nfc_p2p_static_handover_tagdev_go(dev)
+    finally:
+        dev[0].global_request("SET p2p_go_intent 7")
 
+def _test_nfc_p2p_static_handover_tagdev_go(dev):
     set_ip_addr_info(dev[1])
 
     logger.info("Perform NFC connection handover")
@@ -453,7 +488,12 @@ def test_nfc_p2p_static_handover_tagdev_go(dev):
 
 def test_nfc_p2p_static_handover_tagdev_go_forced_freq(dev):
     """NFC static handover to form a new P2P group on forced channel (NFC Tag device becomes GO)"""
+    try:
+        _test_nfc_p2p_static_handover_tagdev_go_forced_freq(dev)
+    finally:
+        dev[0].global_request("SET p2p_go_intent 7")
 
+def _test_nfc_p2p_static_handover_tagdev_go_forced_freq(dev):
     set_ip_addr_info(dev[1])
 
     logger.info("Perform NFC connection handover")
@@ -542,6 +582,13 @@ def test_nfc_p2p_static_handover_join_tagdev_go(dev):
 
 def test_nfc_p2p_static_handover_join_tagdev_client(dev):
     """NFC static handover to join a P2P group (NFC Tag device is the P2P Client)"""
+    try:
+        _test_nfc_p2p_static_handover_join_tagdev_client(dev)
+    finally:
+        dev[1].global_request("SET ignore_old_scan_res 0")
+        dev[2].global_request("SET ignore_old_scan_res 0")
+
+def _test_nfc_p2p_static_handover_join_tagdev_client(dev):
     set_ip_addr_info(dev[0])
     logger.info("Start autonomous GO")
     dev[0].p2p_start_go()
@@ -643,6 +690,12 @@ def test_nfc_p2p_go_legacy_handover(dev):
 
 def test_nfc_p2p_ip_addr_assignment(dev):
     """NFC connection handover and legacy station IP address assignment"""
+    try:
+        _test_nfc_p2p_ip_addr_assignment(dev)
+    finally:
+        dev[0].global_request("SET p2p_go_intent 7")
+
+def _test_nfc_p2p_ip_addr_assignment(dev):
     set_ip_addr_info(dev[1])
     dev[0].global_request("SET p2p_go_intent 3")
     logger.info("Perform NFC connection handover")
@@ -698,6 +751,12 @@ def test_nfc_p2p_ip_addr_assignment(dev):
 
 def test_nfc_p2p_ip_addr_assignment2(dev):
     """NFC connection handover and IP address assignment for two clients"""
+    try:
+        _test_nfc_p2p_ip_addr_assignment2(dev)
+    finally:
+        dev[0].global_request("SET p2p_go_intent 7")
+
+def _test_nfc_p2p_ip_addr_assignment2(dev):
     set_ip_addr_info(dev[1])
     dev[0].global_request("SET p2p_go_intent 3")
     logger.info("Perform NFC connection handover")
@@ -750,6 +809,7 @@ def test_nfc_p2p_ip_addr_assignment2(dev):
     if res['ip_addr'] == res0['ip_addr']:
         raise Exception("Same IP address assigned to both clients")
 
+@remote_compatible
 def test_nfc_p2p_tag_enable_disable(dev):
     """NFC tag enable/disable for P2P"""
     if "FAIL" in dev[0].request("WPS_NFC_TOKEN NDEF").rstrip():
@@ -769,6 +829,7 @@ def test_nfc_p2p_tag_enable_disable(dev):
     if "OK" not in dev[0].request("P2P_SET nfc_tag 0"):
         raise Exception("Failed to disable NFC Tag for P2P static handover")
 
+@remote_compatible
 def test_nfc_p2p_static_handover_invalid(dev):
     """NFC static handover with invalid contents"""
     logger.info("Unknown OOB GO Neg channel")
index 22d599b..0b6cd11 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import time
 import subprocess
 import logging
@@ -34,12 +35,12 @@ def ap_wps_params(ssid):
              "wpa_passphrase": "12345678", "wpa": "2",
              "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"}
 
+@remote_compatible
 def test_nfc_wps_password_token_sta(dev, apdev):
     """NFC tag with password token on the station/Enrollee"""
     ssid = "test-wps-nfc-pw-token-conf"
     params = ap_wps_params(ssid)
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     logger.info("WPS provisioning step using password token from station")
     wps = dev[0].request("WPS_NFC_TOKEN WPS").rstrip()
     if "FAIL" in wps:
@@ -61,8 +62,7 @@ def test_nfc_wps_config_token(dev, apdev):
     """NFC tag with configuration token from AP"""
     ssid = "test-wps-nfc-conf-token"
     params = ap_wps_params(ssid)
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     logger.info("NFC configuration token from AP to station")
     conf = hapd.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip()
     if "FAIL" in conf:
@@ -82,9 +82,8 @@ def test_nfc_wps_config_token(dev, apdev):
 def test_nfc_wps_config_token_init(dev, apdev):
     """NFC tag with configuration token from AP with auto configuration"""
     ssid = "test-wps-nfc-conf-token-init"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
     logger.info("NFC configuration token from AP to station")
     conf = hapd.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip()
     if "FAIL" in conf:
@@ -96,12 +95,12 @@ def test_nfc_wps_config_token_init(dev, apdev):
     dev[0].wait_connected(timeout=15)
     check_wpa2_connection(dev[0], apdev[0], hapd, ssid, mixed=True)
 
+@remote_compatible
 def test_nfc_wps_password_token_sta_init(dev, apdev):
     """Initial AP configuration with first WPS NFC Enrollee"""
     ssid = "test-wps-nfc-pw-token-init"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
     logger.info("WPS provisioning step using password token from station")
     pw = dev[0].request("WPS_NFC_TOKEN NDEF").rstrip()
     if "FAIL" in pw:
@@ -116,12 +115,12 @@ def test_nfc_wps_password_token_sta_init(dev, apdev):
     dev[0].wait_connected(timeout=30)
     check_wpa2_connection(dev[0], apdev[0], hapd, ssid, mixed=True)
 
+@remote_compatible
 def test_nfc_wps_password_token_ap(dev, apdev):
     """WPS registrar configuring an AP using AP password token"""
     ssid = "test-wps-nfc-pw-token-init"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
     logger.info("WPS configuration step")
     pw = hapd.request("WPS_NFC_TOKEN NDEF").rstrip()
     if "FAIL" in pw:
@@ -154,11 +153,16 @@ def test_nfc_wps_password_token_ap(dev, apdev):
 
 def test_nfc_wps_handover_init(dev, apdev):
     """Connect to WPS AP with NFC connection handover and move to configured state"""
+    try:
+        _test_nfc_wps_handover_init(dev, apdev)
+    finally:
+        dev[0].request("SET ignore_old_scan_res 0")
+
+def _test_nfc_wps_handover_init(dev, apdev):
     dev[0].request("SET ignore_old_scan_res 1")
     ssid = "test-wps-nfc-handover-init"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
     logger.info("NFC connection handover")
     req = dev[0].request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip()
     if "FAIL" in req:
@@ -180,12 +184,12 @@ def test_nfc_wps_handover_init(dev, apdev):
         if "FAIL" not in hapd.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR"):
             raise Exception("Unexpected NFC_GET_HANDOVER_SEL success during OOM")
 
+@remote_compatible
 def test_nfc_wps_handover_errors(dev, apdev):
     """WPS AP NFC handover report error cases"""
     ssid = "test-wps-nfc-handover"
-    hostapd.add_ap(apdev[0]['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0],
+                          { "ssid": ssid, "eap_server": "1", "wps_state": "1" })
     sel = hapd.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip()
     if "FAIL" in sel:
         raise Exception("Failed to generate NFC connection handover select")
@@ -214,8 +218,7 @@ def test_nfc_wps_handover(dev, apdev):
     """Connect to WPS AP with NFC connection handover"""
     ssid = "test-wps-nfc-handover"
     params = ap_wps_params(ssid)
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     logger.info("NFC connection handover")
     req = dev[0].request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip()
     if "FAIL" in req:
@@ -235,13 +238,14 @@ def test_nfc_wps_handover(dev, apdev):
 
 def test_nfc_wps_handover_5ghz(dev, apdev):
     """Connect to WPS AP with NFC connection handover on 5 GHz band"""
+    hapd = None
     try:
         ssid = "test-wps-nfc-handover"
         params = ap_wps_params(ssid)
         params["country_code"] = "FI"
         params["hw_mode"] = "a"
         params["channel"] = "36"
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
         logger.info("NFC connection handover")
         req = dev[0].request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip()
         if "FAIL" in req:
@@ -267,13 +271,14 @@ def test_nfc_wps_handover_5ghz(dev, apdev):
 
 def test_nfc_wps_handover_chan14(dev, apdev):
     """Connect to WPS AP with NFC connection handover on channel 14"""
+    hapd = None
     try:
         ssid = "test-wps-nfc-handover"
         params = ap_wps_params(ssid)
         params["country_code"] = "JP"
         params["hw_mode"] = "b"
         params["channel"] = "14"
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
         logger.info("NFC connection handover")
         req = dev[0].request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip()
         if "FAIL" in req:
@@ -301,8 +306,7 @@ def test_nfc_wps_handover_with_pw_token_set(dev, apdev):
     """Connect to WPS AP with NFC connection handover (wps_nfc_* set)"""
     ssid = "test-wps-nfc-handover2"
     params = ap_wps_params(ssid)
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     # enable a password token (which won't be used in this test case)
     pw = hapd.request("WPS_NFC_TOKEN NDEF").rstrip()
     if "FAIL" in pw:
@@ -333,8 +337,7 @@ def test_nfc_wps_handover_pk_hash_mismatch_sta(dev, apdev):
     if "FAIL" in dev[0].request("SET wps_corrupt_pkhash 1"):
         raise Exception("Could not enable wps_corrupt_pkhash")
     params = ap_wps_params(ssid)
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     logger.info("NFC connection handover")
     req = dev[0].request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip()
     if "FAIL" in req:
@@ -359,8 +362,7 @@ def test_nfc_wps_handover_pk_hash_mismatch_ap(dev, apdev):
     """WPS NFC connection handover with invalid pkhash from AP (negative)"""
     ssid = "wps-nfc-handover-pkhash-ap"
     params = ap_wps_params(ssid)
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     if "FAIL" in hapd.request("SET wps_corrupt_pkhash 1"):
         raise Exception("Could not enable wps_corrupt_pkhash")
     logger.info("NFC connection handover")
@@ -386,20 +388,23 @@ def test_nfc_wps_handover_pk_hash_mismatch_ap(dev, apdev):
 def start_ap_er(er, ap, ssid):
     ap_pin = "12345670"
     ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"
-    hostapd.add_ap(ap['ifname'],
-                   { "ssid": ssid, "eap_server": "1", "wps_state": "2",
-                     "wpa_passphrase": "12345678", "wpa": "2",
-                     "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
-                     "device_name": "Wireless AP", "manufacturer": "Company",
-                     "model_name": "WAP", "model_number": "123",
-                     "serial_number": "12345", "device_type": "6-0050F204-1",
-                     "os_version": "01020300",
-                     "config_methods": "label push_button",
-                     "ap_pin": ap_pin, "uuid": ap_uuid, "upnp_iface": "lo"})
+    params = { "ssid": ssid, "eap_server": "1", "wps_state": "2",
+               "wpa_passphrase": "12345678", "wpa": "2",
+               "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
+               "device_name": "Wireless AP", "manufacturer": "Company",
+               "model_name": "WAP", "model_number": "123",
+               "serial_number": "12345", "device_type": "6-0050F204-1",
+               "os_version": "01020300",
+               "config_methods": "label push_button",
+               "ap_pin": ap_pin, "uuid": ap_uuid, "upnp_iface": "lo"}
+    hapd = hostapd.add_ap(ap, params)
     logger.info("Learn AP configuration")
     er.dump_monitor()
-    er.request("SET ignore_old_scan_res 1")
-    er.wps_reg(ap['bssid'], ap_pin)
+    try:
+        er.request("SET ignore_old_scan_res 1")
+        er.wps_reg(ap['bssid'], ap_pin)
+    finally:
+        er.request("SET ignore_old_scan_res 0")
 
     logger.info("Start ER")
     er.request("WPS_ER_STOP")
@@ -413,18 +418,20 @@ def start_ap_er(er, ap, ssid):
 
     logger.info("Use learned network configuration on ER")
     er.request("WPS_ER_SET_CONFIG " + ap_uuid + " 0")
+    return hapd
 
+@remote_compatible
 def test_nfc_wps_er_pw_token(dev, apdev):
     """WPS NFC password token from Enrollee to ER"""
     try:
         _test_nfc_wps_er_pw_token(dev, apdev)
     finally:
         dev[0].request("WPS_ER_STOP")
+        dev[1].request("SET ignore_old_scan_res 0")
 
 def _test_nfc_wps_er_pw_token(dev, apdev):
     ssid = "wps-nfc-er-pw-token"
-    start_ap_er(dev[0], apdev[0], ssid)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = start_ap_er(dev[0], apdev[0], ssid)
     logger.info("WPS provisioning step using password token from station")
     dev[1].request("SET ignore_old_scan_res 1")
     pw = dev[1].request("WPS_NFC_TOKEN NDEF").rstrip()
@@ -443,17 +450,18 @@ def _test_nfc_wps_er_pw_token(dev, apdev):
     dev[1].wait_connected(timeout=15)
     check_wpa2_connection(dev[1], apdev[0], hapd, ssid)
 
+@remote_compatible
 def test_nfc_wps_er_config_token(dev, apdev):
     """WPS NFC configuration token from ER to Enrollee"""
     try:
         _test_nfc_wps_er_config_token(dev, apdev)
     finally:
         dev[0].request("WPS_ER_STOP")
+        dev[1].request("SET ignore_old_scan_res 0")
 
 def _test_nfc_wps_er_config_token(dev, apdev):
     ssid = "wps-nfc-er-config-token"
-    start_ap_er(dev[0], apdev[0], ssid)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = start_ap_er(dev[0], apdev[0], ssid)
     logger.info("WPS provisioning step using configuration token from ER")
     wps = dev[0].request("WPS_ER_NFC_CONFIG_TOKEN WPS " + apdev[0]['bssid']).rstrip()
     if "FAIL" in wps:
@@ -477,8 +485,7 @@ def test_nfc_wps_er_handover(dev, apdev):
 
 def _test_nfc_wps_er_handover(dev, apdev):
     ssid = "wps-nfc-er-handover"
-    start_ap_er(dev[0], apdev[0], ssid)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = start_ap_er(dev[0], apdev[0], ssid)
     logger.info("WPS provisioning step using connection handover")
     req = dev[1].request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip()
     if "FAIL" in req:
@@ -502,11 +509,11 @@ def test_nfc_wps_er_handover_pk_hash_mismatch_sta(dev, apdev):
         _test_nfc_wps_er_handover_pk_hash_mismatch_sta(dev, apdev)
     finally:
         dev[0].request("WPS_ER_STOP")
+        dev[1].request("SET ignore_old_scan_res 0")
 
 def _test_nfc_wps_er_handover_pk_hash_mismatch_sta(dev, apdev):
     ssid = "wps-nfc-er-handover-pkhash-sta"
-    start_ap_er(dev[0], apdev[0], ssid)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = start_ap_er(dev[0], apdev[0], ssid)
     logger.info("WPS provisioning step using connection handover")
     if "FAIL" in dev[1].request("SET wps_corrupt_pkhash 1"):
         raise Exception("Could not enable wps_corrupt_pkhash")
@@ -536,11 +543,11 @@ def test_nfc_wps_er_handover_pk_hash_mismatch_er(dev, apdev):
         _test_nfc_wps_er_handover_pk_hash_mismatch_er(dev, apdev)
     finally:
         dev[0].request("WPS_ER_STOP")
+        dev[1].request("SET ignore_old_scan_res 0")
 
 def _test_nfc_wps_er_handover_pk_hash_mismatch_er(dev, apdev):
     ssid = "wps-nfc-er-handover-pkhash-er"
-    start_ap_er(dev[0], apdev[0], ssid)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = start_ap_er(dev[0], apdev[0], ssid)
     logger.info("WPS provisioning step using connection handover")
     if "FAIL" in dev[0].request("SET wps_corrupt_pkhash 1"):
         raise Exception("Could not enable wps_corrupt_pkhash")
@@ -564,6 +571,7 @@ def _test_nfc_wps_er_handover_pk_hash_mismatch_er(dev, apdev):
     if "WPS-FAIL" not in ev:
         raise Exception("Public key hash mismatch not detected")
 
+@remote_compatible
 def test_nfc_invalid_ndef_record(dev, apdev):
     """Invalid NFC NDEF record handling"""
     tests = [ "11223344",
index 6d49392..85308da 100644 (file)
@@ -11,9 +11,7 @@ import hostapd
 from wpasupplicant import WpaSupplicant
 from test_gas import start_ap
 from test_gas import anqp_get
-from test_p2p_grpform import go_neg_pin_authorized
-from test_p2p_grpform import check_grpform_results
-from test_p2p_grpform import remove_group
+from p2p_utils import *
 
 def test_offchannel_tx_roc_gas(dev, apdev):
     """GAS using cfg80211 remain-on-channel for offchannel TX"""
index c92119b..b5f5418 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import time
 import subprocess
 import logging
@@ -14,22 +15,8 @@ import utils
 from utils import HwsimSkip
 from wlantest import Wlantest
 from wpasupplicant import WpaSupplicant
-
-def autogo(go, freq=None, persistent=None):
-    logger.info("Start autonomous GO " + go.ifname)
-    res = go.p2p_start_go(freq=freq, persistent=persistent)
-    logger.debug("res: " + str(res))
-    return res
-
-def connect_cli(go, client, social=False, freq=None):
-    logger.info("Try to connect the client to the GO")
-    pin = client.wps_read_pin()
-    go.p2p_go_authorize_client(pin)
-    res = client.p2p_connect_group(go.p2p_dev_addr(), pin, timeout=60,
-                                   social=social, freq=freq)
-    logger.info("Client connected")
-    hwsim_utils.test_connectivity_p2p(go, client)
-    return res
+from p2p_utils import *
+from test_p2p_messages import mgmt_tx, parse_p2p_public_action
 
 def test_autogo(dev):
     """P2P autonomous GO and client joining group"""
@@ -97,7 +84,7 @@ def test_autogo(dev):
 
 def test_autogo2(dev):
     """P2P autonomous GO with a separate group interface and client joining group"""
-    dev[0].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
     res = autogo(dev[0], freq=2437)
     if "p2p-wlan" not in res['ifname']:
         raise Exception("Unexpected group interface name on GO")
@@ -111,7 +98,7 @@ def test_autogo2(dev):
 
 def test_autogo3(dev):
     """P2P autonomous GO and client with a separate group interface joining group"""
-    dev[1].request("SET p2p_no_group_iface 0")
+    dev[1].global_request("SET p2p_no_group_iface 0")
     autogo(dev[0], freq=2462)
     res = connect_cli(dev[0], dev[1], social=True, freq=2462)
     if "p2p-wlan" not in res['ifname']:
@@ -126,8 +113,8 @@ def test_autogo3(dev):
 
 def test_autogo4(dev):
     """P2P autonomous GO and client joining group (both with a separate group interface)"""
-    dev[0].request("SET p2p_no_group_iface 0")
-    dev[1].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
+    dev[1].global_request("SET p2p_no_group_iface 0")
     res1 = autogo(dev[0], freq=2412)
     res2 = connect_cli(dev[0], dev[1], social=True, freq=2412)
     if "p2p-wlan" not in res1['ifname']:
@@ -190,13 +177,14 @@ def test_autogo_m2d(dev):
     if ev is None:
         raise Exception("No M2D event on group interface (2)")
 
+@remote_compatible
 def test_autogo_fail(dev):
     """P2P autonomous GO and incorrect PIN"""
     autogo(dev[0], freq=2412)
     go_addr = dev[0].p2p_dev_addr()
     dev[0].p2p_go_authorize_client("00000000")
 
-    dev[1].request("SET p2p_no_group_iface 0")
+    dev[1].global_request("SET p2p_no_group_iface 0")
     if not dev[1].discover_peer(go_addr, social=True):
         raise Exception("GO " + go_addr + " not found")
     dev[1].dump_monitor()
@@ -245,7 +233,6 @@ def test_autogo_pbc(dev):
 
 def test_autogo_tdls(dev):
     """P2P autonomous GO and two clients using TDLS"""
-    wt = Wlantest()
     go = dev[0]
     logger.info("Start autonomous GO with fixed parameters " + go.ifname)
     id = go.add_network()
@@ -255,6 +242,8 @@ def test_autogo_tdls(dev):
     go.set_network(id, "disabled", "2")
     res = go.p2p_start_go(persistent=id, freq="2462")
     logger.debug("res: " + str(res))
+    Wlantest.setup(go, True)
+    wt = Wlantest()
     wt.flush()
     wt.add_passphrase("12345678")
     connect_cli(go, dev[1], social=True, freq=2462)
@@ -266,28 +255,28 @@ def test_autogo_tdls(dev):
     dev[1].tdls_setup(addr2)
     time.sleep(1)
     hwsim_utils.test_connectivity_p2p(dev[1], dev[2])
-    conf = wt.get_tdls_counter("setup_conf_ok", bssid, addr1, addr2);
+    conf = wt.get_tdls_counter("setup_conf_ok", bssid, addr1, addr2)
     if conf == 0:
         raise Exception("No TDLS Setup Confirm (success) seen")
-    dl = wt.get_tdls_counter("valid_direct_link", bssid, addr1, addr2);
+    dl = wt.get_tdls_counter("valid_direct_link", bssid, addr1, addr2)
     if dl == 0:
         raise Exception("No valid frames through direct link")
-    wt.tdls_clear(bssid, addr1, addr2);
+    wt.tdls_clear(bssid, addr1, addr2)
     dev[1].tdls_teardown(addr2)
     time.sleep(1)
-    teardown = wt.get_tdls_counter("teardown", bssid, addr1, addr2);
+    teardown = wt.get_tdls_counter("teardown", bssid, addr1, addr2)
     if teardown == 0:
         raise Exception("No TDLS Setup Teardown seen")
-    wt.tdls_clear(bssid, addr1, addr2);
+    wt.tdls_clear(bssid, addr1, addr2)
     hwsim_utils.test_connectivity_p2p(dev[1], dev[2])
-    ap_path = wt.get_tdls_counter("valid_ap_path", bssid, addr1, addr2);
+    ap_path = wt.get_tdls_counter("valid_ap_path", bssid, addr1, addr2)
     if ap_path == 0:
         raise Exception("No valid frames via AP path")
-    direct_link = wt.get_tdls_counter("valid_direct_link", bssid, addr1, addr2);
+    direct_link = wt.get_tdls_counter("valid_direct_link", bssid, addr1, addr2)
     if direct_link > 0:
         raise Exception("Unexpected frames through direct link")
     idirect_link = wt.get_tdls_counter("invalid_direct_link", bssid, addr1,
-                                       addr2);
+                                       addr2)
     if idirect_link > 0:
         raise Exception("Unexpected frames through direct link (invalid)")
     dev[2].remove_group()
@@ -352,6 +341,7 @@ def test_autogo_chan_switch(dev):
     time.sleep(0.1)
     hwsim_utils.test_connectivity_p2p(dev[0], dev[1])
 
+@remote_compatible
 def test_autogo_extra_cred(dev):
     """P2P autonomous GO sending two WPS credentials"""
     if "FAIL" in dev[0].request("SET wps_testing_dummy_cred 1"):
@@ -378,6 +368,7 @@ def test_autogo_ifdown(dev):
     if res['ifname'] not in ev:
         raise Exception("Unexpected group removal event: " + ev)
 
+@remote_compatible
 def test_autogo_start_during_scan(dev):
     """P2P autonomous GO started during ongoing manual scan"""
     try:
@@ -431,6 +422,7 @@ def test_autogo_passphrase_len(dev):
     finally:
         dev[0].request("SET p2p_passphrase_len 8")
 
+@remote_compatible
 def test_autogo_bridge(dev):
     """P2P autonomous GO in a bridge"""
     try:
@@ -439,16 +431,16 @@ def test_autogo_bridge(dev):
             raise Exception("Failed to set autoscan")
         autogo(dev[0])
         ifname = dev[0].get_group_ifname()
-        subprocess.call(['brctl', 'addbr', 'p2p-br0'])
-        subprocess.call(['brctl', 'setfd', 'p2p-br0', '0'])
-        subprocess.call(['brctl', 'addif', 'p2p-br0', ifname])
-        subprocess.call(['ip', 'link', 'set', 'dev', 'p2p-br0', 'up'])
+        dev[0].cmd_execute(['brctl', 'addbr', 'p2p-br0'])
+        dev[0].cmd_execute(['brctl', 'setfd', 'p2p-br0', '0'])
+        dev[0].cmd_execute(['brctl', 'addif', 'p2p-br0', ifname])
+        dev[0].cmd_execute(['ip', 'link', 'set', 'dev', 'p2p-br0', 'up'])
         time.sleep(0.1)
-        subprocess.call(['brctl', 'delif', 'p2p-br0', ifname])
+        dev[0].cmd_execute(['brctl', 'delif', 'p2p-br0', ifname])
         time.sleep(0.1)
-        subprocess.call(['ip', 'link', 'set', 'dev', 'p2p-br0', 'down'])
+        dev[0].cmd_execute(['ip', 'link', 'set', 'dev', 'p2p-br0', 'down'])
         time.sleep(0.1)
-        subprocess.call(['brctl', 'delbr', 'p2p-br0'])
+        dev[0].cmd_execute(['brctl', 'delbr', 'p2p-br0'])
         ev = dev[0].wait_global_event(["P2P-GROUP-REMOVED"], timeout=1)
         if ev is not None:
             raise Exception("P2P group removed unexpectedly")
@@ -457,16 +449,17 @@ def test_autogo_bridge(dev):
         dev[0].remove_group()
     finally:
         dev[0].request("AUTOSCAN ")
-        subprocess.Popen(['brctl', 'delif', 'p2p-br0', ifname],
-                         stderr=open('/dev/null', 'w'))
-        subprocess.Popen(['ip', 'link', 'set', 'dev', 'p2p-br0', 'down'],
-                         stderr=open('/dev/null', 'w'))
-        subprocess.Popen(['brctl', 'delbr', 'p2p-br0'],
-                         stderr=open('/dev/null', 'w'))
-
+        dev[0].cmd_execute(['brctl', 'delif', 'p2p-br0', ifname,
+                            '2>', '/dev/null'], shell=True)
+        dev[0].cmd_execute(['ip', 'link', 'set', 'dev', 'p2p-br0', 'down',
+                            '2>', '/dev/null'], shell=True)
+        dev[0].cmd_execute(['brctl', 'delbr', 'p2p-br0', '2>', '/dev/null'],
+                           shell=True)
+
+@remote_compatible
 def test_presence_req_on_group_interface(dev):
     """P2P_PRESENCE_REQ on group interface"""
-    dev[1].request("SET p2p_no_group_iface 0")
+    dev[1].global_request("SET p2p_no_group_iface 0")
     res = autogo(dev[0], freq=2437)
     res = connect_cli(dev[0], dev[1], social=True, freq=2437)
     if "FAIL" in dev[1].group_request("P2P_PRESENCE_REQ 30000 102400"):
@@ -486,6 +479,7 @@ def test_autogo_join_auto_go_not_found(dev):
     autogo(wpas, freq=2412)
     addr = wpas.p2p_dev_addr()
     bssid = wpas.p2p_interface_addr()
+    wpas.dump_monitor()
 
     dev[1].global_request("SET p2p_no_group_iface 0")
     dev[1].scan_for_bss(bssid, freq=2412)
@@ -496,12 +490,15 @@ def test_autogo_join_auto_go_not_found(dev):
     # exchange.
     if "OK" not in wpas.group_request("STOP_AP"):
         raise Exception("STOP_AP failed")
+    wpas.dump_monitor()
     wpas.group_request("SET ext_mgmt_frame_handling 1")
     wpas.p2p_listen()
+    wpas.dump_monitor()
     time.sleep(0.02)
     dev[1].global_request("P2P_CONNECT " + addr + " pbc auto")
 
     ev = dev[1].wait_global_event(["P2P-FALLBACK-TO-GO-NEG-ENABLED"], 15)
+    wpas.dump_monitor()
     if ev is None:
         raise Exception("Could not trigger old-scan-only case")
         return
@@ -512,6 +509,7 @@ def test_autogo_join_auto_go_not_found(dev):
         raise Exception("Fallback to GO Negotiation not seen")
     if "reason=GO-not-found" not in ev:
         raise Exception("Unexpected reason for fallback: " + ev)
+    wpas.dump_monitor()
 
 def test_autogo_join_auto(dev):
     """P2P_CONNECT-auto joining a group"""
@@ -536,11 +534,15 @@ def test_autogo_join_auto(dev):
     dev[1].wait_go_ending_session()
     dev[1].flush_scan_cache()
 
+@remote_compatible
 def test_autogo_join_auto_go_neg(dev):
     """P2P_CONNECT-auto fallback to GO Neg"""
     dev[1].flush_scan_cache()
     dev[0].p2p_listen()
     addr = dev[0].p2p_dev_addr()
+    if not dev[1].discover_peer(addr, social=True):
+        raise Exception("Peer not found")
+    dev[1].p2p_stop_find()
     if "OK" not in dev[1].global_request("P2P_CONNECT " + addr + " pbc auto"):
         raise Exception("P2P_CONNECT failed")
 
@@ -569,6 +571,7 @@ def test_autogo_join_auto_go_neg(dev):
     dev[1].wait_go_ending_session()
     dev[1].flush_scan_cache()
 
+@remote_compatible
 def test_autogo_join_auto_go_neg_after_seeing_go(dev):
     """P2P_CONNECT-auto fallback to GO Neg after seeing GO"""
     autogo(dev[0], freq=2412)
@@ -625,7 +628,7 @@ def test_go_search_non_social(dev):
 
 def test_autogo_many(dev):
     """P2P autonomous GO with large number of GO instances"""
-    dev[0].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
     for i in range(100):
         if "OK" not in dev[0].global_request("P2P_GROUP_ADD freq=2412"):
             logger.info("Was able to add %d groups" % i)
@@ -701,3 +704,112 @@ def _test_autogo_many_clients(dev):
     for i in [ name0, name2, name3 ]:
         if i not in ev1 and i not in ev2 and i not in ev3:
             raise Exception('name "%s" not found' % i)
+
+def rx_pd_req(dev):
+    msg = dev.mgmt_rx()
+    if msg is None:
+        raise Exception("MGMT-RX timeout")
+    p2p = parse_p2p_public_action(msg['payload'])
+    if p2p is None:
+        raise Exception("Not a P2P Public Action frame " + str(dialog_token))
+    if p2p['subtype'] != P2P_PROV_DISC_REQ:
+        raise Exception("Unexpected subtype %d" % p2p['subtype'])
+    p2p['freq'] = msg['freq']
+    return p2p
+
+@remote_compatible
+def test_autogo_scan(dev):
+    """P2P autonomous GO and no P2P IE in Probe Response scan results"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    dev[0].p2p_start_go(freq=2412, persistent=True)
+    bssid = dev[0].p2p_interface_addr()
+
+    dev[1].discover_peer(addr0)
+    dev[1].p2p_stop_find()
+    ev = dev[1].wait_global_event(["P2P-FIND-STOPPED"], timeout=2)
+    time.sleep(0.1)
+    dev[1].flush_scan_cache()
+
+    pin = dev[1].wps_read_pin()
+    dev[0].group_request("WPS_PIN any " + pin)
+
+    try:
+        dev[1].request("SET p2p_disabled 1")
+        dev[1].request("SCAN freq=2412")
+        ev = dev[1].wait_event(["CTRL-EVENT-SCAN-RESULTS"])
+        if ev is None:
+            raise Exception("Active scan did not complete")
+    finally:
+        dev[1].request("SET p2p_disabled 0")
+
+    for i in range(2):
+        dev[1].request("SCAN freq=2412 passive=1")
+        ev = dev[1].wait_event(["CTRL-EVENT-SCAN-RESULTS"])
+        if ev is None:
+            raise Exception("Scan did not complete")
+
+    # Disable management frame processing for a moment to skip Probe Response
+    # frame with P2P IE.
+    dev[0].group_request("SET ext_mgmt_frame_handling 1")
+
+    dev[1].global_request("P2P_CONNECT " + bssid + " " + pin + " freq=2412 join")
+
+    # Skip the first Probe Request frame
+    ev = dev[0].wait_group_event(["MGMT-RX"], timeout=10)
+    if ev is None:
+        raise Exception("No Probe Request frame seen")
+    if not ev.split(' ')[4].startswith("40"):
+        raise Exception("Not a Probe Request frame")
+
+    # If a P2P Device is not used, the PD Request will be received on the group
+    # interface (which is actually wlan0, since a separate interface is not
+    # used), which was set to external management frame handling, so need to
+    # reply to it manually.
+    res = dev[0].get_driver_status()
+    if not (int(res['capa.flags'], 0) & 0x20000000):
+        # Reply to PD Request while still filtering Probe Request frames
+        msg = rx_pd_req(dev[0])
+        mgmt_tx(dev[0], "MGMT_TX {} {} freq={} wait_time=10 no_cck=1 action={}".format(addr1, addr0, 2412, "0409506f9a0908%02xdd0a0050f204100800020008" % msg['dialog_token']))
+
+    # Skip Probe Request frames until something else is received
+    for i in range(10):
+        ev = dev[0].wait_group_event(["MGMT-RX"], timeout=10)
+        if ev is None:
+            raise Exception("No frame seen")
+        if not ev.split(' ')[4].startswith("40"):
+            break
+
+    # Allow wpa_supplicant to process authentication and association
+    dev[0].group_request("SET ext_mgmt_frame_handling 0")
+
+    # Joining the group should succeed and indicate persistent group based on
+    # Beacon frame P2P IE.
+    ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+    if ev is None:
+        raise Exception("Failed to join group")
+    if "[PERSISTENT]" not in ev:
+        raise Exception("Did not recognize group as persistent")
+    dev[0].remove_group()
+    dev[1].wait_go_ending_session()
+
+@remote_compatible
+def test_autogo_join_before_found(dev):
+    """P2P client joining a group before having found GO Device Address"""
+    dev[0].global_request("SET p2p_no_group_iface 0")
+    res = autogo(dev[0], freq=2412)
+    if "p2p-wlan" not in res['ifname']:
+        raise Exception("Unexpected group interface name on GO")
+    status = dev[0].get_group_status()
+    bssid = status['bssid']
+
+    pin = dev[1].wps_read_pin()
+    dev[0].p2p_go_authorize_client(pin)
+    cmd = "P2P_CONNECT " + bssid + " " + pin + " join freq=2412"
+    if "OK" not in dev[1].global_request(cmd):
+        raise Exception("P2P_CONNECT join failed")
+    ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
+    if ev is None:
+        raise Exception("Joining the group timed out")
+    dev[0].remove_group()
+    dev[1].wait_go_ending_session()
index 8fa80a4..ecbb867 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 import os
@@ -12,15 +13,10 @@ import time
 
 import hostapd
 import hwsim_utils
-from utils import HwsimSkip
 from tshark import run_tshark
 from wpasupplicant import WpaSupplicant
 from hwsim import HWSimRadio
-from test_p2p_grpform import go_neg_pin_authorized
-from test_p2p_grpform import check_grpform_results
-from test_p2p_grpform import remove_group
-from test_p2p_grpform import go_neg_pbc
-from test_p2p_autogo import autogo
+from p2p_utils import *
 
 def set_country(country, dev=None):
     subprocess.call(['iw', 'reg', 'set', country])
@@ -54,7 +50,7 @@ def test_p2p_channel_5ghz_no_vht(dev):
     """P2P group formation with 5 GHz preference when VHT channels are disallowed"""
     try:
         set_country("US", dev[0])
-        dev[0].request("P2P_SET disallow_freq 5180-5240")
+        dev[0].global_request("P2P_SET disallow_freq 5180-5240")
         [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
                                                r_dev=dev[1], r_intent=0,
                                                test_data=False)
@@ -65,15 +61,15 @@ def test_p2p_channel_5ghz_no_vht(dev):
         remove_group(dev[0], dev[1])
     finally:
         set_country("00")
-        dev[0].request("P2P_SET disallow_freq ")
+        dev[0].global_request("P2P_SET disallow_freq ")
         dev[1].flush_scan_cache()
 
 def test_p2p_channel_random_social(dev):
     """P2P group formation with 5 GHz preference but all 5 GHz channels disabled"""
     try:
         set_country("US", dev[0])
-        dev[0].request("SET p2p_oper_channel 11")
-        dev[0].request("P2P_SET disallow_freq 5000-6000,2462")
+        dev[0].global_request("SET p2p_oper_channel 11")
+        dev[0].global_request("P2P_SET disallow_freq 5000-6000,2462")
         [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
                                                r_dev=dev[1], r_intent=0,
                                                test_data=False)
@@ -84,15 +80,15 @@ def test_p2p_channel_random_social(dev):
         remove_group(dev[0], dev[1])
     finally:
         set_country("00")
-        dev[0].request("P2P_SET disallow_freq ")
+        dev[0].global_request("P2P_SET disallow_freq ")
         dev[1].flush_scan_cache()
 
 def test_p2p_channel_random(dev):
     """P2P group formation with 5 GHz preference but all 5 GHz channels and all social channels disabled"""
     try:
         set_country("US", dev[0])
-        dev[0].request("SET p2p_oper_channel 11")
-        dev[0].request("P2P_SET disallow_freq 5000-6000,2412,2437,2462")
+        dev[0].global_request("SET p2p_oper_channel 11")
+        dev[0].global_request("P2P_SET disallow_freq 5000-6000,2412,2437,2462")
         [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
                                                r_dev=dev[1], r_intent=0,
                                                test_data=False)
@@ -103,7 +99,7 @@ def test_p2p_channel_random(dev):
         remove_group(dev[0], dev[1])
     finally:
         set_country("00")
-        dev[0].request("P2P_SET disallow_freq ")
+        dev[0].global_request("P2P_SET disallow_freq ")
         dev[1].flush_scan_cache()
 
 def test_p2p_channel_random_social_with_op_class_change(dev, apdev, params):
@@ -121,9 +117,9 @@ def test_p2p_channel_random_social_with_op_class_change(dev, apdev, params):
         remove_group(dev[0], dev[1])
 
         logger.info("Disable 5 GHz and try to re-start group based on 5 GHz preference")
-        dev[0].request("SET p2p_oper_reg_class 115")
-        dev[0].request("SET p2p_oper_channel 36")
-        dev[0].request("P2P_SET disallow_freq 5000-6000")
+        dev[0].global_request("SET p2p_oper_reg_class 115")
+        dev[0].global_request("SET p2p_oper_channel 36")
+        dev[0].global_request("P2P_SET disallow_freq 5000-6000")
         [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
                                                r_dev=dev[1], r_intent=0,
                                                test_data=False)
@@ -147,9 +143,9 @@ def test_p2p_channel_random_social_with_op_class_change(dev, apdev, params):
                 raise Exception("Unexpected operating class: " + last.strip())
     finally:
         set_country("00")
-        dev[0].request("P2P_SET disallow_freq ")
-        dev[0].request("SET p2p_oper_reg_class 0")
-        dev[0].request("SET p2p_oper_channel 0")
+        dev[0].global_request("P2P_SET disallow_freq ")
+        dev[0].global_request("SET p2p_oper_reg_class 0")
+        dev[0].global_request("SET p2p_oper_channel 0")
         dev[1].flush_scan_cache()
 
 def test_p2p_channel_avoid(dev):
@@ -174,35 +170,38 @@ def test_p2p_channel_avoid(dev):
         ev = dev[0].wait_event(["CTRL-EVENT-AVOID-FREQ"], timeout=10)
         if ev is None:
             raise Exception("No CTRL-EVENT-AVOID-FREQ event")
-        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP"], timeout=1)
+        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP",
+                                      "AP-CSA-FINISHED"], timeout=1)
         if ev is not None:
-            raise Exception("Unexpected P2P-REMOVE-AND-REFORM-GROUP event")
+            raise Exception("Unexpected + " + ev + " event")
 
         if "OK" not in dev[0].request("DRIVER_EVENT AVOID_FREQUENCIES " + str(freq)):
             raise Exception("Could not simulate driver event(3)")
         ev = dev[0].wait_event(["CTRL-EVENT-AVOID-FREQ"], timeout=10)
         if ev is None:
             raise Exception("No CTRL-EVENT-AVOID-FREQ event")
-        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP"],
+        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP",
+                                      "AP-CSA-FINISHED"],
                                      timeout=10)
         if ev is None:
-            raise Exception("No P2P-REMOVE-AND-REFORM-GROUP event")
+            raise Exception("No P2P-REMOVE-AND-REFORM-GROUP or AP-CSA-FINISHED event")
     finally:
         set_country("00")
         dev[0].request("DRIVER_EVENT AVOID_FREQUENCIES")
         dev[1].flush_scan_cache()
 
+@remote_compatible
 def test_autogo_following_bss(dev, apdev):
     """P2P autonomous GO operate on the same channel as station interface"""
     if dev[0].get_mcc() > 1:
         logger.info("test mode: MCC")
 
-    dev[0].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
 
     channels = { 3 : "2422", 5 : "2432", 9 : "2452" }
     for key in channels:
-        hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid" : 'ap-test',
-                                                    "channel" : str(key) })
+        hapd = hostapd.add_ap(apdev[0], { "ssid" : 'ap-test',
+                                          "channel" : str(key) })
         dev[0].connect("ap-test", key_mgmt="NONE",
                        scan_freq=str(channels[key]))
         res_go = autogo(dev[0])
@@ -211,14 +210,15 @@ def test_autogo_following_bss(dev, apdev):
         hwsim_utils.test_connectivity(dev[0], hapd)
         dev[0].remove_group(res_go['ifname'])
 
+@remote_compatible
 def test_go_neg_with_bss_connected(dev, apdev):
     """P2P channel selection: GO negotiation when station interface is connected"""
 
     dev[0].flush_scan_cache()
     dev[1].flush_scan_cache()
-    dev[0].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
 
-    hapd = hostapd.add_ap(apdev[0]['ifname'],
+    hapd = hostapd.add_ap(apdev[0],
                           { "ssid": 'bss-2.4ghz', "channel": '5' })
     dev[0].connect("bss-2.4ghz", key_mgmt="NONE", scan_freq="2432")
     #dev[0] as GO
@@ -235,7 +235,7 @@ def test_go_neg_with_bss_connected(dev, apdev):
 
     if dev[0].get_mcc() > 1:
         logger.info("Skip as-client case due to MCC being enabled")
-        return;
+        return
 
     #dev[0] as client
     [i_res2, r_res2] = go_neg_pbc(i_dev=dev[0], i_intent=1, r_dev=dev[1],
@@ -260,22 +260,22 @@ def test_autogo_with_bss_on_disallowed_chan(dev, apdev):
         wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
         wpas.interface_add(iface)
 
-        wpas.request("SET p2p_no_group_iface 0")
+        wpas.global_request("SET p2p_no_group_iface 0")
 
         if wpas.get_mcc() < 2:
            raise Exception("New radio does not support MCC")
 
         try:
-            hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": 'bss-2.4ghz',
-                                                        "channel": '1' })
-            wpas.request("P2P_SET disallow_freq 2412")
+            hapd = hostapd.add_ap(apdev[0], { "ssid": 'bss-2.4ghz',
+                                              "channel": '1' })
+            wpas.global_request("P2P_SET disallow_freq 2412")
             wpas.connect("bss-2.4ghz", key_mgmt="NONE", scan_freq="2412")
             res = autogo(wpas)
             if res['freq'] == "2412":
                raise Exception("GO set on a disallowed channel")
             hwsim_utils.test_connectivity(wpas, hapd)
         finally:
-            wpas.request("P2P_SET disallow_freq ")
+            wpas.global_request("P2P_SET disallow_freq ")
 
 def test_go_neg_with_bss_on_disallowed_chan(dev, apdev):
     """P2P channel selection: GO negotiation with station interface on a disallowed channel"""
@@ -284,18 +284,18 @@ def test_go_neg_with_bss_on_disallowed_chan(dev, apdev):
         wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
         wpas.interface_add(iface)
 
-        wpas.request("SET p2p_no_group_iface 0")
+        wpas.global_request("SET p2p_no_group_iface 0")
 
         if wpas.get_mcc() < 2:
            raise Exception("New radio does not support MCC")
 
         try:
-            hapd = hostapd.add_ap(apdev[0]['ifname'],
+            hapd = hostapd.add_ap(apdev[0],
                                   { "ssid": 'bss-2.4ghz', "channel": '1' })
             # make sure PBC overlap from old test cases is not maintained
             dev[1].flush_scan_cache()
             wpas.connect("bss-2.4ghz", key_mgmt="NONE", scan_freq="2412")
-            wpas.request("P2P_SET disallow_freq 2412")
+            wpas.global_request("P2P_SET disallow_freq 2412")
 
             #wpas as GO
             [i_res, r_res] = go_neg_pbc(i_dev=wpas, i_intent=10, r_dev=dev[1],
@@ -330,7 +330,7 @@ def test_go_neg_with_bss_on_disallowed_chan(dev, apdev):
             wpas.request("DISCONNECT")
             hapd.disable()
         finally:
-            wpas.request("P2P_SET disallow_freq ")
+            wpas.global_request("P2P_SET disallow_freq ")
 
 def test_autogo_force_diff_channel(dev, apdev):
     """P2P autonomous GO and station interface operate on different channels"""
@@ -341,18 +341,21 @@ def test_autogo_force_diff_channel(dev, apdev):
         if wpas.get_mcc() < 2:
            raise Exception("New radio does not support MCC")
 
-        wpas.request("SET p2p_no_group_iface 0")
+        wpas.global_request("SET p2p_no_group_iface 0")
 
-        hapd = hostapd.add_ap(apdev[0]['ifname'],
+        hapd = hostapd.add_ap(apdev[0],
                               {"ssid" : 'ap-test', "channel" : '1'})
         wpas.connect("ap-test", key_mgmt = "NONE", scan_freq = "2412")
+        wpas.dump_monitor()
         channels = { 2 : 2417, 5 : 2432, 9 : 2452 }
         for key in channels:
             res_go = autogo(wpas, channels[key])
+            wpas.dump_monitor()
             hwsim_utils.test_connectivity(wpas, hapd)
             if int(res_go['freq']) == 2412:
                 raise Exception("Group operation channel is: 2412 excepted: " + res_go['freq'])
             wpas.remove_group(res_go['ifname'])
+            wpas.dump_monitor()
 
 def test_go_neg_forced_freq_diff_than_bss_freq(dev, apdev):
     """P2P channel selection: GO negotiation with forced freq different than station interface"""
@@ -366,9 +369,9 @@ def test_go_neg_forced_freq_diff_than_bss_freq(dev, apdev):
         # Clear possible PBC session overlap from previous test case
         dev[1].flush_scan_cache()
 
-        wpas.request("SET p2p_no_group_iface 0")
+        wpas.global_request("SET p2p_no_group_iface 0")
 
-        hapd = hostapd.add_ap(apdev[0]['ifname'],
+        hapd = hostapd.add_ap(apdev[0],
                               { "country_code": 'US',
                                 "ssid": 'bss-5ghz', "hw_mode": 'a',
                                 "channel": '40' })
@@ -404,22 +407,23 @@ def test_go_neg_forced_freq_diff_than_bss_freq(dev, apdev):
         subprocess.call(['iw', 'reg', 'set', '00'])
         wpas.flush_scan_cache()
 
+@remote_compatible
 def test_go_pref_chan_bss_on_diff_chan(dev, apdev):
     """P2P channel selection: Station on different channel than GO configured pref channel"""
 
-    dev[0].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
 
     try:
-        hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": 'bss-2.4ghz',
-                                                    "channel": '1' })
-        dev[0].request("SET p2p_pref_chan 81:2")
+        hapd = hostapd.add_ap(apdev[0], { "ssid": 'bss-2.4ghz',
+                                          "channel": '1' })
+        dev[0].global_request("SET p2p_pref_chan 81:2")
         dev[0].connect("bss-2.4ghz", key_mgmt="NONE", scan_freq="2412")
         res = autogo(dev[0])
         if res['freq'] != "2412":
            raise Exception("GO channel did not follow BSS")
         hwsim_utils.test_connectivity(dev[0], hapd)
     finally:
-        dev[0].request("SET p2p_pref_chan ")
+        dev[0].global_request("SET p2p_pref_chan ")
 
 def test_go_pref_chan_bss_on_disallowed_chan(dev, apdev):
     """P2P channel selection: Station interface on different channel than GO configured pref channel, and station channel is disallowed"""
@@ -430,26 +434,27 @@ def test_go_pref_chan_bss_on_disallowed_chan(dev, apdev):
         if wpas.get_mcc() < 2:
            raise Exception("New radio does not support MCC")
 
-        wpas.request("SET p2p_no_group_iface 0")
+        wpas.global_request("SET p2p_no_group_iface 0")
 
         try:
-            hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": 'bss-2.4ghz',
-                                                        "channel": '1' })
-            wpas.request("P2P_SET disallow_freq 2412")
-            wpas.request("SET p2p_pref_chan 81:2")
+            hapd = hostapd.add_ap(apdev[0], { "ssid": 'bss-2.4ghz',
+                                              "channel": '1' })
+            wpas.global_request("P2P_SET disallow_freq 2412")
+            wpas.global_request("SET p2p_pref_chan 81:2")
             wpas.connect("bss-2.4ghz", key_mgmt="NONE", scan_freq="2412")
             res2 = autogo(wpas)
             if res2['freq'] != "2417":
                raise Exception("GO channel did not follow pref_chan configuration")
             hwsim_utils.test_connectivity(wpas, hapd)
         finally:
-            wpas.request("P2P_SET disallow_freq ")
-            wpas.request("SET p2p_pref_chan ")
+            wpas.global_request("P2P_SET disallow_freq ")
+            wpas.global_request("SET p2p_pref_chan ")
 
+@remote_compatible
 def test_no_go_freq(dev, apdev):
     """P2P channel selection: no GO freq"""
     try:
-       dev[0].request("SET p2p_no_go_freq 2412")
+       dev[0].global_request("SET p2p_no_go_freq 2412")
        # dev[0] as client, channel 1 is ok
        [i_res, r_res] = go_neg_pbc(i_dev=dev[0], i_intent=1,
                                    r_dev=dev[1], r_intent=14, r_freq=2412)
@@ -464,7 +469,7 @@ def test_no_go_freq(dev, apdev):
        fail = False
        # dev[0] as GO, channel 1 is not allowed
        try:
-          dev[0].request("SET p2p_no_go_freq 2412")
+          dev[0].global_request("SET p2p_no_go_freq 2412")
           [i_res2, r_res2] = go_neg_pbc(i_dev=dev[0], i_intent=14,
                                         r_dev=dev[1], r_intent=1, r_freq=2412)
           check_grpform_results(i_res2, r_res2)
@@ -474,8 +479,9 @@ def test_no_go_freq(dev, apdev):
        if fail:
            raise Exception("GO set on a disallowed freq")
     finally:
-       dev[0].request("SET p2p_no_go_freq ")
+       dev[0].global_request("SET p2p_no_go_freq ")
 
+@remote_compatible
 def test_go_neg_peers_force_diff_freq(dev, apdev):
     """P2P channel selection when peers for different frequency"""
     try:
@@ -485,6 +491,7 @@ def test_go_neg_peers_force_diff_freq(dev, apdev):
         return
     raise Exception("Unexpected group formation success")
 
+@remote_compatible
 def test_autogo_random_channel(dev, apdev):
     """P2P channel selection: GO instantiated on random channel 1, 6, 11"""
     freqs = []
@@ -501,25 +508,26 @@ def test_autogo_random_channel(dev, apdev):
     if i == 20:
        raise Exception("GO created 20 times and not all social channels were selected. freqs not selected: " + str(list(set(go_freqs) - set(freqs))))
 
+@remote_compatible
 def test_p2p_autogo_pref_chan_disallowed(dev, apdev):
     """P2P channel selection: GO preferred channels are disallowed"""
     try:
-       dev[0].request("SET p2p_pref_chan 81:1,81:3,81:6,81:9,81:11")
-       dev[0].request("P2P_SET disallow_freq 2412,2422,2437,2452,2462")
+       dev[0].global_request("SET p2p_pref_chan 81:1,81:3,81:6,81:9,81:11")
+       dev[0].global_request("P2P_SET disallow_freq 2412,2422,2437,2452,2462")
        for i in range(0, 5):
            res = autogo(dev[0])
            if res['freq'] in [ "2412", "2422", "2437", "2452", "2462" ]:
                raise Exception("GO channel is disallowed")
            dev[0].remove_group(res['ifname'])
     finally:
-       dev[0].request("P2P_SET disallow_freq ")
-       dev[0].request("SET p2p_pref_chan ")
+       dev[0].global_request("P2P_SET disallow_freq ")
+       dev[0].global_request("SET p2p_pref_chan ")
 
 def test_p2p_autogo_pref_chan_not_in_regulatory(dev, apdev):
     """P2P channel selection: GO preferred channel not allowed in the regulatory rules"""
     try:
         set_country("US", dev[0])
-        dev[0].request("SET p2p_pref_chan 124:149")
+        dev[0].global_request("SET p2p_pref_chan 124:149")
         res = autogo(dev[0], persistent=True)
         if res['freq'] != "5745":
             raise Exception("Unexpected channel selected: " + res['freq'])
@@ -536,7 +544,7 @@ def test_p2p_autogo_pref_chan_not_in_regulatory(dev, apdev):
             raise Exception("Unexpected channel selected(2): " + res['freq'])
         dev[0].remove_group(res['ifname'])
     finally:
-        dev[0].request("SET p2p_pref_chan ")
+        dev[0].global_request("SET p2p_pref_chan ")
         set_country("00")
 
 def run_autogo(dev, param):
@@ -584,7 +592,7 @@ def test_p2p_listen_chan_optimize(dev, apdev):
     wpas.interface_add("wlan5")
     addr5 = wpas.p2p_dev_addr()
     try:
-        if "OK" not in wpas.request("SET p2p_optimize_listen_chan 1"):
+        if "OK" not in wpas.global_request("SET p2p_optimize_listen_chan 1"):
             raise Exception("Failed to set p2p_optimize_listen_chan")
         wpas.p2p_listen()
         if not dev[0].discover_peer(addr5):
@@ -597,12 +605,12 @@ def test_p2p_listen_chan_optimize(dev, apdev):
         channel = "1" if lfreq != '2412' else "6"
         freq = "2412" if lfreq != '2412' else "2437"
         params = { "ssid": "test-open", "channel": channel }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
 
         id = wpas.connect("test-open", key_mgmt="NONE", scan_freq=freq)
         wpas.p2p_listen()
 
-        if "OK" not in dev[0].request("P2P_FLUSH"):
+        if "OK" not in dev[0].global_request("P2P_FLUSH"):
             raise Exception("P2P_FLUSH failed")
         if not dev[0].discover_peer(addr5):
             raise Exception("Could not discover peer")
@@ -626,14 +634,14 @@ def test_p2p_listen_chan_optimize(dev, apdev):
 
         lchannel = "1" if channel != "1" else "6"
         lfreq3 = "2412" if channel != "1" else "2437"
-        if "OK" not in wpas.request("P2P_SET listen_channel " + lchannel):
+        if "OK" not in wpas.global_request("P2P_SET listen_channel " + lchannel):
             raise Exception("Failed to set listen channel")
 
         wpas.select_network(id)
         wpas.wait_connected()
         wpas.p2p_listen()
 
-        if "OK" not in dev[0].request("P2P_FLUSH"):
+        if "OK" not in dev[0].global_request("P2P_FLUSH"):
             raise Exception("P2P_FLUSH failed")
         if not dev[0].discover_peer(addr5):
             raise Exception("Could not discover peer")
@@ -644,13 +652,13 @@ def test_p2p_listen_chan_optimize(dev, apdev):
         wpas.p2p_stop_find()
         dev[0].p2p_stop_find()
     finally:
-        wpas.request("SET p2p_optimize_listen_chan 0")
+        wpas.global_request("SET p2p_optimize_listen_chan 0")
 
 def test_p2p_channel_5ghz_only(dev):
     """P2P GO start with only 5 GHz band allowed"""
     try:
         set_country("US", dev[0])
-        dev[0].request("P2P_SET disallow_freq 2400-2500")
+        dev[0].global_request("P2P_SET disallow_freq 2400-2500")
         res = autogo(dev[0])
         freq = int(res['freq'])
         if freq < 5000:
@@ -658,7 +666,7 @@ def test_p2p_channel_5ghz_only(dev):
         dev[0].remove_group()
     finally:
         set_country("00")
-        dev[0].request("P2P_SET disallow_freq ")
+        dev[0].global_request("P2P_SET disallow_freq ")
 
 def test_p2p_channel_5ghz_165_169_us(dev):
     """P2P GO and 5 GHz channels 165 (allowed) and 169 (disallowed) in US"""
@@ -675,11 +683,16 @@ def test_p2p_channel_5ghz_165_169_us(dev):
     finally:
         set_country("00")
 
-def test_p2p_go_move_reg_change(dev, apdev, params):
-    """P2P GO move due to regulatory change [long]"""
-    if not params['long']:
-        raise HwsimSkip("Skip test case with long duration due to --long not specified")
+def wait_go_down_up(dev):
+    ev = dev.wait_group_event(["AP-DISABLED"], timeout=5)
+    if ev is None:
+        raise Exception("AP-DISABLED not seen after P2P-REMOVE-AND-REFORM-GROUP")
+    ev = dev.wait_group_event(["AP-ENABLED"], timeout=5)
+    if ev is None:
+        raise Exception("AP-ENABLED not seen after P2P-REMOVE-AND-REFORM-GROUP")
 
+def test_p2p_go_move_reg_change(dev, apdev):
+    """P2P GO move due to regulatory change"""
     try:
         set_country("US")
         dev[0].global_request("P2P_SET disallow_freq 2400-5000")
@@ -691,12 +704,22 @@ def test_p2p_go_move_reg_change(dev, apdev, params):
         dev[0].global_request("P2P_SET disallow_freq ")
 
         # GO move is not allowed while waiting for initial client connection
-        time.sleep(20)
+        connect_cli(dev[0], dev[1], freq=freq1)
+        dev[1].remove_group()
+
+        freq = dev[0].get_group_status_field('freq')
+        if int(freq) < 5000:
+            raise Exception("Unexpected freq after initial client: " + freq)
+        dev[0].dump_monitor()
+
         set_country("00")
-        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP"],
+        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP",
+                                      "AP-CSA-FINISHED"],
                                      timeout=10)
         if ev is None:
-            raise Exception("P2P-REMOVE-AND-REFORM-GROUP not seen")
+            raise Exception("P2P-REMOVE-AND-REFORM-GROUP or AP-CSA-FINISHED not seen")
+        if "P2P-REMOVE-AND-REFORM-GROUP" in ev:
+            wait_go_down_up(dev[0])
 
         freq2 = dev[0].get_group_status_field('freq')
         if freq1 == freq2:
@@ -707,19 +730,24 @@ def test_p2p_go_move_reg_change(dev, apdev, params):
         dev[0].global_request("P2P_SET disallow_freq ")
         set_country("00")
 
-def test_p2p_go_move_active(dev, apdev, params):
-    """P2P GO stays in freq although SCM is possible [long]"""
-    if dev[0].get_mcc() <= 1:
-        raise HwsimSkip("Skip due to MCC not being enabled")
+def test_p2p_go_move_active(dev, apdev):
+    """P2P GO stays in freq although SCM is possible"""
+    with HWSimRadio(n_channels=2) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+
+        if wpas.get_mcc() < 2:
+            raise Exception("New radio does not support MCC")
 
-    if not params['long']:
-        raise HwsimSkip("Skip test case with long duration due to --long not specified")
+        ndev = [ wpas, dev[1] ]
+        _test_p2p_go_move_active(ndev, apdev)
 
-    dev[0].request("SET p2p_no_group_iface 0")
+def _test_p2p_go_move_active(dev, apdev):
+    dev[0].global_request("SET p2p_no_group_iface 0")
     try:
         dev[0].global_request("P2P_SET disallow_freq 2430-6000")
-        hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid" : 'ap-test',
-                                                    "channel" : '11' })
+        hapd = hostapd.add_ap(apdev[0], { "ssid" : 'ap-test',
+                                          "channel" : '11' })
         dev[0].connect("ap-test", key_mgmt="NONE",
                        scan_freq="2462")
 
@@ -729,31 +757,44 @@ def test_p2p_go_move_active(dev, apdev, params):
             raise Exception("Unexpected channel %d MHz" % freq)
 
         # GO move is not allowed while waiting for initial client connection
-        time.sleep(20)
+        connect_cli(dev[0], dev[1], freq=freq)
+        dev[1].remove_group()
+
+        freq = dev[0].get_group_status_field('freq')
+        if int(freq) > 2430:
+            raise Exception("Unexpected freq after initial client: " + freq)
+
+        dev[0].dump_monitor()
         dev[0].global_request("P2P_SET disallow_freq ")
 
-        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP"],
+        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP",
+                                      "AP-CSA-FINISHED"],
                                      timeout=10)
         if ev is not None:
-            raise Exception("Unexpected P2P-REMOVE-AND-REFORM-GROUP seen")
+            raise Exception("Unexpected P2P-REMOVE-AND-REFORM-GROUP or AP-CSA-FINISHED seen")
 
         dev[0].remove_group()
     finally:
         dev[0].global_request("P2P_SET disallow_freq ")
 
-def test_p2p_go_move_scm(dev, apdev, params):
-    """P2P GO move due to SCM operation preference [long]"""
-    if dev[0].get_mcc() <= 1:
-        raise HwsimSkip("Skip due to MCC not being enabled")
+def test_p2p_go_move_scm(dev, apdev):
+    """P2P GO move due to SCM operation preference"""
+    with HWSimRadio(n_channels=2) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
 
-    if not params['long']:
-        raise HwsimSkip("Skip test case with long duration due to --long not specified")
+        if wpas.get_mcc() < 2:
+            raise Exception("New radio does not support MCC")
 
-    dev[0].request("SET p2p_no_group_iface 0")
+        ndev = [ wpas, dev[1] ]
+        _test_p2p_go_move_scm(ndev, apdev)
+
+def _test_p2p_go_move_scm(dev, apdev):
+    dev[0].global_request("SET p2p_no_group_iface 0")
     try:
         dev[0].global_request("P2P_SET disallow_freq 2430-6000")
-        hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid" : 'ap-test',
-                                                    "channel" : '11' })
+        hapd = hostapd.add_ap(apdev[0], { "ssid" : 'ap-test',
+                                          "channel" : '11' })
         dev[0].connect("ap-test", key_mgmt="NONE",
                        scan_freq="2462")
 
@@ -764,12 +805,22 @@ def test_p2p_go_move_scm(dev, apdev, params):
             raise Exception("Unexpected channel %d MHz" % freq)
 
         # GO move is not allowed while waiting for initial client connection
-        time.sleep(20)
+        connect_cli(dev[0], dev[1], freq=freq)
+        dev[1].remove_group()
+
+        freq = dev[0].get_group_status_field('freq')
+        if int(freq) > 2430:
+            raise Exception("Unexpected freq after initial client: " + freq)
+
+        dev[0].dump_monitor()
         dev[0].global_request("P2P_SET disallow_freq ")
 
-        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP"], timeout=3)
+        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP",
+                                      "AP-CSA-FINISHED"], timeout=3)
         if ev is None:
-            raise Exception("P2P-REMOVE-AND-REFORM-GROUP not seen")
+            raise Exception("P2P-REMOVE-AND-REFORM-GROUP or AP-CSA-FINISHED not seen")
+        if "P2P-REMOVE-AND-REFORM-GROUP" in ev:
+            wait_go_down_up(dev[0])
 
         freq = dev[0].get_group_status_field('freq')
         if freq != '2462':
@@ -780,19 +831,24 @@ def test_p2p_go_move_scm(dev, apdev, params):
         dev[0].global_request("P2P_SET disallow_freq ")
         dev[0].global_request("SET p2p_go_freq_change_policy 2")
 
-def test_p2p_go_move_scm_peer_supports(dev, apdev, params):
-    """P2P GO move due to SCM operation preference (peer supports) [long]"""
-    if dev[0].get_mcc() <= 1:
-        raise HwsimSkip("Skip due to MCC not being enabled")
+def test_p2p_go_move_scm_peer_supports(dev, apdev):
+    """P2P GO move due to SCM operation preference (peer supports)"""
+    with HWSimRadio(n_channels=2) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+
+        if wpas.get_mcc() < 2:
+            raise Exception("New radio does not support MCC")
 
-    if not params['long']:
-        raise HwsimSkip("Skip test case with long duration due to --long not specified")
+        ndev = [ wpas, dev[1] ]
+        _test_p2p_go_move_scm_peer_supports(ndev, apdev)
 
+def _test_p2p_go_move_scm_peer_supports(dev, apdev):
     try:
         dev[0].global_request("SET p2p_go_freq_change_policy 1")
         set_country("US", dev[0])
 
-        dev[0].request("SET p2p_no_group_iface 0")
+        dev[0].global_request("SET p2p_no_group_iface 0")
         [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
                                                r_dev=dev[1], r_intent=0,
                                                test_data=False)
@@ -801,15 +857,18 @@ def test_p2p_go_move_scm_peer_supports(dev, apdev, params):
         if freq < 5000:
             raise Exception("Unexpected channel %d MHz - did not follow 5 GHz preference" % freq)
 
-        hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid" : 'ap-test',
-                                                    "channel" : '11' })
-        logger.info('Connecting client to to an AP on channel 11');
+        hapd = hostapd.add_ap(apdev[0], { "ssid" : 'ap-test',
+                                          "channel" : '11' })
+        logger.info('Connecting client to to an AP on channel 11')
         dev[0].connect("ap-test", key_mgmt="NONE",
                        scan_freq="2462")
 
-        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP"], timeout=3)
+        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP",
+                                      "AP-CSA-FINISHED"], timeout=3)
         if ev is None:
-            raise Exception("P2P-REMOVE-AND-REFORM-GROUP not seen")
+            raise Exception("P2P-REMOVE-AND-REFORM-GROUP or AP-CSA-FINISHED not seen")
+        if "P2P-REMOVE-AND-REFORM-GROUP" in ev:
+            wait_go_down_up(dev[0])
 
         freq = dev[0].get_group_status_field('freq')
         if freq != '2462':
@@ -820,19 +879,24 @@ def test_p2p_go_move_scm_peer_supports(dev, apdev, params):
         dev[0].global_request("SET p2p_go_freq_change_policy 2")
         set_country("00")
 
-def test_p2p_go_move_scm_peer_does_not_support(dev, apdev, params):
-    """No P2P GO move due to SCM operation (peer does not supports) [long]"""
-    if dev[0].get_mcc() <= 1:
-        raise HwsimSkip("Skip due to MCC not being enabled")
+def test_p2p_go_move_scm_peer_does_not_support(dev, apdev):
+    """No P2P GO move due to SCM operation (peer does not supports)"""
+    with HWSimRadio(n_channels=2) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+
+        if wpas.get_mcc() < 2:
+            raise Exception("New radio does not support MCC")
 
-    if not params['long']:
-        raise HwsimSkip("Skip test case with long duration due to --long not specified")
+        ndev = [ wpas, dev[1] ]
+        _test_p2p_go_move_scm_peer_does_not_support(ndev, apdev)
 
+def _test_p2p_go_move_scm_peer_does_not_support(dev, apdev):
     try:
         dev[0].global_request("SET p2p_go_freq_change_policy 1")
         set_country("US", dev[0])
 
-        dev[0].request("SET p2p_no_group_iface 0")
+        dev[0].global_request("SET p2p_no_group_iface 0")
         if "OK" not in dev[1].request("DRIVER_EVENT AVOID_FREQUENCIES 2400-2500"):
             raise Exception("Could not simulate driver event")
         [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
@@ -843,35 +907,42 @@ def test_p2p_go_move_scm_peer_does_not_support(dev, apdev, params):
         if freq < 5000:
             raise Exception("Unexpected channel %d MHz - did not follow 5 GHz preference" % freq)
 
-        hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid" : 'ap-test',
-                                                    "channel" : '11' })
-        logger.info('Connecting client to to an AP on channel 11');
+        hapd = hostapd.add_ap(apdev[0], { "ssid" : 'ap-test',
+                                          "channel" : '11' })
+        logger.info('Connecting client to to an AP on channel 11')
         dev[0].connect("ap-test", key_mgmt="NONE",
                        scan_freq="2462")
 
-        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP"],
+        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP",
+                                      "AP-CSA-FINISHED"],
                                      timeout=10)
         if ev is not None:
-            raise Exception("Unexpected P2P-REMOVE-AND-REFORM-GROUP seen")
+            raise Exception("Unexpected P2P-REMOVE-AND-REFORM-GROUP or AP-CSA-FINISHED seen")
 
         dev[0].remove_group()
     finally:
         dev[0].global_request("SET p2p_go_freq_change_policy 2")
+        dev[1].request("DRIVER_EVENT AVOID_FREQUENCIES")
         set_country("00")
 
-def test_p2p_go_move_scm_multi(dev, apdev, params):
-    """P2P GO move due to SCM operation preference multiple times [long]"""
-    if dev[0].get_mcc() <= 1:
-        raise HwsimSkip("Skip due to MCC not being enabled")
+def test_p2p_go_move_scm_multi(dev, apdev):
+    """P2P GO move due to SCM operation preference multiple times"""
+    with HWSimRadio(n_channels=2) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
 
-    if not params['long']:
-        raise HwsimSkip("Skip test case with long duration due to --long not specified")
+        if wpas.get_mcc() < 2:
+            raise Exception("New radio does not support MCC")
+
+        ndev = [ wpas, dev[1] ]
+        _test_p2p_go_move_scm_multi(ndev, apdev)
 
+def _test_p2p_go_move_scm_multi(dev, apdev):
     dev[0].request("SET p2p_no_group_iface 0")
     try:
         dev[0].global_request("P2P_SET disallow_freq 2430-6000")
-        hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid" : 'ap-test-1',
-                                                    "channel" : '11' })
+        hapd = hostapd.add_ap(apdev[0], { "ssid" : 'ap-test-1',
+                                          "channel" : '11' })
         dev[0].connect("ap-test-1", key_mgmt="NONE",
                        scan_freq="2462")
 
@@ -882,25 +953,38 @@ def test_p2p_go_move_scm_multi(dev, apdev, params):
             raise Exception("Unexpected channel %d MHz" % freq)
 
         # GO move is not allowed while waiting for initial client connection
-        time.sleep(20)
+        connect_cli(dev[0], dev[1], freq=freq)
+        dev[1].remove_group()
+
+        freq = dev[0].get_group_status_field('freq')
+        if int(freq) > 2430:
+            raise Exception("Unexpected freq after initial client: " + freq)
+
+        dev[0].dump_monitor()
         dev[0].global_request("P2P_SET disallow_freq ")
 
-        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP"], timeout=3)
+        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP",
+                                      "AP-CSA-FINISHED"], timeout=3)
         if ev is None:
-            raise Exception("P2P-REMOVE-AND-REFORM-GROUP not seen")
+            raise Exception("P2P-REMOVE-AND-REFORM-GROUP or AP-CSA-FINISHED not seen")
+        if "P2P-REMOVE-AND-REFORM-GROUP" in ev:
+            wait_go_down_up(dev[0])
 
         freq = dev[0].get_group_status_field('freq')
         if freq != '2462':
             raise Exception("Unexpected freq after group reform=" + freq)
 
-        hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid" : 'ap-test-2',
-                                                    "channel" : '6' })
+        hapd = hostapd.add_ap(apdev[0], { "ssid" : 'ap-test-2',
+                                          "channel" : '6' })
         dev[0].connect("ap-test-2", key_mgmt="NONE",
                        scan_freq="2437")
 
-        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP"], timeout=5)
+        ev = dev[0].wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP",
+                                      "AP-CSA-FINISHED"], timeout=5)
         if ev is None:
-            raise Exception("(2) P2P-REMOVE-AND-REFORM-GROUP not seen")
+            raise Exception("(2) P2P-REMOVE-AND-REFORM-GROUP or AP-CSA-FINISHED not seen")
+        if "P2P-REMOVE-AND-REFORM-GROUP" in ev:
+            wait_go_down_up(dev[0])
 
         freq = dev[0].get_group_status_field('freq')
         if freq != '2437':
@@ -910,3 +994,207 @@ def test_p2p_go_move_scm_multi(dev, apdev, params):
     finally:
         dev[0].global_request("P2P_SET disallow_freq ")
         dev[0].global_request("SET p2p_go_freq_change_policy 2")
+
+def test_p2p_delay_go_csa(dev, apdev, params):
+    """P2P GO CSA delayed when inviting a P2P Device to an active P2P Group"""
+    with HWSimRadio(n_channels=2) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+
+        wpas.global_request("SET p2p_no_group_iface 0")
+
+        if wpas.get_mcc() < 2:
+           raise Exception("New radio does not support MCC")
+
+        addr0 = wpas.p2p_dev_addr()
+        addr1 = dev[1].p2p_dev_addr()
+
+        try:
+            dev[1].p2p_listen()
+            if not wpas.discover_peer(addr1, social=True):
+                raise Exception("Peer " + addr1 + " not found")
+            wpas.p2p_stop_find()
+
+            hapd = hostapd.add_ap(apdev[0], { "ssid": 'bss-2.4ghz',
+                                              "channel": '1' })
+
+            wpas.connect("bss-2.4ghz", key_mgmt="NONE", scan_freq="2412")
+
+            wpas.global_request("SET p2p_go_freq_change_policy 0")
+            wpas.dump_monitor()
+
+            logger.info("Start GO on channel 6")
+            res = autogo(wpas, freq=2437)
+            if res['freq'] != "2437":
+               raise Exception("GO set on a freq=%s instead of 2437" % res['freq'])
+
+            # Start find on dev[1] to run scans with dev[2] in parallel
+            dev[1].p2p_find(social=True)
+
+            # Use another client device to stop the initial client connection
+            # timeout on the GO
+            if not dev[2].discover_peer(addr0, social=True):
+                raise Exception("Peer2 did not find the GO")
+            dev[2].p2p_stop_find()
+            pin = dev[2].wps_read_pin()
+            wpas.p2p_go_authorize_client(pin)
+            dev[2].global_request("P2P_CONNECT " + addr0 + " " + pin + " join freq=2437")
+            ev = dev[2].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+            if ev is None:
+                raise Exception("Peer2 did not get connected")
+
+            if not dev[1].discover_peer(addr0, social=True):
+                raise Exception("Peer did not find the GO")
+
+            pin = dev[1].wps_read_pin()
+            dev[1].global_request("P2P_CONNECT " + addr0 + " " + pin + " join auth")
+            dev[1].p2p_listen()
+
+            # Force P2P GO channel switch on successful invitation signaling
+            wpas.group_request("SET p2p_go_csa_on_inv 1")
+
+            logger.info("Starting invitation")
+            wpas.p2p_go_authorize_client(pin)
+            wpas.global_request("P2P_INVITE group=" + wpas.group_ifname + " peer=" + addr1)
+            ev = dev[1].wait_global_event(["P2P-INVITATION-RECEIVED",
+                                           "P2P-GROUP-STARTED"], timeout=10)
+
+            if ev is None:
+                raise Exception("Timeout on invitation on peer")
+            if "P2P-INVITATION-RECEIVED" in ev:
+                raise Exception("Unexpected request to accept pre-authorized invitation")
+
+            # A P2P GO move is not expected at this stage, as during the
+            # invitation signaling, the P2P GO includes only its current
+            # operating channel in the channel list, and as the invitation
+            # response can only include channels that were also in the
+            # invitation request channel list, the group common channels
+            # includes only the current P2P GO operating channel.
+            ev = wpas.wait_group_event(["P2P-REMOVE-AND-REFORM-GROUP",
+                                        "AP-CSA-FINISHED"], timeout=1)
+            if ev is not None:
+                raise Exception("Unexpected + " + ev + " event")
+
+        finally:
+            wpas.global_request("SET p2p_go_freq_change_policy 2")
+
+def test_p2p_channel_vht80p80(dev):
+    """P2P group formation and VHT 80+80 MHz channel"""
+    try:
+        set_country("US", dev[0])
+        [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
+                                               i_freq=5180,
+                                               i_freq2=5775,
+                                               i_max_oper_chwidth=160,
+                                               i_ht40=True, i_vht=True,
+                                               r_dev=dev[1], r_intent=0,
+                                               test_data=False)
+        check_grpform_results(i_res, r_res)
+        freq = int(i_res['freq'])
+        if freq < 5000:
+            raise Exception("Unexpected channel %d MHz - did not follow 5 GHz preference" % freq)
+        sig = dev[1].group_request("SIGNAL_POLL").splitlines()
+        if "FREQUENCY=5180" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
+        if "WIDTH=80+80 MHz" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
+        if "CENTER_FRQ1=5210" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(3): " + str(sig))
+        if "CENTER_FRQ2=5775" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(4): " + str(sig))
+        remove_group(dev[0], dev[1])
+    finally:
+        set_country("00")
+        dev[1].flush_scan_cache()
+
+def test_p2p_channel_vht80p80_autogo(dev):
+    """P2P autonomous GO and VHT 80+80 MHz channel"""
+    addr0 = dev[0].p2p_dev_addr()
+
+    try:
+        set_country("US", dev[0])
+        if "OK" not in dev[0].global_request("P2P_GROUP_ADD vht freq=5180 freq2=5775"):
+            raise Exception("Could not start GO")
+        ev = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=5)
+        if ev is None:
+            raise Exception("GO start up timed out")
+        dev[0].group_form_result(ev)
+
+        pin = dev[1].wps_read_pin()
+        dev[0].p2p_go_authorize_client(pin)
+
+        dev[1].global_request("P2P_CONNECT " + addr0 + " " + pin + " join freq=5180")
+        ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+        if ev is None:
+            raise Exception("Peer did not get connected")
+
+        dev[1].group_form_result(ev)
+        sig = dev[1].group_request("SIGNAL_POLL").splitlines()
+        if "FREQUENCY=5180" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
+        if "WIDTH=80+80 MHz" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
+        if "CENTER_FRQ1=5210" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(3): " + str(sig))
+        if "CENTER_FRQ2=5775" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(4): " + str(sig))
+        remove_group(dev[0], dev[1])
+    finally:
+        set_country("00")
+        dev[1].flush_scan_cache()
+
+def test_p2p_channel_vht80_autogo(dev):
+    """P2P autonomous GO and VHT 80 MHz channel"""
+    addr0 = dev[0].p2p_dev_addr()
+
+    try:
+        set_country("US", dev[0])
+        if "OK" not in dev[0].global_request("P2P_GROUP_ADD vht freq=5180 max_oper_chwidth=80"):
+            raise Exception("Could not start GO")
+        ev = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=5)
+        if ev is None:
+            raise Exception("GO start up timed out")
+        dev[0].group_form_result(ev)
+
+        pin = dev[1].wps_read_pin()
+        dev[0].p2p_go_authorize_client(pin)
+
+        dev[1].global_request("P2P_CONNECT " + addr0 + " " + pin + " join freq=5180")
+        ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+        if ev is None:
+            raise Exception("Peer did not get connected")
+
+        dev[1].group_form_result(ev)
+        sig = dev[1].group_request("SIGNAL_POLL").splitlines()
+        if "FREQUENCY=5180" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
+        if "WIDTH=80 MHz" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
+        remove_group(dev[0], dev[1])
+    finally:
+        set_country("00")
+        dev[1].flush_scan_cache()
+
+def test_p2p_channel_vht80p80_persistent(dev):
+    """P2P persistent group re-invocation and VHT 80+80 MHz channel"""
+    addr0 = dev[0].p2p_dev_addr()
+    form(dev[0], dev[1])
+
+    try:
+        set_country("US", dev[0])
+        invite(dev[0], dev[1], extra="vht freq=5745 freq2=5210")
+        [go_res, cli_res] = check_result(dev[0], dev[1])
+
+        sig = dev[1].group_request("SIGNAL_POLL").splitlines()
+        if "FREQUENCY=5745" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
+        if "WIDTH=80+80 MHz" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
+        if "CENTER_FRQ1=5775" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(3): " + str(sig))
+        if "CENTER_FRQ2=5210" not in sig:
+            raise Exception("Unexpected SIGNAL_POLL value(4): " + str(sig))
+        remove_group(dev[0], dev[1])
+    finally:
+        set_country("00")
+        dev[1].flush_scan_cache()
index 16be8c6..81545cc 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 import subprocess
@@ -11,27 +12,21 @@ import time
 
 import hwsim_utils
 import hostapd
-from test_p2p_grpform import go_neg_pin_authorized
-from test_p2p_grpform import go_neg_pbc
-from test_p2p_grpform import check_grpform_results
-from test_p2p_grpform import remove_group
-from test_p2p_persistent import form
-from test_p2p_persistent import invite_from_cli
-from test_p2p_persistent import invite_from_go
-from test_p2p_persistent import invite
+from p2p_utils import *
 from test_ap_ht import clear_scan_cache
 from utils import HwsimSkip
 
+@remote_compatible
 def test_concurrent_autogo(dev, apdev):
     """Concurrent P2P autonomous GO"""
     logger.info("Connect to an infrastructure AP")
     dev[0].request("P2P_SET cross_connect 0")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-open" })
     dev[0].connect("test-open", key_mgmt="NONE", scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
     logger.info("Start a P2P group while associated to an AP")
-    dev[0].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
     dev[0].p2p_start_go()
     pin = dev[1].wps_read_pin()
     dev[0].p2p_go_authorize_client(pin)
@@ -46,7 +41,7 @@ def test_concurrent_autogo(dev, apdev):
 
 def test_concurrent_autogo_5ghz_ht40(dev, apdev):
     """Concurrent P2P autonomous GO on 5 GHz and HT40 co-ex"""
-    clear_scan_cache(apdev[1]['ifname'])
+    clear_scan_cache(apdev[1])
     try:
         hapd = None
         hapd2 = None
@@ -55,20 +50,20 @@ def test_concurrent_autogo_5ghz_ht40(dev, apdev):
                    "channel": "153",
                    "country_code": "US",
                    "ht_capab": "[HT40-]" }
-        hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+        hapd2 = hostapd.add_ap(apdev[1], params)
 
         params = { "ssid": "test-open-5",
                    "hw_mode": "a",
                    "channel": "149",
                    "country_code": "US" }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
 
         dev[0].request("P2P_SET cross_connect 0")
         dev[0].scan_for_bss(apdev[0]['bssid'], freq=5745)
         dev[0].scan_for_bss(apdev[1]['bssid'], freq=5765)
         dev[0].connect("test-open-5", key_mgmt="NONE", scan_freq="5745")
 
-        dev[0].request("SET p2p_no_group_iface 0")
+        dev[0].global_request("SET p2p_no_group_iface 0")
         if "OK" not in dev[0].global_request("P2P_GROUP_ADD ht40"):
             raise Exception("P2P_GROUP_ADD failed")
         ev = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=5)
@@ -103,7 +98,7 @@ def test_concurrent_autogo_5ghz_ht40(dev, apdev):
 def test_concurrent_autogo_crossconnect(dev, apdev):
     """Concurrent P2P autonomous GO"""
     dev[0].global_request("P2P_SET cross_connect 1")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-open" })
     dev[0].connect("test-open", key_mgmt="NONE", scan_freq="2412")
 
     dev[0].global_request("SET p2p_no_group_iface 0")
@@ -137,15 +132,16 @@ def test_concurrent_autogo_crossconnect(dev, apdev):
         raise Exception("Timeout on cross connection disabled event")
     dev[0].global_request("P2P_SET cross_connect 0")
 
+@remote_compatible
 def test_concurrent_p2pcli(dev, apdev):
     """Concurrent P2P client join"""
     logger.info("Connect to an infrastructure AP")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-open" })
     dev[0].connect("test-open", key_mgmt="NONE", scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
     logger.info("Join a P2P group while associated to an AP")
-    dev[0].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
     dev[1].p2p_start_go(freq=2412)
     pin = dev[0].wps_read_pin()
     dev[1].p2p_go_authorize_client(pin)
@@ -158,15 +154,16 @@ def test_concurrent_p2pcli(dev, apdev):
     logger.info("Confirm AP connection after P2P group removal")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_concurrent_grpform_go(dev, apdev):
     """Concurrent P2P group formation to become GO"""
     logger.info("Connect to an infrastructure AP")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-open" })
     dev[0].connect("test-open", key_mgmt="NONE", scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
     logger.info("Form a P2P group while associated to an AP")
-    dev[0].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
 
     [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
                                            r_dev=dev[1], r_intent=0)
@@ -176,15 +173,16 @@ def test_concurrent_grpform_go(dev, apdev):
     logger.info("Confirm AP connection after P2P group removal")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_concurrent_grpform_cli(dev, apdev):
     """Concurrent P2P group formation to become P2P Client"""
     logger.info("Connect to an infrastructure AP")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-open" })
     dev[0].connect("test-open", key_mgmt="NONE", scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
     logger.info("Form a P2P group while associated to an AP")
-    dev[0].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
 
     [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=0,
                                            r_dev=dev[1], r_intent=15)
@@ -194,14 +192,15 @@ def test_concurrent_grpform_cli(dev, apdev):
     logger.info("Confirm AP connection after P2P group removal")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_concurrent_grpform_while_connecting(dev, apdev):
     """Concurrent P2P group formation while connecting to an AP"""
     logger.info("Start connection to an infrastructure AP")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-open" })
     dev[0].connect("test-open", key_mgmt="NONE", wait_connect=False)
 
     logger.info("Form a P2P group while connecting to an AP")
-    dev[0].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
 
     [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_freq=2412,
                                            r_dev=dev[1], r_freq=2412)
@@ -211,15 +210,16 @@ def test_concurrent_grpform_while_connecting(dev, apdev):
     logger.info("Confirm AP connection after P2P group removal")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_concurrent_grpform_while_connecting2(dev, apdev):
     """Concurrent P2P group formation while connecting to an AP (2)"""
     logger.info("Start connection to an infrastructure AP")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-open" })
     dev[0].connect("test-open", key_mgmt="NONE", wait_connect=False)
     dev[1].flush_scan_cache()
 
     logger.info("Form a P2P group while connecting to an AP")
-    dev[0].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
 
     [i_res, r_res] = go_neg_pbc(i_dev=dev[0], i_intent=15, i_freq=2412,
                                 r_dev=dev[1], r_intent=0, r_freq=2412)
@@ -230,14 +230,15 @@ def test_concurrent_grpform_while_connecting2(dev, apdev):
     dev[0].wait_completed()
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_concurrent_grpform_while_connecting3(dev, apdev):
     """Concurrent P2P group formation while connecting to an AP (3)"""
     logger.info("Start connection to an infrastructure AP")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-open" })
     dev[0].connect("test-open", key_mgmt="NONE", wait_connect=False)
 
     logger.info("Form a P2P group while connecting to an AP")
-    dev[0].request("SET p2p_no_group_iface 0")
+    dev[0].global_request("SET p2p_no_group_iface 0")
 
     [i_res, r_res] = go_neg_pbc(i_dev=dev[1], i_intent=15, i_freq=2412,
                                 r_dev=dev[0], r_intent=0, r_freq=2412)
@@ -248,10 +249,11 @@ def test_concurrent_grpform_while_connecting3(dev, apdev):
     dev[0].wait_completed()
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+@remote_compatible
 def test_concurrent_persistent_group(dev, apdev):
     """Concurrent P2P persistent group"""
     logger.info("Connect to an infrastructure AP")
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open", "channel": "2" })
+    hostapd.add_ap(apdev[0], { "ssid": "test-open", "channel": "2" })
     dev[0].global_request("SET p2p_no_group_iface 0")
     dev[0].connect("test-open", key_mgmt="NONE", scan_freq="2417")
 
@@ -274,7 +276,7 @@ def test_concurrent_invitation_channel_mismatch(dev, apdev):
     dev[1].dump_monitor()
 
     logger.info("Connect to an infrastructure AP")
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-open", "channel": "2" })
+    hostapd.add_ap(apdev[0], { "ssid": "test-open", "channel": "2" })
     dev[0].global_request("SET p2p_no_group_iface 0")
     dev[0].connect("test-open", key_mgmt="NONE", scan_freq="2417")
     invite(dev[1], dev[0], extra="freq=2412")
index c7e6299..36a7041 100644 (file)
@@ -9,11 +9,10 @@ logger = logging.getLogger()
 import time
 
 from wpasupplicant import WpaSupplicant
-from test_p2p_grpform import go_neg_pin_authorized
-from test_p2p_grpform import check_grpform_results
-from test_p2p_grpform import remove_group
+from p2p_utils import *
 from test_nfc_p2p import set_ip_addr_info, check_ip_addr, grpform_events
 from hwsim import HWSimRadio
+from utils import HwsimSkip
 import hostapd
 import hwsim_utils
 
@@ -25,7 +24,11 @@ def test_p2p_device_grpform(dev, apdev):
         [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
                                                r_dev=wpas, r_intent=0)
         check_grpform_results(i_res, r_res)
+        wpas.dump_monitor()
         remove_group(dev[0], wpas)
+        wpas.dump_monitor()
+        if not r_res['ifname'].startswith('p2p-' + iface):
+            raise Exception("Unexpected group ifname: " + r_res['ifname'])
 
         res = wpas.global_request("IFNAME=p2p-dev-" + iface + " STATUS-DRIVER")
         lines = res.splitlines()
@@ -49,7 +52,41 @@ def test_p2p_device_grpform2(dev, apdev):
         [i_res, r_res] = go_neg_pin_authorized(i_dev=wpas, i_intent=15,
                                                r_dev=dev[0], r_intent=0)
         check_grpform_results(i_res, r_res)
+        wpas.dump_monitor()
         remove_group(wpas, dev[0])
+        wpas.dump_monitor()
+        if not i_res['ifname'].startswith('p2p-' + iface):
+            raise Exception("Unexpected group ifname: " + i_res['ifname'])
+
+def test_p2p_device_grpform_no_group_iface(dev, apdev):
+    """P2P group formation with driver using cfg80211 P2P Device but no separate group interface"""
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+        wpas.global_request("SET p2p_no_group_iface 1")
+        [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
+                                               r_dev=wpas, r_intent=0)
+        check_grpform_results(i_res, r_res)
+        wpas.dump_monitor()
+        remove_group(dev[0], wpas)
+        wpas.dump_monitor()
+        if r_res['ifname'] != iface:
+            raise Exception("Unexpected group ifname: " + r_res['ifname'])
+
+def test_p2p_device_grpform_no_group_iface2(dev, apdev):
+    """P2P group formation with driver using cfg80211 P2P Device but no separate group interface (reverse)"""
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+        wpas.global_request("SET p2p_no_group_iface 1")
+        [i_res, r_res] = go_neg_pin_authorized(i_dev=wpas, i_intent=15,
+                                               r_dev=dev[0], r_intent=0)
+        check_grpform_results(i_res, r_res)
+        wpas.dump_monitor()
+        remove_group(dev[0], wpas)
+        wpas.dump_monitor()
+        if i_res['ifname'] != iface:
+            raise Exception("Unexpected group ifname: " + i_res['ifname'])
 
 def test_p2p_device_group_remove(dev, apdev):
     """P2P group removal via the P2P ctrl interface with driver using cfg80211 P2P Device"""
@@ -83,10 +120,18 @@ def test_p2p_device_concurrent_scan(dev, apdev):
             raise Exception("Station mode scan did not start")
 
 def test_p2p_device_nfc_invite(dev, apdev):
-    """P2P NFC invitiation with driver using cfg80211 P2P Device"""
+    """P2P NFC invitation with driver using cfg80211 P2P Device"""
+    run_p2p_device_nfc_invite(dev, apdev, 0)
+
+def test_p2p_device_nfc_invite_no_group_iface(dev, apdev):
+    """P2P NFC invitation with driver using cfg80211 P2P Device (no separate group interface)"""
+    run_p2p_device_nfc_invite(dev, apdev, 1)
+
+def run_p2p_device_nfc_invite(dev, apdev, no_group_iface):
     with HWSimRadio(use_p2p_device=True) as (radio, iface):
         wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
         wpas.interface_add(iface)
+        wpas.global_request("SET p2p_no_group_iface %d" % no_group_iface)
 
         set_ip_addr_info(dev[0])
         logger.info("Start autonomous GO")
@@ -96,6 +141,7 @@ def test_p2p_device_nfc_invite(dev, apdev):
         res = wpas.global_request("P2P_LISTEN")
         if "FAIL" in res:
             raise Exception("Failed to start Listen mode")
+        wpas.dump_monitor()
         pw = wpas.global_request("WPS_NFC_TOKEN NDEF").rstrip()
         if "FAIL" in pw:
             raise Exception("Failed to generate password token")
@@ -105,6 +151,7 @@ def test_p2p_device_nfc_invite(dev, apdev):
         sel = wpas.global_request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
         if "FAIL" in sel:
             raise Exception("Failed to generate NFC connection handover select")
+        wpas.dump_monitor()
 
         logger.info("Read NFC Tag on the GO to trigger invitation")
         res = dev[0].global_request("WPS_NFC_TAG_READ " + sel)
@@ -115,12 +162,14 @@ def test_p2p_device_nfc_invite(dev, apdev):
         if ev is None:
             raise Exception("Joining the group timed out")
         res = wpas.group_form_result(ev)
+        wpas.dump_monitor()
         hwsim_utils.test_connectivity_p2p(dev[0], wpas)
         check_ip_addr(res)
+        wpas.dump_monitor()
 
 def test_p2p_device_misuses(dev, apdev):
     """cfg80211 P2P Device misuses"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     with HWSimRadio(use_p2p_device=True) as (radio, iface):
         wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
         wpas.interface_add(iface)
@@ -189,11 +238,13 @@ def test_p2p_device_incorrect_command_interface(dev, apdev):
         ev = wpas.wait_event(["P2P-DEVICE-FOUND"], timeout=0.1)
         if ev is not None:
             raise Exception("Unexpected P2P-DEVICE-FOUND event on station interface")
+        wpas.dump_monitor()
 
         pin = wpas.wps_read_pin()
         dev[0].p2p_go_neg_auth(wpas.p2p_dev_addr(), pin, "enter", go_intent=14,
                                freq=2412)
         wpas.request('P2P_STOP_FIND')
+        wpas.dump_monitor()
         if "OK" not in wpas.request('P2P_CONNECT ' + dev[0].p2p_dev_addr() + ' ' + pin + ' display go_intent=1'):
             raise Exception("P2P_CONNECT failed")
 
@@ -201,6 +252,7 @@ def test_p2p_device_incorrect_command_interface(dev, apdev):
         if ev is None:
             raise Exception("Group formation timed out")
         wpas.group_form_result(ev)
+        wpas.dump_monitor()
 
         ev = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
         if ev is None:
@@ -209,6 +261,7 @@ def test_p2p_device_incorrect_command_interface(dev, apdev):
 
         dev[0].remove_group()
         wpas.wait_go_ending_session()
+        wpas.dump_monitor()
 
 def test_p2p_device_incorrect_command_interface2(dev, apdev):
     """cfg80211 P2P Device and P2P_GROUP_ADD command on incorrect interface"""
@@ -216,12 +269,238 @@ def test_p2p_device_incorrect_command_interface2(dev, apdev):
         wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
         wpas.interface_add(iface)
 
-        print wpas.request('P2P_GROUP_ADD')
+        if "OK" not in wpas.request('P2P_GROUP_ADD'):
+            raise Exception("P2P_GROUP_ADD failed")
         ev = wpas.wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
         if ev is None:
             raise Exception("Group formation timed out")
         res = wpas.group_form_result(ev)
+        wpas.dump_monitor()
         logger.info("Group results: " + str(res))
         wpas.remove_group()
         if not res['ifname'].startswith('p2p-' + iface + '-'):
             raise Exception("Unexpected group ifname: " + res['ifname'])
+        wpas.dump_monitor()
+
+def test_p2p_device_grpform_timeout_client(dev, apdev):
+    """P2P group formation timeout on client with cfg80211 P2P Device"""
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+        addr0 = dev[0].p2p_dev_addr()
+        addr5 = wpas.p2p_dev_addr()
+        wpas.p2p_listen()
+        dev[0].discover_peer(addr5)
+        dev[0].p2p_listen()
+        wpas.discover_peer(addr0)
+        wpas.p2p_ext_listen(100, 150)
+        dev[0].global_request("P2P_CONNECT " + addr5 + " 12345670 enter go_intent=15 auth")
+        wpas.global_request("P2P_CONNECT " + addr0 + " 12345670 display go_intent=0")
+        ev = dev[0].wait_global_event(["P2P-GO-NEG-SUCCESS"], timeout=5)
+        if ev is None:
+            raise Exception("GO Negotiation did not succeed")
+        ev = dev[0].wait_global_event(["WPS-SUCCESS"], timeout=10)
+        if ev is None:
+            raise Exception("WPS did not succeed (GO)")
+        if "OK" not in dev[0].global_request("P2P_CANCEL"):
+            wpas.global_request("P2P_CANCEL")
+            del wpas
+            raise HwsimSkip("Did not manage to cancel group formation")
+        dev[0].dump_monitor()
+        ev = wpas.wait_global_event(["WPS-SUCCESS"], timeout=10)
+        if ev is None:
+            raise Exception("WPS did not succeed (Client)")
+        dev[0].dump_monitor()
+        ev = wpas.wait_global_event(["P2P-GROUP-FORMATION-FAILURE"], timeout=20)
+        if ev is None:
+            raise Exception("Group formation timeout not seen on client")
+        ev = wpas.wait_global_event(["P2P-GROUP-REMOVED"], timeout=5)
+        if ev is None:
+            raise Exception("Group removal not seen on client")
+        wpas.p2p_cancel_ext_listen()
+        time.sleep(0.1)
+        ifaces = wpas.global_request("INTERFACES")
+        logger.info("Remaining interfaces: " + ifaces)
+        del wpas
+        if "p2p-" + iface + "-" in ifaces:
+            raise Exception("Group interface still present after failure")
+
+def test_p2p_device_grpform_timeout_go(dev, apdev):
+    """P2P group formation timeout on GO with cfg80211 P2P Device"""
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+        addr0 = dev[0].p2p_dev_addr()
+        addr5 = wpas.p2p_dev_addr()
+        wpas.p2p_listen()
+        dev[0].discover_peer(addr5)
+        dev[0].p2p_listen()
+        wpas.discover_peer(addr0)
+        wpas.p2p_ext_listen(100, 150)
+        dev[0].global_request("P2P_CONNECT " + addr5 + " 12345670 enter go_intent=0 auth")
+        wpas.global_request("P2P_CONNECT " + addr0 + " 12345670 display go_intent=15")
+        ev = dev[0].wait_global_event(["P2P-GO-NEG-SUCCESS"], timeout=5)
+        if ev is None:
+            raise Exception("GO Negotiation did not succeed")
+        ev = dev[0].wait_global_event(["WPS-SUCCESS"], timeout=10)
+        if ev is None:
+            raise Exception("WPS did not succeed (Client)")
+        if "OK" not in dev[0].global_request("P2P_CANCEL"):
+            if "OK" not in dev[0].global_request("P2P_GROUP_REMOVE *"):
+                wpas.global_request("P2P_CANCEL")
+                del wpas
+                raise HwsimSkip("Did not manage to cancel group formation")
+        dev[0].dump_monitor()
+        ev = wpas.wait_global_event(["WPS-SUCCESS"], timeout=10)
+        if ev is None:
+            raise Exception("WPS did not succeed (GO)")
+        dev[0].dump_monitor()
+        ev = wpas.wait_global_event(["P2P-GROUP-FORMATION-FAILURE"], timeout=20)
+        if ev is None:
+            raise Exception("Group formation timeout not seen on GO")
+        ev = wpas.wait_global_event(["P2P-GROUP-REMOVED"], timeout=5)
+        if ev is None:
+            raise Exception("Group removal not seen on GO")
+        wpas.p2p_cancel_ext_listen()
+        time.sleep(0.1)
+        ifaces = wpas.global_request("INTERFACES")
+        logger.info("Remaining interfaces: " + ifaces)
+        del wpas
+        if "p2p-" + iface + "-" in ifaces:
+            raise Exception("Group interface still present after failure")
+
+def test_p2p_device_autogo(dev, apdev):
+    """P2P autogo using cfg80211 P2P Device"""
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+
+        res = wpas.p2p_start_go()
+        if not res['ifname'].startswith('p2p-' + iface):
+            raise Exception("Unexpected group ifname: " + res['ifname'])
+        bssid = wpas.get_group_status_field('bssid')
+
+        dev[0].scan_for_bss(bssid, res['freq'])
+        connect_cli(wpas, dev[0], freq=res['freq'])
+        terminate_group(wpas, dev[0])
+
+def test_p2p_device_autogo_no_group_iface(dev, apdev):
+    """P2P autogo using cfg80211 P2P Device (no separate group interface)"""
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+        wpas.global_request("SET p2p_no_group_iface 1")
+
+        res = wpas.p2p_start_go()
+        if res['ifname'] != iface:
+            raise Exception("Unexpected group ifname: " + res['ifname'])
+        bssid = wpas.get_group_status_field('bssid')
+
+        dev[0].scan_for_bss(bssid, res['freq'])
+        connect_cli(wpas, dev[0], freq=res['freq'])
+        terminate_group(wpas, dev[0])
+
+def test_p2p_device_join(dev, apdev):
+    """P2P join-group using cfg80211 P2P Device"""
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+
+        res = dev[0].p2p_start_go()
+        bssid = dev[0].get_group_status_field('bssid')
+
+        wpas.scan_for_bss(bssid, res['freq'])
+        res2 = connect_cli(dev[0], wpas, freq=res['freq'])
+        if not res2['ifname'].startswith('p2p-' + iface):
+            raise Exception("Unexpected group ifname: " + res2['ifname'])
+
+        terminate_group(dev[0], wpas)
+
+def test_p2p_device_join_no_group_iface(dev, apdev):
+    """P2P join-group using cfg80211 P2P Device (no separate group interface)"""
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+        wpas.global_request("SET p2p_no_group_iface 1")
+
+        res = dev[0].p2p_start_go()
+        bssid = dev[0].get_group_status_field('bssid')
+
+        wpas.scan_for_bss(bssid, res['freq'])
+        res2 = connect_cli(dev[0], wpas, freq=res['freq'])
+        if res2['ifname'] != iface:
+            raise Exception("Unexpected group ifname: " + res2['ifname'])
+
+        terminate_group(dev[0], wpas)
+
+def test_p2p_device_persistent_group(dev):
+    """P2P persistent group formation and re-invocation with cfg80211 P2P Device"""
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+        wpas.global_request("SET p2p_no_group_iface 0")
+
+        form(dev[0], wpas)
+        invite_from_cli(dev[0], wpas)
+        invite_from_go(dev[0], wpas)
+
+def test_p2p_device_persistent_group_no_group_iface(dev):
+    """P2P persistent group formation and re-invocation with cfg80211 P2P Device (no separate group interface)"""
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+        wpas.global_request("SET p2p_no_group_iface 1")
+
+        form(dev[0], wpas)
+        invite_from_cli(dev[0], wpas)
+        invite_from_go(dev[0], wpas)
+
+def test_p2p_device_persistent_group2(dev):
+    """P2P persistent group formation and re-invocation (reverse) with cfg80211 P2P Device"""
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+        wpas.global_request("SET p2p_no_group_iface 0")
+
+        form(wpas, dev[0])
+        invite_from_cli(wpas, dev[0])
+        invite_from_go(wpas, dev[0])
+
+def test_p2p_device_persistent_group2_no_group_iface(dev):
+    """P2P persistent group formation and re-invocation (reverse) with cfg80211 P2P Device (no separate group interface)"""
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+        wpas.global_request("SET p2p_no_group_iface 1")
+
+        form(wpas, dev[0])
+        invite_from_cli(wpas, dev[0])
+        invite_from_go(wpas, dev[0])
+
+def p2p_device_group_conf(dev1, dev2):
+    dev1.global_request("SET p2p_group_idle 12")
+    dev1.global_request("SET p2p_go_freq_change_policy 2")
+    dev1.global_request("SET p2p_go_ctwindow 7")
+
+    [i_res, r_res] = go_neg_pin_authorized(i_dev=dev1, i_intent=15,
+                                           r_dev=dev2, r_intent=0)
+    check_grpform_results(i_res, r_res)
+
+    if (dev1.group_request("GET p2p_group_idle") != "12" or
+        dev1.group_request("GET p2p_go_freq_change_policy") != "2" or
+        dev1.group_request("GET p2p_go_ctwindow") != "7"):
+        raise Exception("Unexpected configuration value")
+
+    remove_group(dev1, dev2)
+    dev1.global_request("P2P_FLUSH")
+    dev2.global_request("P2P_FLUSH")
+
+def test_p2p_device_conf(dev, apdev):
+    """P2P configuration with cfg80211 P2P Device"""
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+        wpas.global_request("SET p2p_no_group_iface 1")
+        p2p_device_group_conf(wpas, dev[0])
+        wpas.global_request("SET p2p_no_group_iface 0")
+        p2p_device_group_conf(wpas, dev[0])
index fbd3f83..166180e 100644 (file)
@@ -4,13 +4,19 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
+import os
 import time
 
 import hwsim_utils
 from wpasupplicant import WpaSupplicant
+from p2p_utils import *
+from test_gas import start_ap
+from test_cfg80211 import nl80211_remain_on_channel
 
+@remote_compatible
 def test_discovery(dev):
     """P2P device discovery and provision discovery"""
     addr0 = dev[0].p2p_dev_addr()
@@ -93,6 +99,7 @@ def test_discovery(dev):
     if "FAIL" not in dev[0].global_request("P2P_PROV_DISC 00:11:22:33:44:55 foo"):
         raise Exception("Invalid P2P_PROV_DISC accepted")
 
+@remote_compatible
 def test_discovery_pd_retries(dev):
     """P2P device discovery and provision discovery retries"""
     addr0 = dev[0].p2p_dev_addr()
@@ -115,12 +122,15 @@ def test_discovery_group_client(dev):
     logger.info("Connect a client to the GO")
     pin = dev[1].wps_read_pin()
     dev[0].p2p_go_authorize_client(pin)
-    dev[1].p2p_connect_group(dev[0].p2p_dev_addr(), pin, timeout=60)
+    dev[1].p2p_connect_group(dev[0].p2p_dev_addr(), pin, freq=int(res['freq']),
+                             timeout=60)
     logger.info("Client connected")
     hwsim_utils.test_connectivity_p2p(dev[0], dev[1])
     logger.info("Try to discover a P2P client in a group")
     if not dev[2].discover_peer(dev[1].p2p_dev_addr(), social=False, timeout=10):
+        stop_p2p_find_and_wait(dev[2])
         if not dev[2].discover_peer(dev[1].p2p_dev_addr(), social=False, timeout=10):
+            stop_p2p_find_and_wait(dev[2])
             if not dev[2].discover_peer(dev[1].p2p_dev_addr(), social=False, timeout=10):
                 raise Exception("Could not discover group client")
 
@@ -155,6 +165,56 @@ def test_discovery_group_client(dev):
         if ev is None:
             raise Exception("Timeout on waiting for GO Negotiation Request")
 
+def stop_p2p_find_and_wait(dev):
+    dev.request("P2P_STOP_FIND")
+    for i in range(10):
+        res = dev.get_driver_status_field("scan_state")
+        if "SCAN_STARTED" not in res and "SCAN_REQUESTED" not in res:
+            break
+        logger.debug("Waiting for final P2P_FIND scan to complete")
+        time.sleep(0.02)
+
+def test_discovery_ctrl_char_in_devname(dev):
+    """P2P device discovery and control character in Device Name"""
+    try:
+        _test_discovery_ctrl_char_in_devname(dev)
+    finally:
+        dev[1].global_request("SET device_name Device B")
+
+def _test_discovery_ctrl_char_in_devname(dev):
+    dev[1].global_request("SET device_name Device\tB")
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    res = dev[0].p2p_start_go(freq=2422)
+    bssid = dev[0].p2p_interface_addr()
+    pin = dev[1].wps_read_pin()
+    dev[0].p2p_go_authorize_client(pin)
+    dev[1].scan_for_bss(bssid, freq=2422)
+    dev[1].p2p_connect_group(addr0, pin, timeout=60, freq=2422)
+    if not dev[2].discover_peer(addr1, social=False, freq=2422, timeout=5):
+        stop_p2p_find_and_wait(dev[2])
+        if not dev[2].discover_peer(addr1, social=False, freq=2422, timeout=5):
+            stop_p2p_find_and_wait(dev[2])
+            if not dev[2].discover_peer(addr1, social=False, freq=2422,
+                                        timeout=5):
+                raise Exception("Could not discover group client")
+    devname = dev[2].get_peer(addr1)['device_name']
+    dev[2].p2p_stop_find()
+    if devname != "Device_B":
+        raise Exception("Unexpected device_name from group client: " + devname)
+
+    terminate_group(dev[0], dev[1])
+    dev[2].request("P2P_FLUSH")
+
+    dev[1].p2p_listen()
+    if not dev[2].discover_peer(addr1, social=True, timeout=10):
+        raise Exception("Could not discover peer")
+    devname = dev[2].get_peer(addr1)['device_name']
+    dev[2].p2p_stop_find()
+    if devname != "Device_B":
+        raise Exception("Unexpected device_name from peer: " + devname)
+
+@remote_compatible
 def test_discovery_dev_type(dev):
     """P2P device discovery with Device Type filter"""
     dev[1].request("SET sec_device_type 1-0050F204-2")
@@ -263,8 +323,7 @@ def test_discovery_social_plus_one(dev):
     if dev[1].peer_known(go):
         raise Exception("GO found in social-only scan")
 
-def test_discovery_and_interface_disabled(dev):
-    """P2P device discovery with interface getting didabled"""
+def _test_discovery_and_interface_disabled(dev, delay=1):
     try:
         if "OK" not in dev[0].p2p_find():
             raise Exception("Failed to start P2P find")
@@ -272,7 +331,7 @@ def test_discovery_and_interface_disabled(dev):
         if ev is None:
             raise Exception("Scan did not start")
         dev[0].request("DRIVER_EVENT INTERFACE_DISABLED")
-        time.sleep(1)
+        time.sleep(delay)
 
         # verify that P2P_FIND is rejected
         if "FAIL" not in dev[0].p2p_find():
@@ -291,6 +350,11 @@ def test_discovery_and_interface_disabled(dev):
     finally:
         dev[0].request("DRIVER_EVENT INTERFACE_ENABLED")
 
+def test_discovery_and_interface_disabled(dev):
+    """P2P device discovery with interface getting disabled"""
+    _test_discovery_and_interface_disabled(dev, delay=1)
+    _test_discovery_and_interface_disabled(dev, delay=5)
+
 def test_discovery_auto(dev):
     """P2P device discovery and provision discovery with auto GO/dev selection"""
     dev[0].flush_scan_cache()
@@ -432,6 +496,7 @@ def test_p2p_listen_and_offchannel_tx(dev):
     dev[2].p2p_stop_find()
     dev[0].p2p_stop_find()
 
+@remote_compatible
 def test_p2p_listen_and_scan(dev):
     """P2P_LISTEN and scan"""
     dev[0].p2p_listen()
@@ -475,3 +540,84 @@ def test_p2p_config_methods(dev):
         raise Exception("Unexpected peer config methods(2): " + peer['config_methods'])
 
     wpas.p2p_stop_find()
+
+@remote_compatible
+def test_discovery_after_gas(dev, apdev):
+    """P2P device discovery after GAS/ANQP exchange"""
+    hapd = start_ap(apdev[0])
+    hapd.set("gas_frag_limit", "50")
+    dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412", force_scan=True)
+    dev[0].request("FETCH_ANQP")
+    ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
+    if ev is None:
+        raise Exception("No ANQP-QUERY-DONE event")
+    dev[0].dump_monitor()
+
+    start = os.times()[4]
+    dev[0].p2p_listen()
+    dev[1].p2p_find(social=True)
+    ev = dev[1].wait_global_event(["P2P-DEVICE-FOUND"], timeout=5)
+    if ev is None:
+        raise Exception("Peer not discovered")
+    end = os.times()[4]
+    dev[0].dump_monitor()
+    dev[0].p2p_stop_find()
+    dev[1].p2p_stop_find()
+    logger.info("Device discovery after fragmented GAS took %f seconds" % (end - start))
+    if end - start > 1.3:
+        raise Exception("Device discovery took unexpectedly long time")
+
+@remote_compatible
+def test_discovery_listen_find(dev):
+    """P2P_LISTEN immediately followed by P2P_FIND"""
+    # Request an external remain-on-channel operation to delay start of the ROC
+    # for the following p2p_listen() enough to get p2p_find() processed before
+    # the ROC started event shows up. This is done to test a code path where the
+    # p2p_find() needs to clear the wait for the pending listen operation
+    # (p2p->pending_listen_freq).
+    ifindex = int(dev[0].get_driver_status_field("ifindex"))
+    nl80211_remain_on_channel(dev[0], ifindex, 2417, 200)
+
+    addr0 = dev[0].p2p_dev_addr()
+    dev[0].p2p_listen()
+    dev[0].p2p_find(social=True)
+    time.sleep(0.4)
+    dev[1].p2p_listen()
+    ev = dev[0].wait_global_event(["P2P-DEVICE-FOUND"], timeout=1.2)
+    if not dev[1].discover_peer(addr0):
+        raise Exception("Device discovery timed out")
+    if ev is None:
+        raise Exception("Did not find peer quickly enough after stopped P2P_LISTEN")
+
+def test_discovery_long_listen(dev):
+    """Long P2P_LISTEN and offchannel TX"""
+    addr0 = dev[0].p2p_dev_addr()
+    dev[0].p2p_listen()
+
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    wpas.interface_add("wlan5")
+    addr = wpas.p2p_dev_addr()
+    if not wpas.discover_peer(addr0):
+        raise Exception("Device discovery timed out")
+    peer = wpas.get_peer(addr0)
+    chan = '1' if peer['listen_freq'] == '2462' else '11'
+
+    wpas.request("P2P_SET listen_channel " + chan)
+    wpas.request("P2P_LISTEN 10")
+    if not dev[0].discover_peer(addr):
+        raise Exception("Device discovery timed out (2)")
+
+    time.sleep(0.1)
+    wpas.global_request("P2P_PROV_DISC " + addr0 + " display")
+    ev = dev[0].wait_global_event(["P2P-PROV-DISC-SHOW-PIN"], timeout=15)
+    if ev is None:
+        raise Exception("Provision discovery timed out")
+    dev[0].p2p_stop_find()
+
+    # Verify that the long listen period is still continuing after off-channel
+    # TX of Provision Discovery frames.
+    if not dev[1].discover_peer(addr):
+        raise Exception("Device discovery timed out (3)")
+
+    dev[1].p2p_stop_find()
+    wpas.p2p_stop_find()
index 7385e97..82b7658 100644 (file)
@@ -4,13 +4,15 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 import os
 
 from tshark import run_tshark
-from test_p2p_persistent import form
+from p2p_utils import *
 
+@remote_compatible
 def test_p2p_ext_discovery(dev):
     """P2P device discovery with vendor specific extensions"""
     addr0 = dev[0].p2p_dev_addr()
@@ -71,6 +73,7 @@ def test_p2p_ext_discovery(dev):
     finally:
         dev[0].request("VENDOR_ELEM_REMOVE 1 *")
 
+@remote_compatible
 def test_p2p_ext_discovery_go(dev):
     """P2P device discovery with vendor specific extensions for GO"""
     addr0 = dev[0].p2p_dev_addr()
@@ -333,11 +336,15 @@ def test_p2p_ext_vendor_elem_assoc(dev, apdev, params):
 def _test_p2p_ext_vendor_elem_assoc(dev, apdev, params):
     addr0 = dev[0].p2p_dev_addr()
     addr1 = dev[1].p2p_dev_addr()
+
+    res = dev[0].get_driver_status()
+    p2p_device = True if (int(res['capa.flags'], 0) & 0x20000000) else False
+
     if "OK" not in dev[0].request("VENDOR_ELEM_ADD 11 dd050011223308"):
         raise Exception("VENDOR_ELEM_ADD failed")
     if "OK" not in dev[1].request("VENDOR_ELEM_ADD 12 dd050011223309"):
         raise Exception("VENDOR_ELEM_ADD failed")
-    if "OK" not in dev[0].request("VENDOR_ELEM_ADD 13 dd05001122330a"):
+    if not p2p_device and "OK" not in dev[0].request("VENDOR_ELEM_ADD 13 dd05001122330a"):
         raise Exception("VENDOR_ELEM_ADD failed")
     dev[0].p2p_listen()
     dev[1].p2p_listen()
@@ -352,7 +359,7 @@ def _test_p2p_ext_vendor_elem_assoc(dev, apdev, params):
                      "wlan.fc.type_subtype == 0x00", wait=False)
     if "Vendor Specific Data: 3308" not in out:
         raise Exception("Vendor element (P2P) not found from Association Request frame")
-    if "Vendor Specific Data: 330a" not in out:
+    if not p2p_device and "Vendor Specific Data: 330a" not in out:
         raise Exception("Vendor element (non-P2P) not found from Association Request frame")
 
     out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
index f86637d..9b442d2 100644 (file)
@@ -4,11 +4,12 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
+import binascii
 import logging
 logger = logging.getLogger()
+import struct
 import time
-import threading
-import Queue
 import os
 
 import hostapd
@@ -16,160 +17,10 @@ import hwsim_utils
 import utils
 from utils import HwsimSkip
 from wpasupplicant import WpaSupplicant
+from p2p_utils import *
+from test_p2p_messages import parse_p2p_public_action, p2p_hdr, p2p_attr_capability, p2p_attr_go_intent, p2p_attr_config_timeout, p2p_attr_listen_channel, p2p_attr_intended_interface_addr, p2p_attr_channel_list, p2p_attr_device_info, p2p_attr_operating_channel, ie_p2p, ie_wsc, mgmt_tx, P2P_GO_NEG_REQ
 
-def check_grpform_results(i_res, r_res):
-    if i_res['result'] != 'success' or r_res['result'] != 'success':
-        raise Exception("Failed group formation")
-    if i_res['ssid'] != r_res['ssid']:
-        raise Exception("SSID mismatch")
-    if i_res['freq'] != r_res['freq']:
-        raise Exception("freq mismatch")
-    if 'go_neg_freq' in r_res and i_res['go_neg_freq'] != r_res['go_neg_freq']:
-        raise Exception("go_neg_freq mismatch")
-    if i_res['freq'] != i_res['go_neg_freq']:
-        raise Exception("freq/go_neg_freq mismatch")
-    if i_res['role'] != i_res['go_neg_role']:
-        raise Exception("role/go_neg_role mismatch")
-    if 'go_neg_role' in r_res and r_res['role'] != r_res['go_neg_role']:
-        raise Exception("role/go_neg_role mismatch")
-    if i_res['go_dev_addr'] != r_res['go_dev_addr']:
-        raise Exception("GO Device Address mismatch")
-
-def go_neg_init(i_dev, r_dev, pin, i_method, i_intent, res):
-    logger.debug("Initiate GO Negotiation from i_dev")
-    try:
-        i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), pin, i_method, timeout=20, go_intent=i_intent)
-        logger.debug("i_res: " + str(i_res))
-    except Exception, e:
-        i_res = None
-        logger.info("go_neg_init thread caught an exception from p2p_go_neg_init: " + str(e))
-    res.put(i_res)
-
-def go_neg_pin(i_dev, r_dev, i_intent=None, r_intent=None, i_method='enter', r_method='display'):
-    r_dev.p2p_listen()
-    i_dev.p2p_listen()
-    pin = r_dev.wps_read_pin()
-    logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname)
-    r_dev.dump_monitor()
-    res = Queue.Queue()
-    t = threading.Thread(target=go_neg_init, args=(i_dev, r_dev, pin, i_method, i_intent, res))
-    t.start()
-    logger.debug("Wait for GO Negotiation Request on r_dev")
-    ev = r_dev.wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=15)
-    if ev is None:
-        raise Exception("GO Negotiation timed out")
-    r_dev.dump_monitor()
-    logger.debug("Re-initiate GO Negotiation from r_dev")
-    r_res = r_dev.p2p_go_neg_init(i_dev.p2p_dev_addr(), pin, r_method, go_intent=r_intent, timeout=20)
-    logger.debug("r_res: " + str(r_res))
-    r_dev.dump_monitor()
-    t.join()
-    i_res = res.get()
-    if i_res is None:
-        raise Exception("go_neg_init thread failed")
-    logger.debug("i_res: " + str(i_res))
-    logger.info("Group formed")
-    hwsim_utils.test_connectivity_p2p(r_dev, i_dev)
-    i_dev.dump_monitor()
-    return [i_res, r_res]
-
-def go_neg_pin_authorized(i_dev, r_dev, i_intent=None, r_intent=None, expect_failure=False, i_go_neg_status=None, i_method='enter', r_method='display', test_data=True, i_freq=None, r_freq=None):
-    i_dev.p2p_listen()
-    pin = r_dev.wps_read_pin()
-    logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname)
-    r_dev.p2p_go_neg_auth(i_dev.p2p_dev_addr(), pin, r_method, go_intent=r_intent, freq=r_freq)
-    r_dev.p2p_listen()
-    i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), pin, i_method, timeout=20, go_intent=i_intent, expect_failure=expect_failure, freq=i_freq)
-    r_res = r_dev.p2p_go_neg_auth_result(expect_failure=expect_failure)
-    logger.debug("i_res: " + str(i_res))
-    logger.debug("r_res: " + str(r_res))
-    r_dev.dump_monitor()
-    i_dev.dump_monitor()
-    if i_go_neg_status:
-        if i_res['result'] != 'go-neg-failed':
-            raise Exception("Expected GO Negotiation failure not reported")
-        if i_res['status'] != i_go_neg_status:
-            raise Exception("Expected GO Negotiation status not seen")
-    if expect_failure:
-        return
-    logger.info("Group formed")
-    if test_data:
-        hwsim_utils.test_connectivity_p2p(r_dev, i_dev)
-    return [i_res, r_res]
-
-def go_neg_init_pbc(i_dev, r_dev, i_intent, res, freq, provdisc):
-    logger.debug("Initiate GO Negotiation from i_dev")
-    try:
-        i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), None, "pbc",
-                                      timeout=20, go_intent=i_intent, freq=freq,
-                                      provdisc=provdisc)
-        logger.debug("i_res: " + str(i_res))
-    except Exception, e:
-        i_res = None
-        logger.info("go_neg_init_pbc thread caught an exception from p2p_go_neg_init: " + str(e))
-    res.put(i_res)
-
-def go_neg_pbc(i_dev, r_dev, i_intent=None, r_intent=None, i_freq=None, r_freq=None, provdisc=False, r_listen=False):
-    if r_listen:
-        r_dev.p2p_listen()
-    else:
-        r_dev.p2p_find(social=True)
-    i_dev.p2p_find(social=True)
-    logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname)
-    r_dev.dump_monitor()
-    res = Queue.Queue()
-    t = threading.Thread(target=go_neg_init_pbc, args=(i_dev, r_dev, i_intent, res, i_freq, provdisc))
-    t.start()
-    logger.debug("Wait for GO Negotiation Request on r_dev")
-    ev = r_dev.wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=15)
-    if ev is None:
-        raise Exception("GO Negotiation timed out")
-    r_dev.dump_monitor()
-    # Allow some time for the GO Neg Resp to go out before initializing new
-    # GO Negotiation.
-    time.sleep(0.2)
-    logger.debug("Re-initiate GO Negotiation from r_dev")
-    r_res = r_dev.p2p_go_neg_init(i_dev.p2p_dev_addr(), None, "pbc",
-                                  go_intent=r_intent, timeout=20, freq=r_freq)
-    logger.debug("r_res: " + str(r_res))
-    r_dev.dump_monitor()
-    t.join()
-    i_res = res.get()
-    if i_res is None:
-        raise Exception("go_neg_init_pbc thread failed")
-    logger.debug("i_res: " + str(i_res))
-    logger.info("Group formed")
-    hwsim_utils.test_connectivity_p2p(r_dev, i_dev)
-    i_dev.dump_monitor()
-    return [i_res, r_res]
-
-def go_neg_pbc_authorized(i_dev, r_dev, i_intent=None, r_intent=None,
-                          expect_failure=False, i_freq=None, r_freq=None):
-    i_dev.p2p_listen()
-    logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname)
-    r_dev.p2p_go_neg_auth(i_dev.p2p_dev_addr(), None, "pbc",
-                          go_intent=r_intent, freq=r_freq)
-    r_dev.p2p_listen()
-    i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), None, "pbc", timeout=20,
-                                  go_intent=i_intent,
-                                  expect_failure=expect_failure, freq=i_freq)
-    r_res = r_dev.p2p_go_neg_auth_result(expect_failure=expect_failure)
-    logger.debug("i_res: " + str(i_res))
-    logger.debug("r_res: " + str(r_res))
-    r_dev.dump_monitor()
-    i_dev.dump_monitor()
-    if expect_failure:
-        return
-    logger.info("Group formed")
-    return [i_res, r_res]
-
-def remove_group(dev1, dev2):
-    dev1.remove_group()
-    try:
-        dev2.remove_group()
-    except:
-        pass
-
+@remote_compatible
 def test_grpform(dev):
     """P2P group formation using PIN and authorized connection (init -> GO)"""
     try:
@@ -206,6 +57,15 @@ def test_grpform_b(dev):
     if "p2p-wlan" not in r_res['ifname']:
         raise Exception("Unexpected group interface name")
     check_grpform_results(i_res, r_res)
+    addr = dev[0].group_request("P2P_GROUP_MEMBER " + dev[1].p2p_dev_addr())
+    if "FAIL" in addr:
+        raise Exception("P2P_GROUP_MEMBER failed")
+    if addr != dev[1].p2p_interface_addr():
+        raise Exception("Unexpected P2P_GROUP_MEMBER result: " + addr)
+    if "FAIL" not in dev[0].group_request("P2P_GROUP_MEMBER a"):
+        raise Exception("Invalid P2P_GROUP_MEMBER command accepted")
+    if "FAIL" not in dev[0].group_request("P2P_GROUP_MEMBER 00:11:22:33:44:55"):
+        raise Exception("P2P_GROUP_MEMBER for non-member accepted")
     remove_group(dev[0], dev[1])
     if r_res['ifname'] in utils.get_ifnames():
         raise Exception("Group interface netdev was not removed")
@@ -227,6 +87,7 @@ def test_grpform_c(dev):
     if r_res['ifname'] in utils.get_ifnames():
         raise Exception("Group interface netdev was not removed")
 
+@remote_compatible
 def test_grpform2(dev):
     """P2P group formation using PIN and authorized connection (resp -> GO)"""
     go_neg_pin_authorized(i_dev=dev[0], i_intent=0, r_dev=dev[1], r_intent=15)
@@ -243,6 +104,7 @@ def test_grpform2_c(dev):
     if r_res['ifname'] in utils.get_ifnames():
         raise Exception("Group interface netdev was not removed")
 
+@remote_compatible
 def test_grpform3(dev):
     """P2P group formation using PIN and re-init GO Negotiation"""
     go_neg_pin(i_dev=dev[0], i_intent=15, r_dev=dev[1], r_intent=0)
@@ -259,6 +121,7 @@ def test_grpform3_c(dev):
     if r_res['ifname'] in utils.get_ifnames():
         raise Exception("Group interface netdev was not removed")
 
+@remote_compatible
 def test_grpform4(dev):
     """P2P group formation response during p2p_find"""
     addr1 = dev[1].p2p_dev_addr()
@@ -274,6 +137,7 @@ def test_grpform4(dev):
     dev[1].p2p_stop_find()
     dev[0].p2p_stop_find()
 
+@remote_compatible
 def test_grpform_pbc(dev):
     """P2P group formation using PBC and re-init GO Negotiation"""
     [i_res, r_res] = go_neg_pbc(i_dev=dev[0], i_intent=15, r_dev=dev[1], r_intent=0)
@@ -282,6 +146,7 @@ def test_grpform_pbc(dev):
         raise Exception("Unexpected device roles")
     remove_group(dev[0], dev[1])
 
+@remote_compatible
 def test_grpform_pd(dev):
     """P2P group formation with PD-before-GO-Neg workaround"""
     [i_res, r_res] = go_neg_pbc(i_dev=dev[0], provdisc=True, r_dev=dev[1], r_listen=True)
@@ -378,18 +243,22 @@ def _test_grpform_ext_listen_oper(dev):
     if not found:
         raise Exception("Could not discover peer that was supposed to use extended listen")
 
+@remote_compatible
 def test_both_go_intent_15(dev):
     """P2P GO Negotiation with both devices using GO intent 15"""
     go_neg_pin_authorized(i_dev=dev[0], i_intent=15, r_dev=dev[1], r_intent=15, expect_failure=True, i_go_neg_status=9)
 
+@remote_compatible
 def test_both_go_neg_display(dev):
     """P2P GO Negotiation with both devices trying to display PIN"""
     go_neg_pin_authorized(i_dev=dev[0], r_dev=dev[1], expect_failure=True, i_go_neg_status=10, i_method='display', r_method='display')
 
+@remote_compatible
 def test_both_go_neg_enter(dev):
     """P2P GO Negotiation with both devices trying to enter PIN"""
     go_neg_pin_authorized(i_dev=dev[0], r_dev=dev[1], expect_failure=True, i_go_neg_status=10, i_method='enter', r_method='enter')
 
+@remote_compatible
 def test_go_neg_pbc_vs_pin(dev):
     """P2P GO Negotiation with one device using PBC and the other PIN"""
     addr0 = dev[0].p2p_dev_addr()
@@ -410,6 +279,7 @@ def test_go_neg_pbc_vs_pin(dev):
     if "status=10" not in ev:
         raise Exception("Unexpected failure reason: " + ev)
 
+@remote_compatible
 def test_go_neg_pin_vs_pbc(dev):
     """P2P GO Negotiation with one device using PIN and the other PBC"""
     addr0 = dev[0].p2p_dev_addr()
@@ -466,6 +336,7 @@ def test_grpform_per_sta_psk_wps(dev):
     dev[2].request("DISCONNECT")
     dev[1].wait_go_ending_session()
 
+@remote_compatible
 def test_grpform_force_chan_go(dev):
     """P2P group formation forced channel selection by GO"""
     [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
@@ -477,6 +348,7 @@ def test_grpform_force_chan_go(dev):
         raise Exception("Unexpected channel - did not follow GO's forced channel")
     remove_group(dev[0], dev[1])
 
+@remote_compatible
 def test_grpform_force_chan_cli(dev):
     """P2P group formation forced channel selection by client"""
     [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=0,
@@ -488,53 +360,71 @@ def test_grpform_force_chan_cli(dev):
         raise Exception("Unexpected channel - did not follow GO's forced channel")
     remove_group(dev[0], dev[1])
 
+@remote_compatible
 def test_grpform_force_chan_conflict(dev):
     """P2P group formation fails due to forced channel mismatch"""
     go_neg_pin_authorized(i_dev=dev[0], i_intent=0, i_freq=2422,
                           r_dev=dev[1], r_intent=15, r_freq=2427,
                           expect_failure=True, i_go_neg_status=7)
 
+@remote_compatible
 def test_grpform_pref_chan_go(dev):
     """P2P group formation preferred channel selection by GO"""
-    dev[0].request("SET p2p_pref_chan 81:7")
-    [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
-                                           r_dev=dev[1], r_intent=0,
-                                           test_data=False)
-    check_grpform_results(i_res, r_res)
-    if i_res['freq'] != "2442":
-        raise Exception("Unexpected channel - did not follow GO's p2p_pref_chan")
-    remove_group(dev[0], dev[1])
+    try:
+        dev[0].request("SET p2p_pref_chan 81:7")
+        [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
+                                               r_dev=dev[1], r_intent=0,
+                                               test_data=False)
+        check_grpform_results(i_res, r_res)
+        if i_res['freq'] != "2442":
+            raise Exception("Unexpected channel - did not follow GO's p2p_pref_chan")
+        remove_group(dev[0], dev[1])
+    finally:
+        dev[0].request("SET p2p_pref_chan ")
 
+@remote_compatible
 def test_grpform_pref_chan_go_overridden(dev):
     """P2P group formation preferred channel selection by GO overridden by client"""
-    dev[1].request("SET p2p_pref_chan 81:7")
-    [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=0,
-                                           i_freq=2422,
-                                           r_dev=dev[1], r_intent=15,
-                                           test_data=False)
-    check_grpform_results(i_res, r_res)
-    if i_res['freq'] != "2422":
-        raise Exception("Unexpected channel - did not follow client's forced channel")
-    remove_group(dev[0], dev[1])
+    try:
+        dev[1].request("SET p2p_pref_chan 81:7")
+        [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=0,
+                                               i_freq=2422,
+                                               r_dev=dev[1], r_intent=15,
+                                               test_data=False)
+        check_grpform_results(i_res, r_res)
+        if i_res['freq'] != "2422":
+            raise Exception("Unexpected channel - did not follow client's forced channel")
+        remove_group(dev[0], dev[1])
+    finally:
+        dev[1].request("SET p2p_pref_chan ")
 
+@remote_compatible
 def test_grpform_no_go_freq_forcing_chan(dev):
     """P2P group formation with no-GO freq forcing channel"""
-    dev[1].request("SET p2p_no_go_freq 100-200,300,4000-6000")
-    [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=0,
-                                           r_dev=dev[1], r_intent=15,
-                                           test_data=False)
-    check_grpform_results(i_res, r_res)
-    if int(i_res['freq']) > 4000:
-        raise Exception("Unexpected channel - did not follow no-GO freq")
-    remove_group(dev[0], dev[1])
+    try:
+        dev[1].request("SET p2p_no_go_freq 100-200,300,4000-6000")
+        [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=0,
+                                               r_dev=dev[1], r_intent=15,
+                                               test_data=False)
+        check_grpform_results(i_res, r_res)
+        if int(i_res['freq']) > 4000:
+            raise Exception("Unexpected channel - did not follow no-GO freq")
+        remove_group(dev[0], dev[1])
+    finally:
+        dev[1].request("SET p2p_no_go_freq ")
 
+@remote_compatible
 def test_grpform_no_go_freq_conflict(dev):
     """P2P group formation fails due to no-GO range forced by client"""
-    dev[1].request("SET p2p_no_go_freq 2000-3000")
-    go_neg_pin_authorized(i_dev=dev[0], i_intent=0, i_freq=2422,
-                          r_dev=dev[1], r_intent=15,
-                          expect_failure=True, i_go_neg_status=7)
+    try:
+        dev[1].request("SET p2p_no_go_freq 2000-3000")
+        go_neg_pin_authorized(i_dev=dev[0], i_intent=0, i_freq=2422,
+                              r_dev=dev[1], r_intent=15,
+                              expect_failure=True, i_go_neg_status=7)
+    finally:
+        dev[1].request("SET p2p_no_go_freq ")
 
+@remote_compatible
 def test_grpform_no_5ghz_world_roaming(dev):
     """P2P group formation with world roaming regulatory"""
     [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=0,
@@ -545,54 +435,75 @@ def test_grpform_no_5ghz_world_roaming(dev):
         raise Exception("Unexpected channel - did not follow world roaming rules")
     remove_group(dev[0], dev[1])
 
+@remote_compatible
 def test_grpform_no_5ghz_add_cli(dev):
     """P2P group formation with passive scan 5 GHz and p2p_add_cli_chan=1"""
-    dev[0].request("SET p2p_add_cli_chan 1")
-    dev[1].request("SET p2p_add_cli_chan 1")
-    [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=0,
-                                           r_dev=dev[1], r_intent=14,
-                                           test_data=False)
-    check_grpform_results(i_res, r_res)
-    if int(i_res['freq']) > 4000:
-        raise Exception("Unexpected channel - did not follow world roaming rules")
-    remove_group(dev[0], dev[1])
+    try:
+        dev[0].request("SET p2p_add_cli_chan 1")
+        dev[1].request("SET p2p_add_cli_chan 1")
+        [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=0,
+                                               r_dev=dev[1], r_intent=14,
+                                               test_data=False)
+        check_grpform_results(i_res, r_res)
+        if int(i_res['freq']) > 4000:
+            raise Exception("Unexpected channel - did not follow world roaming rules")
+        remove_group(dev[0], dev[1])
+    finally:
+        dev[0].request("SET p2p_add_cli_chan 0")
+        dev[1].request("SET p2p_add_cli_chan 0")
 
+@remote_compatible
 def test_grpform_no_5ghz_add_cli2(dev):
     """P2P group formation with passive scan 5 GHz and p2p_add_cli_chan=1 (reverse)"""
-    dev[0].request("SET p2p_add_cli_chan 1")
-    dev[1].request("SET p2p_add_cli_chan 1")
-    [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=14,
-                                           r_dev=dev[1], r_intent=0,
-                                           test_data=False)
-    check_grpform_results(i_res, r_res)
-    if int(i_res['freq']) > 4000:
-        raise Exception("Unexpected channel - did not follow world roaming rules")
-    remove_group(dev[0], dev[1])
+    try:
+        dev[0].request("SET p2p_add_cli_chan 1")
+        dev[1].request("SET p2p_add_cli_chan 1")
+        [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=14,
+                                               r_dev=dev[1], r_intent=0,
+                                               test_data=False)
+        check_grpform_results(i_res, r_res)
+        if int(i_res['freq']) > 4000:
+            raise Exception("Unexpected channel - did not follow world roaming rules")
+        remove_group(dev[0], dev[1])
+    finally:
+        dev[0].request("SET p2p_add_cli_chan 0")
+        dev[1].request("SET p2p_add_cli_chan 0")
 
+@remote_compatible
 def test_grpform_no_5ghz_add_cli3(dev):
     """P2P group formation with passive scan 5 GHz and p2p_add_cli_chan=1 (intent 15)"""
-    dev[0].request("SET p2p_add_cli_chan 1")
-    dev[1].request("SET p2p_add_cli_chan 1")
-    [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=0,
-                                           r_dev=dev[1], r_intent=15,
-                                           test_data=False)
-    check_grpform_results(i_res, r_res)
-    if int(i_res['freq']) > 4000:
-        raise Exception("Unexpected channel - did not follow world roaming rules")
-    remove_group(dev[0], dev[1])
+    try:
+        dev[0].request("SET p2p_add_cli_chan 1")
+        dev[1].request("SET p2p_add_cli_chan 1")
+        [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=0,
+                                               r_dev=dev[1], r_intent=15,
+                                               test_data=False)
+        check_grpform_results(i_res, r_res)
+        if int(i_res['freq']) > 4000:
+            raise Exception("Unexpected channel - did not follow world roaming rules")
+        remove_group(dev[0], dev[1])
+    finally:
+        dev[0].request("SET p2p_add_cli_chan 0")
+        dev[1].request("SET p2p_add_cli_chan 0")
 
+@remote_compatible
 def test_grpform_no_5ghz_add_cli4(dev):
     """P2P group formation with passive scan 5 GHz and p2p_add_cli_chan=1 (reverse; intent 15)"""
-    dev[0].request("SET p2p_add_cli_chan 1")
-    dev[1].request("SET p2p_add_cli_chan 1")
-    [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
-                                           r_dev=dev[1], r_intent=0,
-                                           test_data=False)
-    check_grpform_results(i_res, r_res)
-    if int(i_res['freq']) > 4000:
-        raise Exception("Unexpected channel - did not follow world roaming rules")
-    remove_group(dev[0], dev[1])
+    try:
+        dev[0].request("SET p2p_add_cli_chan 1")
+        dev[1].request("SET p2p_add_cli_chan 1")
+        [i_res, r_res] = go_neg_pin_authorized(i_dev=dev[0], i_intent=15,
+                                               r_dev=dev[1], r_intent=0,
+                                               test_data=False)
+        check_grpform_results(i_res, r_res)
+        if int(i_res['freq']) > 4000:
+            raise Exception("Unexpected channel - did not follow world roaming rules")
+        remove_group(dev[0], dev[1])
+    finally:
+        dev[0].request("SET p2p_add_cli_chan 0")
+        dev[1].request("SET p2p_add_cli_chan 0")
 
+@remote_compatible
 def test_grpform_incorrect_pin(dev):
     """P2P GO Negotiation with incorrect PIN"""
     dev[1].p2p_listen()
@@ -627,6 +538,7 @@ def test_grpform_incorrect_pin(dev):
     if ev is None:
         raise Exception("Group formation failure timed out")
 
+@remote_compatible
 def test_grpform_reject(dev):
     """User rejecting group formation attempt by a P2P peer"""
     addr0 = dev[0].p2p_dev_addr()
@@ -641,12 +553,13 @@ def test_grpform_reject(dev):
         raise Exception("P2P_REJECT failed")
     dev[1].request("P2P_STOP_FIND")
     dev[1].p2p_go_neg_init(addr0, None, "pbc")
-    ev = dev[1].wait_global_event(["GO-NEG-FAILURE"], timeout=10)
+    ev = dev[1].wait_global_event(["P2P-GO-NEG-FAILURE"], timeout=10)
     if ev is None:
         raise Exception("Rejection not reported")
     if "status=11" not in ev:
         raise Exception("Unexpected status code in rejection")
 
+@remote_compatible
 def test_grpform_pd_no_probe_resp(dev):
     """GO Negotiation after PD, but no Probe Response"""
     addr0 = dev[0].p2p_dev_addr()
@@ -713,15 +626,14 @@ def test_go_neg_two_peers(dev):
     if ev is None:
         raise Exception("timeout on GO Neg RX event")
     dev[2].request("P2P_CONNECT " + addr0 + " pbc")
-    ev = dev[2].wait_global_event(["GO-NEG-FAILURE"], timeout=10)
+    ev = dev[2].wait_global_event(["P2P-GO-NEG-FAILURE"], timeout=10)
     if ev is None:
         raise Exception("Rejection not reported")
     if "status=5" not in ev:
         raise Exception("Unexpected status code in rejection: " + ev)
 
-def clear_pbc_overlap(dev, ifname):
-    hapd_global = hostapd.HostapdGlobal()
-    hapd_global.remove(ifname)
+def clear_pbc_overlap(dev, ap):
+    hostapd.remove_bss(ap)
     dev[0].request("P2P_CANCEL")
     dev[1].request("P2P_CANCEL")
     dev[0].p2p_stop_find()
@@ -733,10 +645,11 @@ def clear_pbc_overlap(dev, ifname):
     dev[1].flush_scan_cache()
     time.sleep(0.1)
 
+@remote_compatible
 def test_grpform_pbc_overlap(dev, apdev):
     """P2P group formation during PBC overlap"""
     params = { "ssid": "wps", "eap_server": "1", "wps_state": "1" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     hapd.request("WPS_PBC")
     time.sleep(0.1)
 
@@ -768,15 +681,16 @@ def test_grpform_pbc_overlap(dev, apdev):
     if ev is None:
         raise Exception("PBC overlap not reported")
 
-    clear_pbc_overlap(dev, apdev[0]['ifname'])
+    clear_pbc_overlap(dev, apdev[0])
 
+@remote_compatible
 def test_grpform_pbc_overlap_group_iface(dev, apdev):
     """P2P group formation during PBC overlap using group interfaces"""
     # Note: Need to include P2P IE from the AP to get the P2P interface BSS
     # update use this information.
     params = { "ssid": "wps", "eap_server": "1", "wps_state": "1",
                "beacon_int": "15", 'manage_p2p': '1' }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     hapd.request("WPS_PBC")
 
     dev[0].request("SET p2p_no_group_iface 0")
@@ -806,8 +720,9 @@ def test_grpform_pbc_overlap_group_iface(dev, apdev):
         # the group interface.
         logger.info("PBC overlap not reported")
 
-    clear_pbc_overlap(dev, apdev[0]['ifname'])
+    clear_pbc_overlap(dev, apdev[0])
 
+@remote_compatible
 def test_grpform_goneg_fail_with_group_iface(dev):
     """P2P group formation fails while using group interface"""
     dev[0].request("SET p2p_no_group_iface 0")
@@ -933,6 +848,7 @@ def test_grpform_no_wsc_done(dev):
         if mode != "P2P GO - group formation":
             raise Exception("Unexpected mode on GO during group formation: " + mode)
 
+@remote_compatible
 def test_grpform_wait_peer(dev):
     """P2P group formation wait for peer to become ready"""
     addr0 = dev[0].p2p_dev_addr()
@@ -957,6 +873,7 @@ def test_grpform_wait_peer(dev):
         raise Exception("Group formation timed out")
     dev[0].remove_group()
 
+@remote_compatible
 def test_invalid_p2p_connect_command(dev):
     """P2P_CONNECT error cases"""
     id = dev[0].add_network()
@@ -979,6 +896,7 @@ def test_invalid_p2p_connect_command(dev):
     if "FAIL-CHANNEL-UNSUPPORTED" not in dev[0].request("P2P_CONNECT 00:11:22:33:44:55 pin freq=3000"):
         raise Exception("Unsupported channel not reported")
 
+@remote_compatible
 def test_p2p_unauthorize(dev):
     """P2P_UNAUTHORIZE to unauthorize a peer"""
     if "FAIL" not in dev[0].request("P2P_UNAUTHORIZE foo"):
@@ -999,6 +917,7 @@ def test_p2p_unauthorize(dev):
     if ev is None:
         raise Exception("No GO Negotiation Request RX reported")
 
+@remote_compatible
 def test_grpform_pbc_multiple(dev):
     """P2P group formation using PBC multiple times in a row"""
     try:
@@ -1050,3 +969,195 @@ def test_grpform_not_ready2(dev):
         raise Exception("Unexpected peer discovered: " + ev)
     for i in range(3):
         dev[i].p2p_stop_find()
+
+@remote_compatible
+def test_grpform_and_scan(dev):
+    """GO Negotiation and scan operations"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+    dev[1].p2p_listen()
+    if not dev[0].discover_peer(addr1):
+        raise Exception("Could not discover peer")
+    dev[0].p2p_stop_find()
+    dev[1].p2p_stop_find()
+
+    if "OK" not in dev[0].request("SCAN TYPE=ONLY freq=2412-2472"):
+        raise Exception("Could not start scan")
+    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=5)
+    if ev is None:
+        raise Exception("Scan did not start")
+    time.sleep(0.1)
+    # Request PD while the previously started scan is still in progress
+    if "OK" not in dev[0].request("P2P_PROV_DISC %s pbc" % addr1):
+        raise Exception("Could not request PD")
+    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10)
+    if ev is None:
+        raise Exception("Scan did not complete")
+    time.sleep(0.3)
+
+    dev[1].p2p_listen()
+    ev = dev[0].wait_global_event(["P2P-PROV-DISC-PBC-RESP"], timeout=5)
+    if ev is None:
+        raise Exception("PD Response not received")
+
+    if "OK" not in dev[0].request("SCAN TYPE=ONLY freq=2412-2472"):
+        raise Exception("Could not start scan")
+    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=5)
+    if ev is None:
+        raise Exception("Scan did not start")
+    time.sleep(0.1)
+    # Request GO Neg while the previously started scan is still in progress
+    if "OK" not in dev[0].request("P2P_CONNECT %s pbc" % addr1):
+        raise Exception("Could not request GO Negotiation")
+    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10)
+    if ev is None:
+        raise Exception("Scan did not complete")
+
+    ev = dev[1].wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=10)
+    if ev is None:
+        raise Exception("GO Neg Req RX not reported")
+
+    dev[1].p2p_stop_find()
+
+    if "OK" not in dev[1].request("SCAN TYPE=ONLY freq=2412-2472"):
+        raise Exception("Could not start scan")
+    ev = dev[1].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=5)
+    if ev is None:
+        raise Exception("Scan did not start")
+    time.sleep(0.1)
+    dev[1].global_request("P2P_CONNECT " + addr0 + " pbc")
+    ev = dev[1].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10)
+    if ev is None:
+        raise Exception("Scan did not complete")
+
+    ev0 = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
+    if ev0 is None:
+        raise Exception("Group formation timed out on dev0")
+    dev[0].group_form_result(ev0)
+
+    ev1 = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
+    if ev1 is None:
+        raise Exception("Group formation timed out on dev1")
+    dev[1].group_form_result(ev1)
+
+    dev[0].dump_monitor()
+    dev[1].dump_monitor()
+
+    remove_group(dev[0], dev[1])
+
+    dev[0].dump_monitor()
+    dev[1].dump_monitor()
+
+def test_grpform_go_neg_dup_on_restart(dev):
+    """Duplicated GO Negotiation Request after GO Neg restart"""
+    if dev[0].p2p_dev_addr() > dev[1].p2p_dev_addr():
+        higher = dev[0]
+        lower = dev[1]
+    else:
+        higher = dev[1]
+        lower = dev[0]
+    addr_low = lower.p2p_dev_addr()
+    addr_high = higher.p2p_dev_addr()
+    higher.p2p_listen()
+    if not lower.discover_peer(addr_high):
+        raise Exception("Could not discover peer")
+    lower.p2p_stop_find()
+
+    if "OK" not in lower.request("P2P_CONNECT %s pbc" % addr_high):
+        raise Exception("Could not request GO Negotiation")
+    ev = higher.wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=10)
+    if ev is None:
+        raise Exception("GO Neg Req RX not reported")
+
+    # Wait for GO Negotiation Response (Status=1) to go through
+    time.sleep(0.2)
+
+    if "FAIL" in lower.request("SET ext_mgmt_frame_handling 1"):
+        raise Exception("Failed to enable external management frame handling")
+
+    higher.p2p_stop_find()
+    higher.global_request("P2P_CONNECT " + addr_low + " pbc")
+
+    # Wait for the GO Negotiation Request frame of the restarted GO Negotiation
+    rx_msg = lower.mgmt_rx()
+    if rx_msg is None:
+        raise Exception("MGMT-RX timeout")
+    p2p = parse_p2p_public_action(rx_msg['payload'])
+    if p2p is None:
+        raise Exception("Not a P2P Public Action frame")
+    if p2p['subtype'] != 0:
+        raise Exception("Unexpected P2P Public Action subtype %d" % p2p['subtype'])
+
+    # Send duplicate GO Negotiation Request from the prior instance of GO
+    # Negotiation
+    lower.p2p_stop_find()
+    peer = higher.get_peer(addr_low)
+
+    msg = p2p_hdr(addr_high, addr_low, type=P2P_GO_NEG_REQ, dialog_token=123)
+    attrs = p2p_attr_capability(dev_capab=0x25, group_capab=0x08)
+    attrs += p2p_attr_go_intent(go_intent=7, tie_breaker=1)
+    attrs += p2p_attr_config_timeout()
+    attrs += p2p_attr_listen_channel(chan=(int(peer['listen_freq']) - 2407) / 5)
+    attrs += p2p_attr_intended_interface_addr(lower.p2p_dev_addr())
+    attrs += p2p_attr_channel_list()
+    attrs += p2p_attr_device_info(addr_low, config_methods=0x80, name="Device A")
+    attrs += p2p_attr_operating_channel()
+    wsc_attrs = struct.pack(">HHH", 0x1012, 2, 4)
+    msg['payload'] += ie_p2p(attrs) + ie_wsc(wsc_attrs)
+    mgmt_tx(lower, "MGMT_TX {} {} freq={} wait_time=200 no_cck=1 action={}".format(addr_high, addr_high, peer['listen_freq'], binascii.hexlify(msg['payload'])))
+
+    # Wait for the GO Negotiation Response frame which would have been sent in
+    # this case previously, but not anymore after the check for
+    # dev->go_neg_req_sent and dev->flags & P2P_DEV_PEER_WAITING_RESPONSE.
+    rx_msg = lower.mgmt_rx(timeout=0.2)
+    if rx_msg is not None:
+        raise Exception("Unexpected management frame")
+
+    if "FAIL" in lower.request("SET ext_mgmt_frame_handling 0"):
+        raise Exception("Failed to disable external management frame handling")
+    lower.p2p_listen()
+
+    ev = lower.wait_global_event(["P2P-GO-NEG-SUCCESS"], timeout=10)
+    if ev is None:
+        raise Exception("GO Negotiation did not succeed on dev0")
+
+    ev = higher.wait_global_event(["P2P-GO-NEG-SUCCESS"], timeout=10)
+    if ev is None:
+        raise Exception("GO Negotiation did not succeed on dev1")
+
+    ev0 = lower.wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
+    if ev0 is None:
+        raise Exception("Group formation timed out on dev0")
+    lower.group_form_result(ev0)
+
+    ev1 = higher.wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
+    if ev1 is None:
+        raise Exception("Group formation timed out on dev1")
+    higher.group_form_result(ev1)
+
+    lower.dump_monitor()
+    higher.dump_monitor()
+
+    remove_group(lower, higher)
+
+    lower.dump_monitor()
+    higher.dump_monitor()
+
+@remote_compatible
+def test_grpform_go_neg_stopped(dev):
+    """GO Negotiation stopped after TX start"""
+    addr0 = dev[0].p2p_dev_addr()
+    dev[0].p2p_listen()
+    if not dev[1].discover_peer(addr0):
+        raise Exception("Could not discover peer")
+    dev[0].p2p_stop_find()
+    if "OK" not in dev[1].request("P2P_CONNECT %s pbc" % addr0):
+        raise Exception("Could not request GO Negotiation")
+    dev[1].p2p_stop_find()
+    dev[1].p2p_listen()
+    dev[0].p2p_find(social=True)
+    ev = dev[0].wait_global_event(["P2P-DEVICE-FOUND"], timeout=1.2)
+    dev[0].p2p_stop_find()
+    dev[1].p2p_stop_find()
+    if ev is None:
+        raise Exception("Did not find peer quickly enough after stopped P2P_CONNECT")
index ffe8437..e3e9c02 100644 (file)
@@ -4,11 +4,13 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 
 import hwsim_utils
 
+@remote_compatible
 def test_p2p_go_invite(dev):
     """P2P GO inviting a client to join"""
     addr0 = dev[0].p2p_dev_addr()
@@ -53,6 +55,7 @@ def test_p2p_go_invite(dev):
     dev[0].remove_group()
     dev[1].wait_go_ending_session()
 
+@remote_compatible
 def test_p2p_go_invite_auth(dev):
     """P2P GO inviting a client to join (authorized invitation)"""
     addr0 = dev[0].p2p_dev_addr()
@@ -104,6 +107,7 @@ def test_p2p_go_invite_auth(dev):
     dev[0].remove_group()
     dev[1].wait_go_ending_session()
 
+@remote_compatible
 def test_p2p_go_invite_unknown(dev):
     """P2P GO inviting a client that has not discovered the GO"""
     try:
@@ -176,6 +180,7 @@ def test_p2p_cli_invite(dev):
     dev[1].wait_go_ending_session()
     dev[2].wait_go_ending_session()
 
+@remote_compatible
 def test_p2p_invite_invalid(dev):
     """Invalid parameters to P2P_INVITE"""
     id = dev[0].add_network()
index 19d551b..0def528 100644 (file)
@@ -1,9 +1,10 @@
 # P2P protocol tests for various messages
-# Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
 #
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import binascii
 import struct
 import time
@@ -11,71 +12,8 @@ import logging
 logger = logging.getLogger()
 
 import hostapd
-from test_p2p_persistent import form
-from test_p2p_persistent import invite
-
-MGMT_SUBTYPE_PROBE_REQ = 4
-MGMT_SUBTYPE_ACTION = 13
-ACTION_CATEG_PUBLIC = 4
-
-P2P_GO_NEG_REQ = 0
-P2P_GO_NEG_RESP = 1
-P2P_GO_NEG_CONF = 2
-P2P_INVITATION_REQ = 3
-P2P_INVITATION_RESP = 4
-P2P_DEV_DISC_REQ = 5
-P2P_DEV_DISC_RESP = 6
-P2P_PROV_DISC_REQ = 7
-P2P_PROV_DISC_RESP = 8
-
-P2P_ATTR_STATUS = 0
-P2P_ATTR_MINOR_REASON_CODE = 1
-P2P_ATTR_CAPABILITY = 2
-P2P_ATTR_DEVICE_ID = 3
-P2P_ATTR_GROUP_OWNER_INTENT = 4
-P2P_ATTR_CONFIGURATION_TIMEOUT = 5
-P2P_ATTR_LISTEN_CHANNEL = 6
-P2P_ATTR_GROUP_BSSID = 7
-P2P_ATTR_EXT_LISTEN_TIMING = 8
-P2P_ATTR_INTENDED_INTERFACE_ADDR = 9
-P2P_ATTR_MANAGEABILITY = 10
-P2P_ATTR_CHANNEL_LIST = 11
-P2P_ATTR_NOTICE_OF_ABSENCE = 12
-P2P_ATTR_DEVICE_INFO = 13
-P2P_ATTR_GROUP_INFO = 14
-P2P_ATTR_GROUP_ID = 15
-P2P_ATTR_INTERFACE = 16
-P2P_ATTR_OPERATING_CHANNEL = 17
-P2P_ATTR_INVITATION_FLAGS = 18
-P2P_ATTR_OOB_GO_NEG_CHANNEL = 19
-P2P_ATTR_SERVICE_HASH = 21
-P2P_ATTR_SESSION_INFORMATION_DATA = 22
-P2P_ATTR_CONNECTION_CAPABILITY = 23
-P2P_ATTR_ADVERTISEMENT_ID = 24
-P2P_ATTR_ADVERTISED_SERVICE = 25
-P2P_ATTR_SESSION_ID = 26
-P2P_ATTR_FEATURE_CAPABILITY = 27
-P2P_ATTR_PERSISTENT_GROUP = 28
-P2P_ATTR_VENDOR_SPECIFIC = 221
-
-P2P_SC_SUCCESS = 0
-P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE = 1
-P2P_SC_FAIL_INCOMPATIBLE_PARAMS = 2
-P2P_SC_FAIL_LIMIT_REACHED = 3
-P2P_SC_FAIL_INVALID_PARAMS = 4
-P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE = 5
-P2P_SC_FAIL_PREV_PROTOCOL_ERROR = 6
-P2P_SC_FAIL_NO_COMMON_CHANNELS = 7
-P2P_SC_FAIL_UNKNOWN_GROUP = 8
-P2P_SC_FAIL_BOTH_GO_INTENT_15 = 9
-P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10
-P2P_SC_FAIL_REJECTED_BY_USER = 11
-
-WSC_ATTR_CONFIG_METHODS = 0x1008
-
-WLAN_EID_SSID = 0
-WLAN_EID_SUPP_RATES = 1
-WLAN_EID_VENDOR_SPECIFIC = 221
+from p2p_utils import *
+from test_gas import anqp_adv_proto
 
 def ie_ssid(ssid):
     return struct.pack("<BB", WLAN_EID_SSID, len(ssid)) + ssid
@@ -145,8 +83,9 @@ def p2p_attr_channel_list():
 def p2p_attr_device_info(addr, name="Test", config_methods=0, dev_type="00010050F2040001"):
     val = struct.unpack('6B', binascii.unhexlify(addr.replace(':','')))
     val2 = struct.unpack('8B', binascii.unhexlify(dev_type))
-    t = (P2P_ATTR_DEVICE_INFO, 6 + 2 + 8 + 1 + 4 + len(name)) + val + (config_methods,) + val2 + (0,)
-    return struct.pack("<BH6BH8BB", *t) + struct.pack('>HH', 0x1011, len(name)) +name
+    t = (P2P_ATTR_DEVICE_INFO, 6 + 2 + 8 + 1 + 4 + len(name)) + val
+    t2 = val2 + (0,)
+    return struct.pack("<BH6B", *t) + struct.pack(">H", config_methods) + struct.pack("8BB", *t2) + struct.pack('>HH', 0x1011, len(name)) +name
 
 def p2p_attr_group_id(addr, ssid):
     val = struct.unpack('6B', binascii.unhexlify(addr.replace(':','')))
@@ -201,7 +140,7 @@ def start_p2p(dev, apdev):
         params['channel'] = '6'
     elif peer['listen_freq'] == "2462":
         params['channel'] = '11'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     hapd.set("ext_mgmt_frame_handling", "1")
     return addr0, bssid, hapd, int(params['channel'])
 
@@ -281,12 +220,14 @@ def parse_p2p_public_action(payload):
 
     return p2p
 
+@remote_compatible
 def test_p2p_msg_empty(dev, apdev):
     """P2P protocol test: empty P2P Public Action frame"""
     dst, src, hapd, channel = start_p2p(dev, apdev)
     msg = p2p_hdr(dst, src)
     hapd.mgmt_tx(msg)
 
+@remote_compatible
 def test_p2p_msg_long_ssid(dev, apdev):
     """P2P protocol test: Too long SSID in P2P Public Action frame"""
     dst, src, hapd, channel = start_p2p(dev, apdev)
@@ -302,10 +243,11 @@ def test_p2p_msg_long_ssid(dev, apdev):
     msg['payload'] += ie_p2p(attrs)
     msg['payload'] += ie_ssid(255 * 'A')
     hapd.mgmt_tx(msg)
-    ev = dev[0].wait_event(["P2P-DEVICE-FOUND"], timeout=5)
+    ev = dev[0].wait_global_event(["P2P-DEVICE-FOUND"], timeout=5)
     if ev is None:
         raise Exception("Timeout on device found event")
 
+@remote_compatible
 def test_p2p_msg_long_dev_name(dev, apdev):
     """P2P protocol test: Too long Device Name in P2P Public Action frame"""
     dst, src, hapd, channel = start_p2p(dev, apdev)
@@ -897,6 +839,7 @@ def test_p2p_msg_invitation_req_to_go(dev, apdev):
     if p2p['p2p_status'] != 7 and dev[1].get_mcc() <= 1:
         raise Exception("Unexpected status %d" % p2p['p2p_status'])
 
+@remote_compatible
 def test_p2p_msg_invitation_req_unknown(dev, apdev):
     """P2P protocol tests for invitation request from unknown peer"""
     dst, src, hapd, channel = start_p2p(dev, apdev)
@@ -919,6 +862,7 @@ def test_p2p_msg_invitation_req_unknown(dev, apdev):
     if hapd.mgmt_rx(timeout=1) is None:
         raise Exception("No invitation response " + str(dialog_token))
 
+@remote_compatible
 def test_p2p_msg_invitation_no_common_channels(dev, apdev):
     """P2P protocol tests for invitation request without common channels"""
     dst, src, hapd, channel = start_p2p(dev, apdev)
@@ -1055,7 +999,7 @@ def test_p2p_msg_invitation_resp(dev, apdev):
     msg['payload'] += ie_p2p(attrs)
     mgmt_tx(dev[1], "MGMT_TX {} {} freq={} wait_time=200 no_cck=1 action={}".format(addr0, addr0, rx_msg['freq'], binascii.hexlify(msg['payload'])))
 
-    ev = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=15);
+    ev = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
     if ev is None:
         raise Exception("Group was not started")
 
@@ -1087,11 +1031,11 @@ def test_p2p_msg_invitation_resend(dev, apdev):
     mgmt_tx(dev[1], "MGMT_TX {} {} freq={} wait_time=200 no_cck=1 action={}".format(addr0, addr0, rx_msg['freq'], binascii.hexlify(msg['payload'])))
     ev = dev[0].wait_global_event(["P2P-INVITATION-RESULT"], timeout=15)
     if ev is None:
-        raise Exception("Timeout on invitation result");
+        raise Exception("Timeout on invitation result")
     if "status=7" not in ev:
         raise Exception("Unexpected invitation result: " + ev)
 
-    logger.info("Any channel allowed, only preference provided in invitation");
+    logger.info("Any channel allowed, only preference provided in invitation")
     invite(dev[0], dev[1], extra="pref=2422")
     rx_msg = dev[1].mgmt_rx()
     if rx_msg is None:
@@ -1110,14 +1054,14 @@ def test_p2p_msg_invitation_resend(dev, apdev):
     mgmt_tx(dev[1], "MGMT_TX {} {} freq={} wait_time=200 no_cck=1 action={}".format(addr0, addr0, rx_msg['freq'], binascii.hexlify(msg['payload'])))
     ev = dev[0].wait_global_event(["P2P-INVITATION-RESULT"], timeout=15)
     if ev is None:
-        raise Exception("Timeout on invitation result");
+        raise Exception("Timeout on invitation result")
     if "status=0" not in ev:
         raise Exception("Unexpected invitation result: " + ev)
 
-    ev = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=15);
+    ev = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
     if ev is None:
         raise Exception("Group was not started on dev0")
-    ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=15);
+    ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
     if ev is None:
         raise Exception("Group was not started on dev1")
 
@@ -1132,7 +1076,7 @@ def test_p2p_msg_invitation_resend_duplicate(dev, apdev):
     if "FAIL" in dev[1].request("SET ext_mgmt_frame_handling 1"):
         raise Exception("Failed to enable external management frame handling")
 
-    logger.info("Any channel allowed, only preference provided in invitation");
+    logger.info("Any channel allowed, only preference provided in invitation")
     invite(dev[0], dev[1], extra="pref=2422")
     rx_msg = dev[1].mgmt_rx()
     if rx_msg is None:
@@ -1172,7 +1116,7 @@ def test_p2p_msg_invitation_resend_duplicate(dev, apdev):
 
     ev = dev[0].wait_global_event(["P2P-INVITATION-RESULT"], timeout=10)
     if ev is None:
-        raise Exception("Timeout on invitation result");
+        raise Exception("Timeout on invitation result")
     if "status=0" not in ev:
         raise Exception("Unexpected invitation result: " + ev)
     ev = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
@@ -1181,6 +1125,7 @@ def test_p2p_msg_invitation_resend_duplicate(dev, apdev):
     dev[0].group_form_result(ev)
     dev[0].remove_group()
 
+@remote_compatible
 def test_p2p_msg_pd_req(dev, apdev):
     """P2P protocol tests for provision discovery request processing"""
     dst, src, hapd, channel = start_p2p(dev, apdev)
@@ -1351,10 +1296,10 @@ def test_p2p_msg_go_neg_both_start(dev, apdev):
     ev = dev[0].wait_global_event(["P2P-GO-NEG-SUCCESS"], timeout=10)
     if ev is None:
         raise Exception("GO Neg did not succeed")
-    ev = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=5);
+    ev = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=5)
     if ev is None:
         raise Exception("Group formation not succeed")
-    ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=5);
+    ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=5)
     if ev is None:
         raise Exception("Group formation not succeed")
 
@@ -1949,3 +1894,198 @@ def test_p2p_msg_unexpected_go_neg_resp(dev, apdev):
     mgmt_tx(dev[0], "MGMT_TX {} {} freq={} wait_time=200 no_cck=1 action={}".format(addr1, addr1, p2p['freq'], binascii.hexlify(msg['payload'])))
     check_p2p_go_neg_fail_event(dev[1], P2P_SC_FAIL_NO_COMMON_CHANNELS)
     rx_go_neg_conf(dev[0], P2P_SC_FAIL_NO_COMMON_CHANNELS, dialog_token)
+
+def test_p2p_msg_group_info(dev):
+    """P2P protocol tests for Group Info parsing"""
+    try:
+        _test_p2p_msg_group_info(dev)
+    finally:
+        dev[0].request("VENDOR_ELEM_REMOVE 2 *")
+
+def _test_p2p_msg_group_info(dev):
+    tests = [ "dd08506f9a090e010001",
+              "dd08506f9a090e010000",
+              "dd20506f9a090e190018" + "112233445566" + "aabbccddeeff" + "00" + "0000" + "0000000000000000" + "ff",
+              "dd20506f9a090e190018" + "112233445566" + "aabbccddeeff" + "00" + "0000" + "0000000000000000" + "00",
+              "dd24506f9a090e1d001c" + "112233445566" + "aabbccddeeff" + "00" + "0000" + "0000000000000000" + "00" + "00000000",
+              "dd24506f9a090e1d001c" + "112233445566" + "aabbccddeeff" + "00" + "0000" + "0000000000000000" + "00" + "10110001",
+              "dd24506f9a090e1d001c" + "112233445566" + "aabbccddeeff" + "00" + "0000" + "0000000000000000" + "00" + "1011ffff" ]
+    for t in tests:
+        dev[0].request("VENDOR_ELEM_REMOVE 2 *")
+        if "OK" not in dev[0].request("VENDOR_ELEM_ADD 2 " + t):
+            raise Exception("VENDOR_ELEM_ADD failed")
+        dev[0].p2p_start_go(freq=2412)
+        bssid = dev[0].get_group_status_field('bssid')
+        dev[2].request("BSS_FLUSH 0")
+        dev[2].scan_for_bss(bssid, freq=2412, force_scan=True)
+        bss = dev[2].request("BSS " + bssid)
+        if 'p2p_group_client' in bss:
+            raise Exception("Unexpected p2p_group_client")
+        dev[0].remove_group()
+
+MGMT_SUBTYPE_ACTION = 13
+ACTION_CATEG_PUBLIC = 4
+
+GAS_INITIAL_REQUEST = 10
+GAS_INITIAL_RESPONSE = 11
+GAS_COMEBACK_REQUEST = 12
+GAS_COMEBACK_RESPONSE = 13
+
+def gas_hdr(dst, src, type, req=True, dialog_token=0):
+    msg = {}
+    msg['fc'] = MGMT_SUBTYPE_ACTION << 4
+    msg['da'] = dst
+    msg['sa'] = src
+    if req:
+        msg['bssid'] = dst
+    else:
+        msg['bssid'] = src
+    if dialog_token is None:
+        msg['payload'] = struct.pack("<BB", ACTION_CATEG_PUBLIC, type)
+    else:
+        msg['payload'] = struct.pack("<BBB", ACTION_CATEG_PUBLIC, type,
+                                     dialog_token)
+    return msg
+
+@remote_compatible
+def test_p2p_msg_sd(dev, apdev):
+    """P2P protocol tests for service discovery messages"""
+    dst, src, hapd, channel = start_p2p(dev, apdev)
+
+    logger.debug("Truncated GAS Initial Request - no Dialog Token field")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST, dialog_token=None)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Truncated GAS Initial Request - no Advertisement Protocol element")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Truncated GAS Initial Request - no Advertisement Protocol element length")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    msg['payload'] += struct.pack('B', 108)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Invalid GAS Initial Request - unexpected IE")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    msg['payload'] += struct.pack('BB', 0, 0)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Truncated GAS Initial Request - too short Advertisement Protocol element")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    msg['payload'] += struct.pack('BB', 108, 0)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Truncated GAS Initial Request - too short Advertisement Protocol element 2")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    msg['payload'] += struct.pack('BBB', 108, 1, 127)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Invalid GAS Initial Request - unsupported GAS advertisement protocol id 255")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    msg['payload'] += struct.pack('BBBB', 108, 2, 127, 255)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Truncated GAS Initial Request - no Query Request length field")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    msg['payload'] += anqp_adv_proto()
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Truncated GAS Initial Request - too short Query Request length field")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    msg['payload'] += anqp_adv_proto()
+    msg['payload'] += struct.pack('<B', 0)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Truncated GAS Initial Request - too short Query Request field (minimum underflow)")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    msg['payload'] += anqp_adv_proto()
+    msg['payload'] += struct.pack('<H', 1)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Truncated GAS Initial Request - too short Query Request field (maximum underflow)")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    msg['payload'] += anqp_adv_proto()
+    msg['payload'] += struct.pack('<H', 65535)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Truncated GAS Initial Request - too short Query Request field")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    msg['payload'] += anqp_adv_proto()
+    msg['payload'] += struct.pack('<H', 0)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Invalid GAS Initial Request - unsupported ANQP Info ID 65535")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    msg['payload'] += anqp_adv_proto()
+    msg['payload'] += struct.pack('<HHH', 4, 65535, 0)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Invalid GAS Initial Request - invalid ANQP Query Request length (truncated frame)")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    msg['payload'] += anqp_adv_proto()
+    msg['payload'] += struct.pack('<HHH', 4, 56797, 65535)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Invalid GAS Initial Request - invalid ANQP Query Request length (too short Query Request to contain OUI + OUI-type)")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    msg['payload'] += anqp_adv_proto()
+    msg['payload'] += struct.pack('<HHH', 4, 56797, 0)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Invalid GAS Initial Request - unsupported ANQP vendor OUI-type")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    msg['payload'] += anqp_adv_proto()
+    req = struct.pack('<HH', 56797, 4) + struct.pack('>L', 0x506f9a00)
+    msg['payload'] += struct.pack('<H', len(req)) + req
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Truncated GAS Initial Request - no Service Update Indicator")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    msg['payload'] += anqp_adv_proto()
+    req = struct.pack('<HH', 56797, 4) + struct.pack('>L', 0x506f9a09)
+    msg['payload'] += struct.pack('<H', len(req)) + req
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Truncated GAS Initial Request - truncated Service Update Indicator")
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    msg['payload'] += anqp_adv_proto()
+    req = struct.pack('<HH', 56797, 4) + struct.pack('>L', 0x506f9a09)
+    req += struct.pack('<B', 0)
+    msg['payload'] += struct.pack('<H', len(req)) + req
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Unexpected GAS Initial Response")
+    hapd.dump_monitor()
+    msg = gas_hdr(dst, src, GAS_INITIAL_RESPONSE)
+    msg['payload'] += struct.pack('<HH', 0, 0)
+    msg['payload'] += anqp_adv_proto()
+    msg['payload'] += struct.pack('<H', 0)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Truncated GAS Comeback Request - no Dialog Token field")
+    msg = gas_hdr(dst, src, GAS_COMEBACK_REQUEST, dialog_token=None)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("GAS Comeback Request - no pending SD response fragment available")
+    msg = gas_hdr(dst, src, GAS_COMEBACK_REQUEST)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Unexpected GAS Comeback Response")
+    hapd.dump_monitor()
+    msg = gas_hdr(dst, src, GAS_COMEBACK_RESPONSE)
+    msg['payload'] += struct.pack('<HBH', 0, 0, 0)
+    msg['payload'] += anqp_adv_proto()
+    msg['payload'] += struct.pack('<H', 0)
+    hapd.mgmt_tx(msg)
+
+    logger.debug("Minimal GAS Initial Request")
+    hapd.dump_monitor()
+    msg = gas_hdr(dst, src, GAS_INITIAL_REQUEST)
+    msg['payload'] += anqp_adv_proto()
+    req = struct.pack('<HH', 56797, 4) + struct.pack('>L', 0x506f9a09)
+    req += struct.pack('<H', 0)
+    msg['payload'] += struct.pack('<H', len(req)) + req
+    hapd.mgmt_tx(msg)
+    resp = hapd.mgmt_rx()
+    if resp is None:
+        raise Exception("No response to minimal GAS Initial Request")
index 2752a88..673fda3 100644 (file)
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 import re
 import time
 
 import hwsim_utils
-from test_p2p_autogo import connect_cli
-
-def go_neg_pin_authorized_persistent(i_dev, r_dev, i_intent=None, r_intent=None, i_method='enter', r_method='display', test_data=True):
-    r_dev.p2p_listen()
-    i_dev.p2p_listen()
-    pin = r_dev.wps_read_pin()
-    logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname)
-    r_dev.p2p_go_neg_auth(i_dev.p2p_dev_addr(), pin, r_method,
-                          go_intent=r_intent, persistent=True)
-    r_dev.p2p_listen()
-    i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), pin, i_method,
-                                  timeout=20, go_intent=i_intent,
-                                  persistent=True)
-    r_res = r_dev.p2p_go_neg_auth_result()
-    logger.debug("i_res: " + str(i_res))
-    logger.debug("r_res: " + str(r_res))
-    r_dev.dump_monitor()
-    i_dev.dump_monitor()
-    logger.info("Group formed")
-    if test_data:
-        hwsim_utils.test_connectivity_p2p(r_dev, i_dev)
-    return [i_res, r_res]
-
-def terminate_group(go, cli):
-    logger.info("Terminate persistent group")
-    go.remove_group()
-    cli.wait_go_ending_session()
-
-def invite(inv, resp, extra=None, persistent_reconnect=True):
-    addr = resp.p2p_dev_addr()
-    if persistent_reconnect:
-        resp.global_request("SET persistent_reconnect 1")
-    else:
-        resp.global_request("SET persistent_reconnect 0")
-    resp.p2p_listen()
-    if not inv.discover_peer(addr, social=True):
-        raise Exception("Peer " + addr + " not found")
-    inv.dump_monitor()
-    peer = inv.get_peer(addr)
-    cmd = "P2P_INVITE persistent=" + peer['persistent'] + " peer=" + addr
-    if extra:
-        cmd = cmd + " " + extra;
-    inv.global_request(cmd)
-
-def check_result(go, cli):
-    ev = go.wait_global_event(["P2P-GROUP-STARTED"], timeout=30)
-    if ev is None:
-        raise Exception("Timeout on group re-invocation (on GO)")
-    if "[PERSISTENT]" not in ev:
-        raise Exception("Re-invoked group not marked persistent")
-    go_res = go.group_form_result(ev)
-    if go_res['role'] != 'GO':
-        raise Exception("Persistent group GO did not become GO")
-    if not go_res['persistent']:
-        raise Exception("Persistent group not re-invoked as persistent (GO)")
-    ev = cli.wait_global_event(["P2P-GROUP-STARTED"], timeout=30)
-    if ev is None:
-        raise Exception("Timeout on group re-invocation (on client)")
-    if "[PERSISTENT]" not in ev:
-        raise Exception("Re-invoked group not marked persistent")
-    cli_res = cli.group_form_result(ev)
-    if cli_res['role'] != 'client':
-        raise Exception("Persistent group client did not become client")
-    if not cli_res['persistent']:
-        raise Exception("Persistent group not re-invoked as persistent (cli)")
-    return [go_res, cli_res]
-
-def form(go, cli, test_data=True, reverse_init=False):
-    logger.info("Form a persistent group")
-    if reverse_init:
-        [i_res, r_res] = go_neg_pin_authorized_persistent(i_dev=cli, i_intent=0,
-                                                          r_dev=go, r_intent=15,
-                                                          test_data=test_data)
-    else:
-        [i_res, r_res] = go_neg_pin_authorized_persistent(i_dev=go, i_intent=15,
-                                                          r_dev=cli, r_intent=0,
-                                                          test_data=test_data)
-    if not i_res['persistent'] or not r_res['persistent']:
-        raise Exception("Formed group was not persistent")
-    terminate_group(go, cli)
-    if reverse_init:
-        return r_res
-    else:
-        return i_res
-
-def invite_from_cli(go, cli):
-    logger.info("Re-invoke persistent group from client")
-    invite(cli, go)
-    [go_res, cli_res] = check_result(go, cli)
-    hwsim_utils.test_connectivity_p2p(go, cli)
-    terminate_group(go, cli)
-    return [go_res, cli_res]
-
-def invite_from_go(go, cli):
-    logger.info("Re-invoke persistent group from GO")
-    invite(go, cli)
-    [go_res, cli_res] = check_result(go, cli)
-    hwsim_utils.test_connectivity_p2p(go, cli)
-    terminate_group(go, cli)
-    return [go_res, cli_res]
+from p2p_utils import *
 
+@remote_compatible
 def test_persistent_group(dev):
     """P2P persistent group formation and re-invocation"""
     form(dev[0], dev[1])
@@ -155,12 +58,14 @@ def test_persistent_group(dev):
     if dev[1].p2p_dev_addr() in clients:
         raise Exception("Peer was still in client list")
 
+@remote_compatible
 def test_persistent_group2(dev):
     """P2P persistent group formation with reverse roles"""
     form(dev[0], dev[1], reverse_init=True)
     invite_from_cli(dev[0], dev[1])
     invite_from_go(dev[0], dev[1])
 
+@remote_compatible
 def test_persistent_group3(dev):
     """P2P persistent group formation and re-invocation with empty BSS table"""
     form(dev[0], dev[1])
@@ -358,6 +263,7 @@ def test_persistent_group_invite_removed_client(dev):
 
     terminate_group(dev[0], dev[1])
 
+@remote_compatible
 def test_persistent_group_channel(dev):
     """P2P persistent group re-invocation with channel selection"""
     form(dev[0], dev[1], test_data=False)
@@ -383,6 +289,7 @@ def test_persistent_group_channel(dev):
         raise Exception("Persistent group client channel preference not followed")
     terminate_group(dev[0], dev[1])
 
+@remote_compatible
 def test_persistent_group_and_role_change(dev):
     """P2P persistent group, auto GO in another role, and re-invocation"""
     form(dev[0], dev[1])
@@ -451,6 +358,7 @@ def test_persistent_go_client_list(dev):
     if 'persistent' not in peer or peer['persistent'] != id:
         raise Exception("Persistent group client not recognized(2)")
 
+@remote_compatible
 def test_persistent_group_in_grpform(dev):
     """P2P persistent group parameters re-used in group formation"""
     addr0 = dev[0].p2p_dev_addr()
@@ -472,6 +380,7 @@ def test_persistent_group_in_grpform(dev):
     logger.debug("i_res: " + str(i_res))
     logger.debug("r_res: " + str(r_res))
 
+@remote_compatible
 def test_persistent_group_without_persistent_reconnect(dev):
     """P2P persistent group re-invocation without persistent reconnect"""
     form(dev[0], dev[1])
@@ -483,13 +392,13 @@ def test_persistent_group_without_persistent_reconnect(dev):
 
     ev = dev[0].wait_global_event(["P2P-INVITATION-RECEIVED"], timeout=15)
     if ev is None:
-        raise Exception("No invitation request reported");
+        raise Exception("No invitation request reported")
     if "persistent=" not in ev:
         raise Exception("Invalid invitation type reported: " + ev)
 
     ev2 = dev[1].wait_global_event(["P2P-INVITATION-RESULT"], timeout=15)
     if ev2 is None:
-        raise Exception("No invitation response reported");
+        raise Exception("No invitation response reported")
     if "status=1" not in ev2:
         raise Exception("Unexpected status: " + ev2)
     dev[1].p2p_listen()
@@ -523,13 +432,13 @@ def test_persistent_group_without_persistent_reconnect(dev):
 
     ev = dev[1].wait_global_event(["P2P-INVITATION-RECEIVED"], timeout=15)
     if ev is None:
-        raise Exception("No invitation request reported");
+        raise Exception("No invitation request reported")
     if "persistent=" not in ev:
         raise Exception("Invalid invitation type reported: " + ev)
 
     ev2 = dev[0].wait_global_event(["P2P-INVITATION-RESULT"], timeout=15)
     if ev2 is None:
-        raise Exception("No invitation response reported");
+        raise Exception("No invitation response reported")
     if "status=1" not in ev2:
         raise Exception("Unexpected status: " + ev2)
     dev[0].p2p_listen()
@@ -546,6 +455,7 @@ def test_persistent_group_without_persistent_reconnect(dev):
     [go_res, cli_res] = check_result(dev[0], dev[1])
     terminate_group(dev[0], dev[1])
 
+@remote_compatible
 def test_persistent_group_already_running(dev):
     """P2P persistent group formation and invitation while GO already running"""
     form(dev[0], dev[1])
@@ -562,19 +472,25 @@ def test_persistent_group_already_running(dev):
         raise Exception("Could not state GO")
     invite_from_cli(dev[0], dev[1])
 
+@remote_compatible
 def test_persistent_group_add_cli_chan(dev):
     """P2P persistent group formation and re-invocation with p2p_add_cli_chan=1"""
-    dev[0].request("SET p2p_add_cli_chan 1")
-    dev[1].request("SET p2p_add_cli_chan 1")
-    form(dev[0], dev[1])
-    dev[1].request("BSS_FLUSH 0")
-    dev[1].scan(freq="2412", only_new=True)
-    dev[1].scan(freq="2437", only_new=True)
-    dev[1].scan(freq="2462", only_new=True)
-    dev[1].request("BSS_FLUSH 0")
-    invite_from_cli(dev[0], dev[1])
-    invite_from_go(dev[0], dev[1])
-
+    try:
+        dev[0].request("SET p2p_add_cli_chan 1")
+        dev[1].request("SET p2p_add_cli_chan 1")
+        form(dev[0], dev[1])
+        dev[1].request("BSS_FLUSH 0")
+        dev[1].scan(freq="2412", only_new=True)
+        dev[1].scan(freq="2437", only_new=True)
+        dev[1].scan(freq="2462", only_new=True)
+        dev[1].request("BSS_FLUSH 0")
+        invite_from_cli(dev[0], dev[1])
+        invite_from_go(dev[0], dev[1])
+    finally:
+        dev[0].request("SET p2p_add_cli_chan 0")
+        dev[1].request("SET p2p_add_cli_chan 0")
+
+@remote_compatible
 def test_persistent_invalid_group_add(dev):
     """Invalid P2P_GROUP_ADD command"""
     id = dev[0].add_network()
@@ -633,14 +549,15 @@ def test_persistent_group_missed_inv_resp(dev):
 
     terminate_group(dev[0], dev[1])
 
+@remote_compatible
 def test_persistent_group_profile_add(dev):
     """Create a P2P persistent group with ADD_NETWORK"""
     passphrase="passphrase here"
-    id = dev[0].add_network()
-    dev[0].set_network_quoted(id, "ssid", "DIRECT-ab")
-    dev[0].set_network_quoted(id, "psk", passphrase)
-    dev[0].set_network(id, "mode", "3")
-    dev[0].set_network(id, "disabled", "2")
+    id = dev[0].p2pdev_add_network()
+    dev[0].p2pdev_set_network_quoted(id, "ssid", "DIRECT-ab")
+    dev[0].p2pdev_set_network_quoted(id, "psk", passphrase)
+    dev[0].p2pdev_set_network(id, "mode", "3")
+    dev[0].p2pdev_set_network(id, "disabled", "2")
     dev[0].p2p_start_go(persistent=id, freq=2412)
 
     pin = dev[1].wps_read_pin()
@@ -652,3 +569,105 @@ def test_persistent_group_profile_add(dev):
 
     dev[0].remove_group()
     dev[1].wait_go_ending_session()
+
+@remote_compatible
+def test_persistent_group_cancel_on_cli(dev):
+    """P2P persistent group formation, re-invocation, and cancel"""
+    dev[0].global_request("SET p2p_no_group_iface 0")
+    dev[1].global_request("SET p2p_no_group_iface 0")
+    form(dev[0], dev[1])
+
+    invite_from_go(dev[0], dev[1], terminate=False)
+    if "FAIL" not in dev[1].global_request("P2P_CANCEL"):
+        raise Exception("P2P_CANCEL succeeded unexpectedly on CLI")
+    if "FAIL" not in dev[0].global_request("P2P_CANCEL"):
+        raise Exception("P2P_CANCEL succeeded unexpectedly on GO")
+    terminate_group(dev[0], dev[1])
+
+    invite_from_cli(dev[0], dev[1], terminate=False)
+    if "FAIL" not in dev[1].global_request("P2P_CANCEL"):
+        raise Exception("P2P_CANCEL succeeded unexpectedly on CLI")
+    if "FAIL" not in dev[0].global_request("P2P_CANCEL"):
+        raise Exception("P2P_CANCEL succeeded unexpectedly on GO")
+    terminate_group(dev[0], dev[1])
+
+@remote_compatible
+def test_persistent_group_cancel_on_cli2(dev):
+    """P2P persistent group formation, re-invocation, and cancel (2)"""
+    form(dev[0], dev[1])
+    invite_from_go(dev[0], dev[1], terminate=False)
+    if "FAIL" not in dev[1].global_request("P2P_CANCEL"):
+        raise Exception("P2P_CANCEL succeeded unexpectedly on CLI")
+    if "FAIL" not in dev[0].global_request("P2P_CANCEL"):
+        raise Exception("P2P_CANCEL succeeded unexpectedly on GO")
+    terminate_group(dev[0], dev[1])
+
+    invite_from_cli(dev[0], dev[1], terminate=False)
+    if "FAIL" not in dev[1].global_request("P2P_CANCEL"):
+        raise Exception("P2P_CANCEL succeeded unexpectedly on CLI")
+    if "FAIL" not in dev[0].global_request("P2P_CANCEL"):
+        raise Exception("P2P_CANCEL succeeded unexpectedly on GO")
+    terminate_group(dev[0], dev[1])
+
+@remote_compatible
+def test_persistent_group_peer_dropped(dev):
+    """P2P persistent group formation and re-invocation with peer having dropped group"""
+    form(dev[0], dev[1], reverse_init=True)
+    invite_from_cli(dev[0], dev[1])
+
+    logger.info("Remove group on the GO and try to invite from the client")
+    dev[0].global_request("REMOVE_NETWORK all")
+    invite(dev[1], dev[0])
+    ev = dev[1].wait_global_event(["P2P-INVITATION-RESULT"], timeout=10)
+    if ev is None:
+        raise Exception("No invitation result seen")
+    if "status=8" not in ev:
+        raise Exception("Unexpected invitation result: " + ev)
+    networks = dev[1].list_networks(p2p=True)
+    if len(networks) > 0:
+        raise Exception("Unexpected network block on client")
+
+    logger.info("Verify that a new group can be formed")
+    form(dev[0], dev[1], reverse_init=True)
+
+@remote_compatible
+def test_persistent_group_peer_dropped2(dev):
+    """P2P persistent group formation and re-invocation with peer having dropped group (2)"""
+    form(dev[0], dev[1])
+    invite_from_go(dev[0], dev[1])
+
+    logger.info("Remove group on the client and try to invite from the GO")
+    dev[1].global_request("REMOVE_NETWORK all")
+    invite(dev[0], dev[1])
+    ev = dev[0].wait_global_event(["P2P-INVITATION-RESULT"], timeout=10)
+    if ev is None:
+        raise Exception("No invitation result seen")
+    if "status=8" not in ev:
+        raise Exception("Unexpected invitation result: " + ev)
+    networks = dev[1].list_networks(p2p=True)
+    if len(networks) > 0:
+        raise Exception("Unexpected network block on client")
+
+    logger.info("Verify that a new group can be formed")
+    form(dev[0], dev[1])
+
+def test_persistent_group_peer_dropped3(dev):
+    """P2P persistent group formation and re-invocation with peer having dropped group (3)"""
+    form(dev[0], dev[1], reverse_init=True)
+    invite_from_cli(dev[0], dev[1])
+
+    logger.info("Remove group on the GO and try to invite from the client")
+    dev[0].global_request("REMOVE_NETWORK all")
+    invite(dev[1], dev[0], use_listen=False)
+    ev = dev[1].wait_global_event(["P2P-INVITATION-RESULT"], timeout=10)
+    if ev is None:
+        raise Exception("No invitation result seen")
+    if "status=8" not in ev:
+        raise Exception("Unexpected invitation result: " + ev)
+    networks = dev[1].list_networks(p2p=True)
+    if len(networks) > 0:
+        raise Exception("Unexpected network block on client")
+
+    time.sleep(0.2)
+    logger.info("Verify that a new group can be formed")
+    form(dev[0], dev[1], reverse_init=True, r_listen=False)
index ea7a8f4..4f5af5c 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 import time
@@ -87,6 +88,7 @@ def run_sd(dev, dst, query, exp_query=None, fragment=False, query2=None):
 
     return ev
 
+@remote_compatible
 def test_p2p_service_discovery(dev):
     """P2P service discovery"""
     addr0 = dev[0].p2p_dev_addr()
@@ -132,6 +134,7 @@ def test_p2p_service_discovery4(dev):
         if "496e7465726e6574" not in ev:
             raise Exception("Unexpected service discovery response contents (UPnP)")
 
+@remote_compatible
 def test_p2p_service_discovery_multiple_queries(dev):
     """P2P service discovery with multiple queries"""
     for dst in [ "00:00:00:00:00:00", dev[0].p2p_dev_addr() ]:
@@ -161,6 +164,7 @@ def test_p2p_service_discovery_fragmentation(dev):
             if "496e7465726e6574" not in ev:
                 raise Exception("Unexpected service discovery response contents (UPnP)")
 
+@remote_compatible
 def test_p2p_service_discovery_bonjour(dev):
     """P2P service discovery (Bonjour)"""
     ev = run_sd(dev, "00:00:00:00:00:00", "02000101")
@@ -171,6 +175,7 @@ def test_p2p_service_discovery_bonjour(dev):
     if "496e7465726e6574" in ev:
         raise Exception("Unexpected service discovery response contents (UPnP not expected)")
 
+@remote_compatible
 def test_p2p_service_discovery_bonjour2(dev):
     """P2P service discovery (Bonjour AFS)"""
     ev = run_sd(dev, "00:00:00:00:00:00", "130001010b5f6166706f766572746370c00c000c01")
@@ -181,6 +186,7 @@ def test_p2p_service_discovery_bonjour2(dev):
     if "496e7465726e6574" in ev:
         raise Exception("Unexpected service discovery response contents (UPnP not expected)")
 
+@remote_compatible
 def test_p2p_service_discovery_bonjour3(dev):
     """P2P service discovery (Bonjour AFS - no match)"""
     ev = run_sd(dev, "00:00:00:00:00:00", "130001010b5f6166706f766572746370c00c000c02")
@@ -193,6 +199,7 @@ def test_p2p_service_discovery_bonjour3(dev):
     if "496e7465726e6574" in ev:
         raise Exception("Unexpected service discovery response contents (UPnP not expected)")
 
+@remote_compatible
 def test_p2p_service_discovery_upnp(dev):
     """P2P service discovery (UPnP)"""
     ev = run_sd(dev, "00:00:00:00:00:00", "02000201")
@@ -201,6 +208,7 @@ def test_p2p_service_discovery_upnp(dev):
     if "496e7465726e6574" not in ev:
         raise Exception("Unexpected service discovery response contents (UPnP)")
 
+@remote_compatible
 def test_p2p_service_discovery_upnp2(dev):
     """P2P service discovery (UPnP using request helper)"""
     ev = run_sd(dev, "00:00:00:00:00:00", "upnp 10 ssdp:all", "0b00020110737364703a616c6c")
@@ -209,6 +217,7 @@ def test_p2p_service_discovery_upnp2(dev):
     if "496e7465726e6574" not in ev:
         raise Exception("Unexpected service discovery response contents (UPnP)")
 
+@remote_compatible
 def test_p2p_service_discovery_upnp3(dev):
     """P2P service discovery (UPnP using request helper - no match)"""
     ev = run_sd(dev, "00:00:00:00:00:00", "upnp 10 ssdp:foo", "0b00020110737364703a666f6f")
@@ -219,6 +228,7 @@ def test_p2p_service_discovery_upnp3(dev):
     if "496e7465726e6574" in ev:
         raise Exception("Unexpected service discovery response contents (UPnP)")
 
+@remote_compatible
 def test_p2p_service_discovery_ws(dev):
     """P2P service discovery (WS-Discovery)"""
     ev = run_sd(dev, "00:00:00:00:00:00", "02000301")
@@ -229,6 +239,7 @@ def test_p2p_service_discovery_ws(dev):
     if "0300030101" not in ev:
         raise Exception("Unexpected service discovery response contents (WS)")
 
+@remote_compatible
 def test_p2p_service_discovery_wfd(dev):
     """P2P service discovery (Wi-Fi Display)"""
     dev[0].global_request("SET wifi_display 1")
@@ -240,6 +251,7 @@ def test_p2p_service_discovery_wfd(dev):
     if "0300040101" not in ev:
         raise Exception("Unexpected response to WFD SD query (protocol was disabled)")
 
+@remote_compatible
 def test_p2p_service_discovery_req_cancel(dev):
     """Cancel a P2P service discovery request"""
     if "FAIL" not in dev[0].global_request("P2P_SERV_DISC_CANCEL_REQ ab"):
@@ -263,6 +275,7 @@ def test_p2p_service_discovery_req_cancel(dev):
     if "OK" not in dev[0].global_request("P2P_SERV_DISC_CANCEL_REQ " + query):
         raise Exception("Unexpected SD(broadcast) cancel failure")
 
+@remote_compatible
 def test_p2p_service_discovery_go(dev):
     """P2P service discovery from GO"""
     addr0 = dev[0].p2p_dev_addr()
@@ -387,6 +400,7 @@ def _test_p2p_service_discovery_external(dev):
         if "FAIL" not in dev[0].global_request("P2P_SERV_DISC_RESP " + cmd):
             raise Exception("Invalid P2P_SERV_DISC_RESP accepted: " + cmd)
 
+@remote_compatible
 def test_p2p_service_discovery_external(dev):
     """P2P service discovery using external response"""
     try:
@@ -394,6 +408,7 @@ def test_p2p_service_discovery_external(dev):
     finally:
         dev[0].global_request("P2P_SERV_DISC_EXTERNAL 0")
 
+@remote_compatible
 def test_p2p_service_discovery_invalid_commands(dev):
     """P2P service discovery invalid commands"""
     for cmd in [ "bonjour",
@@ -454,6 +469,7 @@ def get_p2p_state(dev):
         raise Exception("Could not get p2p_state")
     return p2p_state
 
+@remote_compatible
 def test_p2p_service_discovery_peer_not_listening(dev):
     """P2P service discovery and peer not listening"""
     addr0 = dev[0].p2p_dev_addr()
@@ -483,6 +499,7 @@ def test_p2p_service_discovery_peer_not_listening(dev):
     if p2p_state != "IDLE":
         raise Exception("Unexpected p2p_state after P2P_FIND timeout: " + p2p_state)
 
+@remote_compatible
 def test_p2p_service_discovery_peer_not_listening2(dev):
     """P2P service discovery and peer not listening"""
     addr0 = dev[0].p2p_dev_addr()
index ba1e7ce..a96b572 100644 (file)
@@ -4,6 +4,8 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
+
 def test_p2p_set(dev):
     """P2P_SET commands"""
     for cmd in [ "",
@@ -102,6 +104,7 @@ def test_p2p_set_managed(dev):
     dev[2].p2p_stop_find()
     dev[0].p2p_stop_find()
 
+@remote_compatible
 def test_p2p_set_ssid_postfix(dev):
     """P2P_SET ssid_postfix"""
     addr0 = dev[0].p2p_dev_addr()
index e820639..94c7da9 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 import time
@@ -12,8 +13,7 @@ import Queue
 
 import hwsim_utils
 import utils
-from test_p2p_autogo import connect_cli
-from test_p2p_persistent import form, invite, invite_from_cli, invite_from_go
+from p2p_utils import *
 
 def test_wifi_display(dev):
     """Wi-Fi Display extensions to P2P"""
@@ -299,6 +299,7 @@ def test_wifi_display_persistent_group(dev):
         dev[1].request("SET wifi_display 0")
         dev[2].request("SET wifi_display 0")
 
+@remote_compatible
 def test_wifi_display_invalid_subelem(dev):
     """Wi-Fi Display and invalid subelement parsing"""
     addr1 = dev[1].p2p_dev_addr()
@@ -319,3 +320,41 @@ def test_wifi_display_invalid_subelem(dev):
     finally:
         dev[0].request("SET wifi_display 0")
         dev[1].request("SET wifi_display 0")
+
+def test_wifi_display_parsing(dev):
+    """Wi-Fi Display extensions to P2P and special parsing cases"""
+    try:
+        _test_wifi_display_parsing(dev)
+    finally:
+        dev[1].request("VENDOR_ELEM_REMOVE 11 *")
+        dev[0].request("SET wifi_display 0")
+
+def _test_wifi_display_parsing(dev):
+    wfd_devinfo = "00411c440028"
+    dev[0].request("SET wifi_display 1")
+    dev[0].request("WFD_SUBELEM_SET 0 0006" + wfd_devinfo)
+    dev[0].p2p_start_go(freq=2412)
+
+    # P2P Client with invalid WFD IE
+    if "OK" not in dev[1].request("VENDOR_ELEM_ADD 11 dd10506f9a0a000000010000060000ffffff"):
+        raise Exception("VENDOR_ELEM_ADD failed")
+
+    pin = dev[1].wps_read_pin()
+    dev[0].p2p_go_authorize_client(pin)
+    dev[1].p2p_connect_group(dev[0].p2p_dev_addr(), pin, timeout=60,
+                             social=True, freq=2412)
+    bssid = dev[0].get_group_status_field('bssid')
+    dev[2].scan_for_bss(bssid, freq=2412, force_scan=True)
+    bss = dev[2].get_bss(bssid)
+    if bss['wfd_subelems'] != "000006" + wfd_devinfo:
+        raise Exception("Unexpected WFD elements in scan results: " + bss['wfd_subelems'])
+
+    # P2P Client without WFD IE
+    pin = dev[2].wps_read_pin()
+    dev[0].p2p_go_authorize_client(pin)
+    dev[2].p2p_connect_group(dev[0].p2p_dev_addr(), pin, timeout=60,
+                             social=True, freq=2412)
+    dev[2].remove_group()
+
+    dev[0].remove_group()
+    dev[1].wait_go_ending_session()
index 5f0b13b..4ae0868 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 import time
@@ -12,10 +13,10 @@ import re
 
 import hwsim_utils
 from wpasupplicant import WpaSupplicant
-from test_p2p_grpform import check_grpform_results
-from test_p2p_grpform import remove_group
-from test_p2p_persistent import go_neg_pin_authorized_persistent
+import hostapd
+from p2p_utils import *
 from utils import HwsimSkip
+from hwsim import HWSimRadio
 
 # Dev[0] -> Advertiser
 # Dev[1] -> Seeker
@@ -92,6 +93,7 @@ def p2ps_exact_seek(i_dev, r_dev, svc_name, srv_info=None,
         if rcvd_svc_name != svc_name:
             raise Exception("service name not matching")
 
+    i_dev.p2p_stop_find()
     return [adv_id, rcvd_svc_name]
 
 def p2ps_nonexact_seek(i_dev, r_dev, svc_name, srv_info=None, adv_num=None):
@@ -123,6 +125,8 @@ def p2ps_nonexact_seek(i_dev, r_dev, svc_name, srv_info=None, adv_num=None):
         adv_id = ev1.split(" ")[3]
         rcvd_svc_name = ev1.split(" ")[6]
         ev_list.append(''.join([adv_id, ' ', rcvd_svc_name]))
+
+    i_dev.p2p_stop_find()
     return ev_list
 
 def p2ps_parse_event(ev, *args):
@@ -132,12 +136,15 @@ def p2ps_parse_event(ev, *args):
         ret += (m.group(1) if m is not None else None,)
     return ret
 
-def p2ps_provision(seeker, advertiser, adv_id, auto_accept=True, method="1000", adv_cpt=None, seeker_cpt=None):
+def p2ps_provision(seeker, advertiser, adv_id, auto_accept=True, method="1000",
+                   adv_cpt=None, seeker_cpt=None, handler=None, adv_role=None,
+                   seeker_role=None):
     addr0 = seeker.p2p_dev_addr()
     addr1 = advertiser.p2p_dev_addr()
 
     seeker.asp_provision(addr1, adv_id=str(adv_id), adv_mac=addr1, session_id=1,
-                         session_mac=addr0, method=method, cpt=seeker_cpt)
+                         session_mac=addr0, method=method, cpt=seeker_cpt,
+                         role=seeker_role)
 
     if not auto_accept or method == "100":
         pin = None
@@ -153,6 +160,13 @@ def p2ps_provision(seeker, advertiser, adv_id, auto_accept=True, method="1000",
         if ev is None:
             raise Exception("P2P-PROV-DISC-FAILURE timeout on seeker side")
 
+        if handler:
+            handler(seeker, advertiser)
+
+        # Put seeker into a listen state, since we expect the deferred flow to
+        # continue.
+        seeker.p2p_ext_listen(500, 500)
+
         if method == "100":
             ev = advertiser.wait_global_event(["P2P-PROV-DISC-ENTER-PIN"],
                                               timeout=10)
@@ -176,10 +190,15 @@ def p2ps_provision(seeker, advertiser, adv_id, auto_accept=True, method="1000",
                 raise Exception("Unknown peer " + addr0)
             pin = ev.split()[2]
 
+        # Stop P2P_LISTEN before issuing P2P_ASP_PROVISION_RESP to avoid
+        # excessive delay and test case timeouts if it takes large number of
+        # retries to find the peer awake on its Listen channel.
+        advertiser.p2p_stop_find()
+
         advertiser.asp_provision(peer, adv_id=advert_id, adv_mac=advert_mac,
                                  session_id=int(session, 0),
                                  session_mac=session_mac, status=12,
-                                 cpt=adv_cpt)
+                                 cpt=adv_cpt, role=adv_role)
 
         ev1 = seeker.wait_global_event(["P2PS-PROV-DONE"], timeout=10)
         if ev1 is None:
@@ -197,6 +216,7 @@ def p2ps_provision(seeker, advertiser, adv_id, auto_accept=True, method="1000",
             if addr1 not in ev:
                 raise Exception("Unknown peer " + addr1)
 
+        seeker.p2p_cancel_ext_listen()
         if pin is not None:
             return ev1, ev2, pin
         return ev1, ev2
@@ -227,14 +247,14 @@ def p2ps_provision(seeker, advertiser, adv_id, auto_accept=True, method="1000",
 
     return ev1, ev2
 
-def p2ps_connect_pd(dev0, dev1, ev0, ev1, pin=None):
+def p2ps_connect_pd(dev0, dev1, ev0, ev1, pin=None, join_extra="", go_ev=None):
     conf_methods_map = {"8": "p2ps", "1": "display", "5": "keypad"}
     peer0 = ev0.split()[1]
     peer1 = ev1.split()[1]
-    status0, conncap0, adv_id0, adv_mac0, mac0, session0, dev_passwd_id0, go0, join0, feature_cap0, persist0 =\
-        p2ps_parse_event(ev0, "status", "conncap", "adv_id", "adv_mac", "mac", "session", "dev_passwd_id", "go", "join", "feature_cap", "persist")
-    status1, conncap1, adv_id1, adv_mac1, mac1, session1, dev_passwd_id1, go1, join1, feature_cap1, persist1 =\
-        p2ps_parse_event(ev1, "status", "conncap", "adv_id", "adv_mac", "mac", "session", "dev_passwd_id", "go", "join", "feature_cap", "persist")
+    status0, conncap0, adv_id0, adv_mac0, mac0, session0, dev_passwd_id0, go0, join0, feature_cap0, persist0, group_ssid0 =\
+        p2ps_parse_event(ev0, "status", "conncap", "adv_id", "adv_mac", "mac", "session", "dev_passwd_id", "go", "join", "feature_cap", "persist", "group_ssid")
+    status1, conncap1, adv_id1, adv_mac1, mac1, session1, dev_passwd_id1, go1, join1, feature_cap1, persist1, group_ssid1 =\
+        p2ps_parse_event(ev1, "status", "conncap", "adv_id", "adv_mac", "mac", "session", "dev_passwd_id", "go", "join", "feature_cap", "persist", "group_ssid")
 
     if status0 != "0" and status0 != "12":
         raise Exception("PD failed on " + dev0.p2p_dev_addr())
@@ -272,6 +292,7 @@ def p2ps_connect_pd(dev0, dev1, ev0, ev1, pin=None):
 
     # Persistent Connection (todo: handle frequency)
     if persist0 is not None:
+        dev0.p2p_stop_find()
         if "OK" not in dev0.global_request("P2P_GROUP_ADD persistent=" + persist0 + " freq=2412"):
             raise Exception("Could not re-start persistent group")
         ev0 = dev0.wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
@@ -329,9 +350,9 @@ def p2ps_connect_pd(dev0, dev1, ev0, ev1, pin=None):
             dev1.group_form_result(ev)
         else:
             if conncap0 == "2" and conncap1 == "4":  # dev0 CLI, dev1 GO
-                dev_cli, dev_go, go_if, join_address, go_method, cli_method = dev0, dev1, go1, join0, method1, method0
+                dev_cli, dev_go, go_if, join_address, go_method, cli_method, join_ssid = dev0, dev1, go1, join0, method1, method0, group_ssid0
             elif conncap0 == "4" and conncap1 == "2":  # dev0 GO, dev1 CLI
-                dev_cli, dev_go, go_if, join_address, go_method, cli_method = dev1, dev0, go0, join1, method0, method1
+                dev_cli, dev_go, go_if, join_address, go_method, cli_method, join_ssid = dev1, dev0, go0, join1, method0, method1, group_ssid1
             else:
                 raise Exception("Bad connection capabilities")
 
@@ -339,15 +360,26 @@ def p2ps_connect_pd(dev0, dev1, ev0, ev1, pin=None):
                 raise Exception("Device " + dev_go.p2p_dev_addr() + " failed to become GO")
             if join_address is None:
                 raise Exception("Device " + dev_cli.p2p_dev_addr() + " failed to become CLI")
-            ev = dev_go.wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
-            if ev is None:
-                raise Exception("P2P-GROUP-STARTED timeout on " + dev_go.p2p_dev_addr())
-            dev_go.group_form_result(ev)
+
+            if not dev_go.get_group_ifname().startswith('p2p-'):
+                if go_ev:
+                    ev = go_ev
+                else:
+                    ev = dev_go.wait_global_event(["P2P-GROUP-STARTED"],
+                                                  timeout=10)
+                if ev is None:
+                    raise Exception("P2P-GROUP-STARTED timeout on " + dev_go.p2p_dev_addr())
+                dev_go.group_form_result(ev)
+
             if go_method != "p2ps":
                 ev = dev_go.group_request("WPS_PIN any " + pin)
                 if ev is None:
                     raise Exception("Failed to initiate pin authorization on registrar side")
-            if "OK" not in dev_cli.global_request("P2P_CONNECT " + join_address + " " + pin + " " + cli_method + " persistent join"):
+            if join_ssid:
+                group_ssid_txt = " ssid=" + join_ssid
+            else:
+                group_ssid_txt = ""
+            if "OK" not in dev_cli.global_request("P2P_CONNECT " + join_address + " " + pin + " " + cli_method + join_extra + " persistent join" + group_ssid_txt):
                 raise Exception("P2P_CONNECT failed on " + dev_cli.p2p_dev_addr())
             ev = dev_cli.wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
             if ev is None:
@@ -362,12 +394,13 @@ def p2ps_connect_pd(dev0, dev1, ev0, ev1, pin=None):
 def set_no_group_iface(dev, enable):
     if enable:
         res = dev.get_driver_status()
-       if (int(res['capa.flags'], 0) & 0x20000000):
-           raise HwsimSkip("P2P Device used. Cannot set enable no_group_iface")
+        if (int(res['capa.flags'], 0) & 0x20000000):
+            raise HwsimSkip("P2P Device used. Cannot set enable no_group_iface")
         dev.global_request("SET p2p_no_group_iface 1")
     else:
         dev.global_request("SET p2p_no_group_iface 0")
 
+@remote_compatible
 def test_p2ps_exact_search(dev):
     """P2PS exact service request"""
     p2ps_advertise(r_dev=dev[0], r_role='1', svc_name='org.wi-fi.wfds.send.rx',
@@ -379,6 +412,7 @@ def test_p2ps_exact_search(dev):
     if ev0 is None:
         raise Exception("Unable to remove the advertisement instance")
 
+@remote_compatible
 def test_p2ps_exact_search_srvinfo(dev):
     """P2PS exact service request with service info"""
     p2ps_advertise(r_dev=dev[0], r_role='0', svc_name='org.wi-fi.wfds.send.rx',
@@ -391,6 +425,7 @@ def test_p2ps_exact_search_srvinfo(dev):
     if ev0 is None:
         raise Exception("Unable to remove the advertisement instance")
 
+@remote_compatible
 def test_p2ps_nonexact_search(dev):
     """P2PS nonexact seek request"""
     p2ps_advertise(r_dev=dev[0], r_role='0', svc_name='org.wi-fi.wfds.play.rx',
@@ -403,6 +438,7 @@ def test_p2ps_nonexact_search(dev):
     if ev0 is None:
         raise Exception("Unable to remove the advertisement instance")
 
+@remote_compatible
 def test_p2ps_nonexact_search_srvinfo(dev):
     """P2PS nonexact seek request with service info"""
     p2ps_advertise(r_dev=dev[0], r_role='0', svc_name='org.wi-fi.wfds.send.rx',
@@ -415,6 +451,7 @@ def test_p2ps_nonexact_search_srvinfo(dev):
     if ev0 is None:
         raise Exception("Unable to remove the advertisement instance")
 
+@remote_compatible
 def test_p2ps_connect_p2ps_method_nonautoaccept(dev):
     """P2PS connect for non-auto-accept and P2PS config method"""
     p2ps_advertise(r_dev=dev[0], r_role='0', svc_name='org.wi-fi.wfds.send.rx',
@@ -431,6 +468,7 @@ def test_p2ps_connect_p2ps_method_nonautoaccept(dev):
         raise Exception("Unable to remove the advertisement instance")
     remove_group(dev[0], dev[1])
 
+@remote_compatible
 def test_p2ps_connect_p2ps_method_autoaccept(dev):
     """P2PS connection with P2PS default config method and auto-accept"""
     p2ps_advertise(r_dev=dev[0], r_role='1', svc_name='org.wi-fi.wfds.send.rx',
@@ -447,6 +485,7 @@ def test_p2ps_connect_p2ps_method_autoaccept(dev):
         raise Exception("Unable to remove the advertisement instance")
     remove_group(dev[0], dev[1])
 
+@remote_compatible
 def test_p2ps_connect_keypad_method_nonautoaccept(dev):
     """P2PS Connection with non-auto-accept and seeker having keypad method"""
     p2ps_advertise(r_dev=dev[0], r_role='0', svc_name='org.wi-fi.wfds.send.rx',
@@ -464,6 +503,7 @@ def test_p2ps_connect_keypad_method_nonautoaccept(dev):
         raise Exception("Unable to remove the advertisement instance")
     remove_group(dev[0], dev[1])
 
+@remote_compatible
 def test_p2ps_connect_display_method_nonautoaccept(dev):
     """P2PS connection with non-auto-accept and seeker having display method"""
     p2ps_advertise(r_dev=dev[0], r_role='0', svc_name='org.wi-fi.wfds.send.rx',
@@ -480,6 +520,7 @@ def test_p2ps_connect_display_method_nonautoaccept(dev):
         raise Exception("Unable to remove the advertisement instance")
     remove_group(dev[0], dev[1])
 
+@remote_compatible
 def test_p2ps_connect_keypad_method_autoaccept(dev):
     """P2PS connection with auto-accept and keypad method on seeker side"""
     p2ps_advertise(r_dev=dev[0], r_role='1', svc_name='org.wi-fi.wfds.send.rx',
@@ -496,6 +537,7 @@ def test_p2ps_connect_keypad_method_autoaccept(dev):
         raise Exception("Unable to remove the advertisement instance")
     remove_group(dev[0], dev[1])
 
+@remote_compatible
 def test_p2ps_connect_display_method_autoaccept(dev):
     """P2PS connection with auto-accept and display method on seeker side"""
     p2ps_advertise(r_dev=dev[0], r_role='1', svc_name='org.wi-fi.wfds.send.rx',
@@ -512,6 +554,7 @@ def test_p2ps_connect_display_method_autoaccept(dev):
         raise Exception("Unable to remove the advertisement instance")
     remove_group(dev[0], dev[1])
 
+@remote_compatible
 def test_p2ps_connect_adv_go_p2ps_method(dev):
     """P2PS auto-accept connection with advertisement as GO and P2PS method"""
     p2ps_advertise(r_dev=dev[0], r_role='4', svc_name='org.wi-fi.wfds.send.rx',
@@ -528,6 +571,7 @@ def test_p2ps_connect_adv_go_p2ps_method(dev):
         raise Exception("Unable to remove the advertisement instance")
     remove_group(dev[0], dev[1])
 
+@remote_compatible
 def test_p2ps_connect_adv_go_p2ps_method_group_iface(dev):
     """P2PS auto-accept connection with advertisement as GO and P2PS method using separate group interface"""
     set_no_group_iface(dev[0], 0)
@@ -546,6 +590,7 @@ def test_p2ps_connect_adv_go_p2ps_method_group_iface(dev):
         raise Exception("Unable to remove the advertisement instance")
     remove_group(dev[0], dev[1])
 
+@remote_compatible
 def test_p2ps_connect_adv_client_p2ps_method(dev):
     """P2PS auto-accept connection with advertisement as Client and P2PS method"""
     p2ps_advertise(r_dev=dev[0], r_role='2', svc_name='org.wi-fi.wfds.send.rx',
@@ -577,10 +622,12 @@ def p2ps_connect_adv_go_pin_method(dev, keep_group=False):
             raise Exception("Unable to remove the advertisement instance")
         remove_group(dev[0], dev[1])
 
+@remote_compatible
 def test_p2ps_connect_adv_go_pin_method(dev):
     """P2PS advertiser as GO with keypad config method on seeker side and auto-accept"""
     p2ps_connect_adv_go_pin_method(dev)
 
+@remote_compatible
 def test_p2ps_connect_adv_client_pin_method(dev):
     """P2PS advertiser as client with keypad config method on seeker side and auto-accept"""
     dev[0].flush_scan_cache()
@@ -700,17 +747,30 @@ def get_ifnames():
         ifnames.append(ifname)
     return ifnames
 
-def p2ps_connect_p2ps_method(dev, keep_group=False):
-    dev[0].flush_scan_cache()
-    dev[1].flush_scan_cache()
+def p2ps_connect_p2ps_method(dev, keep_group=False, join_extra="", flush=True):
+    if flush:
+        dev[0].flush_scan_cache()
+        dev[1].flush_scan_cache()
     p2ps_advertise(r_dev=dev[0], r_role='2', svc_name='org.wi-fi.wfds.send.rx',
                    srv_info='I can receive files upto size 2 GB')
     [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
                                               svc_name='org.wi-fi.wfds.send.rx',
                                               srv_info='2 GB')
     ev1, ev0 = p2ps_provision(dev[1], dev[0], adv_id)
+    go_ev = None
+    if "join=" in ev0 and "go=" in ev1:
+        # dev[1] started GO and dev[0] is about to join it.
+        # Parse P2P-GROUP-STARTED from the GO to learn the operating frequency.
+        go_ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+        if go_ev is None:
+            raise Exception("P2P-GROUP-STARTED timeout on dev1")
+        res = dev[1].group_form_result(go_ev)
+        if join_extra == "":
+            join_extra = " freq=" + res['freq']
+        
     ifnames = get_ifnames()
-    p2ps_connect_pd(dev[0], dev[1], ev0, ev1)
+    p2ps_connect_pd(dev[0], dev[1], ev0, ev1, join_extra=join_extra,
+                    go_ev=go_ev)
 
     grp_ifname0 = dev[0].get_group_ifname()
     grp_ifname1 = dev[1].get_group_ifname()
@@ -778,9 +838,9 @@ def test_p2ps_connect_p2ps_method_4(dev):
 
     (grp_ifname0, grp_ifname1, ifnames) = p2ps_connect_p2ps_method(dev)
     if not grp_ifname0.startswith('p2p-' + dev[0].ifname + '-'):
-        raise Exception("unexpected dev0 group ifname: " + res0['ifname'])
+        raise Exception("unexpected dev0 group ifname: " + grp_ifname0)
     if not grp_ifname1.startswith('p2p-' + dev[1].ifname + '-'):
-        raise Exception("unexpected dev1 group ifname: " + res1['ifname'])
+        raise Exception("unexpected dev1 group ifname: " + grp_ifname1)
 
 def test_p2ps_connect_adv_go_persistent(dev):
     """P2PS auto-accept connection with advertisement as GO and having persistent group"""
@@ -801,6 +861,65 @@ def test_p2ps_connect_adv_go_persistent(dev):
     p2ps_connect_pd(dev[0], dev[1], ev0, ev1)
     remove_group(dev[0], dev[1])
 
+@remote_compatible
+def test_p2ps_adv_go_persistent_no_peer_entry(dev):
+    """P2PS advertisement as GO having persistent group (no peer entry)"""
+    go_neg_pin_authorized_persistent(i_dev=dev[0], i_intent=15,
+                                     r_dev=dev[1], r_intent=0)
+    dev[0].remove_group()
+    dev[1].wait_go_ending_session()
+
+    p2ps_advertise(r_dev=dev[0], r_role='4', svc_name='org.wi-fi.wfds.send.rx',
+                   srv_info='I can receive files upto size 2 GB')
+    [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                              svc_name='org.wi-fi.wfds.send.rx',
+                                              srv_info='2 GB')
+    dev[0].global_request("P2P_FLUSH")
+    dev[0].p2p_listen()
+    ev1, ev0 = p2ps_provision(dev[1], dev[0], adv_id)
+    if "persist=" not in ev0 or "persist=" not in ev1:
+        raise Exception("Persistent group isn't used by peers")
+
+@remote_compatible
+def test_p2ps_pd_follow_on_status_failure(dev):
+    """P2PS PD follow on request with status 11"""
+    addr0 = dev[0].p2p_dev_addr()
+    addr1 = dev[1].p2p_dev_addr()
+
+    p2ps_advertise(r_dev=dev[0], r_role='0', svc_name='org.wi-fi.wfds.send.rx',
+                   srv_info='I can receive files upto size 2 GB')
+    [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                              svc_name='org.wi-fi.wfds.send.rx',
+                                              srv_info='2 GB')
+    dev[1].asp_provision(addr0, adv_id=str(adv_id), adv_mac=addr0,
+                         session_id=1, session_mac=addr1)
+    ev_pd_start = dev[0].wait_global_event(["P2PS-PROV-START"], timeout=10)
+    if ev_pd_start is None:
+        raise Exception("P2PS-PROV-START timeout on Advertiser side")
+    ev = dev[1].wait_global_event(["P2P-PROV-DISC-FAILURE"], timeout=10)
+    if ev is None:
+        raise Exception("P2P-PROV-DISC-FAILURE timeout on seeker side")
+    dev[1].p2p_ext_listen(500, 500)
+    dev[0].p2p_stop_find()
+    dev[0].asp_provision(addr1, adv_id=str(adv_id), adv_mac=addr0, session_id=1,
+                         session_mac=addr1, status=11, method=0)
+
+    ev = dev[1].wait_global_event(["P2PS-PROV-DONE"], timeout=10)
+    if ev is None:
+        raise Exception("P2P-PROV-DONE timeout on seeker side")
+    if adv_id not in ev:
+        raise Exception("P2P-PROV-DONE without adv_id on seeker side")
+    if "status=11" not in ev:
+        raise Exception("P2P-PROV-DONE without status on seeker side")
+
+    ev = dev[0].wait_global_event(["P2PS-PROV-DONE"], timeout=10)
+    if ev is None:
+        raise Exception("P2P-PROV-DONE timeout on advertiser side")
+    if adv_id not in ev:
+        raise Exception("P2P-PROV-DONE without adv_id on advertiser side")
+    if "status=11" not in ev:
+        raise Exception("P2P-PROV-DONE without status on advertiser side")
+
 def test_p2ps_client_probe(dev):
     """P2PS CLI discoverability on operating channel"""
     cli_probe = dev[0].global_request("SET p2p_cli_probe 1")
@@ -820,6 +939,7 @@ def test_p2ps_go_probe(dev):
     dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
     remove_group(dev[0], dev[1])
 
+@remote_compatible
 def test_p2ps_wildcard_p2ps(dev):
     """P2PS wildcard SD Probe Request/Response"""
     p2ps_wildcard = "org.wi-fi.wfds"
@@ -948,36 +1068,509 @@ def p2ps_test_feature_capability_cpt(dev, adv_cpt, seeker_cpt, adv_role,
     if ev is None:
         raise Exception("Unable to remove the advertisement instance")
 
+@remote_compatible
 def test_p2ps_feature_capability_mac_autoaccept(dev):
     """P2PS PD Feature Capability CPT: advertiser MAC, seeker UDP:MAC, autoaccept"""
     p2ps_test_feature_capability_cpt(dev, adv_cpt="MAC", seeker_cpt="UDP:MAC",
                                      adv_role="4", result="MAC")
 
+@remote_compatible
 def test_p2ps_feature_capability_mac_nonautoaccept(dev):
     """P2PS PD Feature Capability CPT: advertiser:MAC, seeker UDP:MAC, nonautoaccept"""
     p2ps_test_feature_capability_cpt(dev, adv_cpt="MAC", seeker_cpt="UDP:MAC",
                                      adv_role="0", result="MAC")
 
+@remote_compatible
 def test_p2ps_feature_capability_mac_udp_autoaccept(dev):
     """P2PS PD Feature Capability CPT: advertiser MAC:UDP, seeker UDP:MAC, autoaccept"""
     p2ps_test_feature_capability_cpt(dev, adv_cpt="MAC:UDP",
                                      seeker_cpt="UDP:MAC", adv_role="2",
                                      result="MAC")
 
+@remote_compatible
 def test_p2ps_feature_capability_mac_udp_nonautoaccept(dev):
     """P2PS PD Feature Capability CPT: advertiser MAC:UDP, seeker UDP:MAC, nonautoaccept"""
     p2ps_test_feature_capability_cpt(dev, adv_cpt="MAC:UDP",
                                      seeker_cpt="UDP:MAC", adv_role="0",
                                      result="UDP")
 
+@remote_compatible
 def test_p2ps_feature_capability_udp_mac_autoaccept(dev):
     """P2PS PD Feature Capability CPT: advertiser UDP:MAC, seeker MAC:UDP, autoaccept"""
     p2ps_test_feature_capability_cpt(dev, adv_cpt="UDP:MAC",
                                      seeker_cpt="MAC:UDP", adv_role="2",
                                      result="UDP")
 
+@remote_compatible
 def test_p2ps_feature_capability_udp_mac_nonautoaccept(dev):
     """P2PS PD Feature Capability CPT: advertiser UDP:MAC, seeker MAC:UDP,  nonautoaccept"""
     p2ps_test_feature_capability_cpt(dev, adv_cpt="UDP:MAC",
                                      seeker_cpt="MAC:UDP", adv_role="0",
                                      result="MAC")
+
+def test_p2ps_channel_one_connected(dev, apdev):
+    """P2PS connection with P2PS method - one of the stations connected"""
+    set_no_group_iface(dev[0], 0)
+    set_no_group_iface(dev[1], 0)
+
+    try:
+        hapd = hostapd.add_ap(apdev[0],
+                              { "ssid": 'bss-2.4ghz', "channel": '7' })
+        dev[1].connect("bss-2.4ghz", key_mgmt="NONE", scan_freq="2442")
+
+        (grp_ifname0, grp_ifname1, ifnames) = p2ps_connect_p2ps_method(dev, keep_group=True, join_extra=" freq=2442")
+        freq = dev[0].get_group_status_field('freq')
+
+        if freq != '2442':
+            raise Exception('Unexpected frequency for group 2442 != ' + freq)
+    finally:
+        remove_group(dev[0], dev[1])
+        dev[0].global_request("P2P_SERVICE_DEL asp all")
+
+def set_random_listen_chan(dev):
+    chan = random.randrange(0, 3) * 5 + 1
+    dev.global_request("P2P_SET listen_channel %d" % chan)
+
+def test_p2ps_channel_both_connected_same(dev, apdev):
+    """P2PS connection with P2PS method - stations connected on same channel"""
+    set_no_group_iface(dev[2], 0)
+    set_no_group_iface(dev[1], 0)
+
+    dev[2].global_request("P2P_SET listen_channel 6")
+    dev[1].global_request("P2P_SET listen_channel 6")
+
+    dev[1].flush_scan_cache()
+    dev[2].flush_scan_cache()
+
+    try:
+        hapd = hostapd.add_ap(apdev[0],
+                              { "ssid": 'bss-2.4ghz', "channel": '6' })
+
+        dev[2].connect("bss-2.4ghz", key_mgmt="NONE", scan_freq="2437")
+        dev[1].connect("bss-2.4ghz", key_mgmt="NONE", scan_freq="2437")
+
+        tmpdev = [ dev[2], dev[1] ]
+        (grp_ifname0, grp_ifname1, ifnames) = p2ps_connect_p2ps_method(tmpdev, keep_group=True, join_extra=" freq=2437", flush=False)
+        freq = dev[2].get_group_status_field('freq')
+
+        if freq != '2437':
+            raise Exception('Unexpected frequency for group 2437 != ' + freq)
+    finally:
+        remove_group(dev[2], dev[1])
+        dev[2].global_request("P2P_SERVICE_DEL asp all")
+        for i in range(1, 3):
+            set_random_listen_chan(dev[i])
+
+def disconnect_handler(seeker, advertiser):
+    advertiser.request("DISCONNECT")
+    advertiser.wait_disconnected(timeout=1)
+
+def test_p2ps_channel_both_connected_different(dev, apdev):
+    """P2PS connection with P2PS method - stations connected on different channel"""
+    if dev[0].get_mcc() > 1:
+        raise HwsimSkip('Skip due to MCC being enabled')
+
+    set_no_group_iface(dev[0], 0)
+    set_no_group_iface(dev[1], 0)
+
+    try:
+        hapd1 = hostapd.add_ap(apdev[0],
+                               { "ssid": 'bss-channel-3', "channel": '3' })
+
+        hapd2 = hostapd.add_ap(apdev[1],
+                               { "ssid": 'bss-channel-10', "channel": '10' })
+
+        dev[0].connect("bss-channel-3", key_mgmt="NONE", scan_freq="2422")
+        dev[1].connect("bss-channel-10", key_mgmt="NONE", scan_freq="2457")
+
+        p2ps_advertise(r_dev=dev[0], r_role='2',
+                       svc_name='org.wi-fi.wfds.send.rx',
+                       srv_info='I can receive files upto size 2 GB')
+        [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                                  svc_name='org.wi-fi.wfds.send.rx',
+                                                  srv_info='2 GB')
+
+        ev1, ev0 = p2ps_provision(dev[1], dev[0], adv_id, auto_accept=False,
+                                  handler=disconnect_handler)
+        p2ps_connect_pd(dev[0], dev[1], ev0, ev1)
+        freq = dev[0].get_group_status_field('freq')
+        if freq != '2457':
+            raise Exception('Unexpected frequency for group 2457 != ' + freq)
+    finally:
+        remove_group(dev[0], dev[1])
+        dev[0].global_request("P2P_SERVICE_DEL asp all")
+
+def test_p2ps_channel_both_connected_different_mcc(dev, apdev):
+    """P2PS connection with P2PS method - stations connected on different channels with mcc"""
+    if dev[0].get_mcc() == 1:
+        raise HwsimSkip('Skip case due to MCC not enabled')
+
+    set_no_group_iface(dev[0], 0)
+    set_no_group_iface(dev[1], 0)
+
+    try:
+        hapd1 = hostapd.add_ap(apdev[0],
+                               { "ssid": 'bss-channel-3', "channel": '3' })
+
+        hapd2 = hostapd.add_ap(apdev[1],
+                               { "ssid": 'bss-channel-10', "channel": '10' })
+
+        dev[0].connect("bss-channel-3", key_mgmt="NONE", scan_freq="2422")
+        dev[1].connect("bss-channel-10", key_mgmt="NONE", scan_freq="2457")
+
+        (grp_ifname0, grp_ifname1, ifnames) = p2ps_connect_p2ps_method(dev, keep_group=True)
+        freq = dev[0].get_group_status_field('freq')
+
+        if freq != '2422' and freq != '2457':
+            raise Exception('Unexpected frequency for group =' + freq)
+    finally:
+        remove_group(dev[0], dev[1])
+        dev[0].global_request("P2P_SERVICE_DEL asp all")
+
+def clear_disallow_handler(seeker, advertiser):
+    advertiser.global_request("P2P_SET disallow_freq ")
+
+@remote_compatible
+def test_p2ps_channel_disallow_freq(dev, apdev):
+    """P2PS connection with P2PS method - disallow freqs"""
+    set_no_group_iface(dev[0], 0)
+    set_no_group_iface(dev[1], 0)
+
+    try:
+        dev[0].global_request("P2P_SET disallow_freq 2412-2457")
+        dev[1].global_request("P2P_SET disallow_freq 2417-2462")
+
+        p2ps_advertise(r_dev=dev[0], r_role='2',
+                       svc_name='org.wi-fi.wfds.send.rx',
+                       srv_info='I can receive files upto size 2 GB')
+
+        [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                                  svc_name='org.wi-fi.wfds.send.rx',
+                                                  srv_info='2 GB')
+
+        ev1, ev0 = p2ps_provision(dev[1], dev[0], adv_id, auto_accept=False,
+                                  handler=clear_disallow_handler)
+        p2ps_connect_pd(dev[0], dev[1], ev0, ev1)
+
+        freq = dev[0].get_group_status_field('freq')
+        if freq != '2412':
+            raise Exception('Unexpected frequency for group 2412 != ' + freq)
+    finally:
+        remove_group(dev[0], dev[1])
+        dev[0].global_request("P2P_SERVICE_DEL asp all")
+        dev[0].global_request("P2P_SET disallow_freq ")
+        dev[1].global_request("P2P_SET disallow_freq ")
+
+def test_p2ps_channel_sta_connected_disallow_freq(dev, apdev):
+    """P2PS connection with P2PS method - one station and disallow freqs"""
+    if dev[0].get_mcc() > 1:
+        raise HwsimSkip('Skip due to MCC being enabled')
+
+    set_no_group_iface(dev[0], 0)
+    set_no_group_iface(dev[1], 0)
+
+    try:
+        dev[0].global_request("P2P_SET disallow_freq 2437")
+        hapd = hostapd.add_ap(apdev[0],
+                              { "ssid": 'bss-channel-6', "channel": '6' })
+
+        dev[1].connect("bss-channel-6", key_mgmt="NONE", scan_freq="2437")
+
+        p2ps_advertise(r_dev=dev[0], r_role='2',
+                       svc_name='org.wi-fi.wfds.send.rx',
+                       srv_info='I can receive files upto size 2 GB')
+        [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                                  svc_name='org.wi-fi.wfds.send.rx',
+                                                  srv_info='2 GB')
+
+        ev1, ev0 = p2ps_provision(dev[1], dev[0], adv_id, auto_accept=False,
+                                  handler=clear_disallow_handler)
+        p2ps_connect_pd(dev[0], dev[1], ev0, ev1)
+
+        freq = dev[0].get_group_status_field('freq')
+        if freq != '2437':
+            raise Exception('Unexpected frequency for group 2437 != ' + freq)
+    finally:
+        remove_group(dev[0], dev[1])
+        dev[0].global_request("P2P_SET disallow_freq ")
+        dev[0].global_request("P2P_SERVICE_DEL asp all")
+
+def test_p2ps_channel_sta_connected_disallow_freq_mcc(dev, apdev):
+    """P2PS connection with P2PS method - one station and disallow freqs with mcc"""
+    with HWSimRadio(n_channels=2) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+
+        if wpas.get_mcc() < 2:
+            raise Exception("New radio does not support MCC")
+
+        set_no_group_iface(dev[0], 0)
+        set_no_group_iface(wpas, 0)
+
+        try:
+            dev[0].global_request("P2P_SET disallow_freq 2437")
+            hapd1 = hostapd.add_ap(apdev[0],
+                                   { "ssid": 'bss-channel-6', "channel": '6' })
+
+            wpas.connect("bss-channel-6", key_mgmt="NONE", scan_freq="2437")
+
+            tmpdev = [ dev[0], wpas ]
+            (grp_ifname0, grp_ifname1, ifnames) = p2ps_connect_p2ps_method(tmpdev, keep_group=True)
+
+            freq = dev[0].get_group_status_field('freq')
+            if freq == '2437':
+                raise Exception('Unexpected frequency=2437')
+        finally:
+            remove_group(dev[0], wpas)
+            dev[0].global_request("P2P_SET disallow_freq ")
+            dev[0].global_request("P2P_SERVICE_DEL asp all")
+
+@remote_compatible
+def test_p2ps_active_go_adv(dev, apdev):
+    """P2PS connection with P2PS method - active GO on advertiser"""
+    set_no_group_iface(dev[0], 0)
+    set_no_group_iface(dev[1], 0)
+
+    try:
+        # Add a P2P GO
+        dev[0].global_request("P2P_GROUP_ADD persistent")
+        ev = dev[0].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+        if ev is None:
+            raise Exception("P2P-GROUP-STARTED timeout on " + dev[0].p2p_dev_addr())
+
+        dev[0].group_form_result(ev)
+
+        p2ps_advertise(r_dev=dev[0], r_role='4',
+                       svc_name='org.wi-fi.wfds.send.rx',
+                       srv_info='I can receive files upto size 2 GB')
+        [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                                  svc_name='org.wi-fi.wfds.send.rx',
+                                                  single_peer_expected=False)
+
+        ev1, ev0 = p2ps_provision(dev[1], dev[0], adv_id)
+
+        # explicitly stop find/listen as otherwise the long listen started by
+        # the advertiser would prevent the seeker to connect with the P2P GO
+        dev[0].p2p_stop_find()
+        p2ps_connect_pd(dev[0], dev[1], ev0, ev1)
+    finally:
+        remove_group(dev[0], dev[1])
+        dev[0].global_request("P2P_SERVICE_DEL asp all")
+
+@remote_compatible
+def test_p2ps_active_go_seeker(dev, apdev):
+    """P2PS connection with P2PS method - active GO on seeker"""
+    set_no_group_iface(dev[0], 0)
+    set_no_group_iface(dev[1], 0)
+
+    try:
+        # Add a P2P GO on the seeker
+        dev[1].global_request("P2P_GROUP_ADD persistent")
+        ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+        if ev is None:
+            raise Exception("P2P-GROUP-STARTED timeout on " + dev[1].p2p_dev_addr())
+
+        res = dev[1].group_form_result(ev)
+
+        p2ps_advertise(r_dev=dev[0], r_role='2',
+                       svc_name='org.wi-fi.wfds.send.rx',
+                       srv_info='I can receive files upto size 2 GB')
+        [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                                  svc_name='org.wi-fi.wfds.send.rx',
+                                                  srv_info='2 GB')
+
+        ev1, ev0 = p2ps_provision(dev[1], dev[0], adv_id)
+        p2ps_connect_pd(dev[0], dev[1], ev0, ev1,
+                        join_extra=" freq=" + res['freq'])
+    finally:
+        remove_group(dev[0], dev[1])
+        dev[0].global_request("P2P_SERVICE_DEL asp all")
+
+def test_p2ps_channel_active_go_and_station_same(dev, apdev):
+    """P2PS connection, active P2P GO and station on channel"""
+    set_no_group_iface(dev[2], 0)
+    set_no_group_iface(dev[1], 0)
+
+    dev[2].global_request("P2P_SET listen_channel 11")
+    dev[1].global_request("P2P_SET listen_channel 11")
+    try:
+        hapd = hostapd.add_ap(apdev[0],
+                              { "ssid": 'bss-channel-11', "channel": '11' })
+
+        dev[2].connect("bss-channel-11", key_mgmt="NONE", scan_freq="2462")
+
+        # Add a P2P GO on the seeker
+        dev[1].global_request("P2P_GROUP_ADD freq=2462 persistent")
+        ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+        if ev is None:
+            raise Exception("P2P-GROUP-STARTED timeout on " + dev[1].p2p_dev_addr())
+
+        dev[1].group_form_result(ev)
+
+        p2ps_advertise(r_dev=dev[2], r_role='2',
+                       svc_name='org.wi-fi.wfds.send.rx',
+                       srv_info='I can receive files upto size 2 GB')
+        [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[2],
+                                                  svc_name='org.wi-fi.wfds.send.rx',
+                                                  srv_info='2 GB')
+
+        ev1, ev0 = p2ps_provision(dev[1], dev[2], adv_id)
+        p2ps_connect_pd(dev[2], dev[1], ev0, ev1, join_extra=" freq=2462")
+    finally:
+        remove_group(dev[2], dev[1])
+        dev[2].global_request("P2P_SERVICE_DEL asp all")
+        for i in range(1, 3):
+            set_random_listen_chan(dev[i])
+
+def test_p2ps_channel_active_go_and_station_different(dev, apdev):
+    """P2PS connection, active P2P GO and station on channel"""
+    if dev[0].get_mcc() > 1:
+        raise HwsimSkip('Skip due to MCC being enabled')
+
+    set_no_group_iface(dev[0], 0)
+    set_no_group_iface(dev[1], 0)
+
+    try:
+        hapd = hostapd.add_ap(apdev[0],
+                              { "ssid": 'bss-channel-2', "channel": '2' })
+
+        dev[0].connect("bss-channel-2", key_mgmt="NONE", scan_freq="2417")
+
+        # Add a P2P GO on the seeker. Force the listen channel to be the same,
+        # as extended listen will not kick as long as P2P GO is waiting for
+        # initial connection.
+        dev[1].global_request("P2P_SET listen_channel 11")
+        dev[1].global_request("P2P_GROUP_ADD freq=2462 persistent")
+        ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+        if ev is None:
+            raise Exception("P2P-GROUP-STARTED timeout on " + dev[1].p2p_dev_addr())
+
+        dev[1].group_form_result(ev)
+
+        p2ps_advertise(r_dev=dev[0], r_role='2',
+                       svc_name='org.wi-fi.wfds.send.rx',
+                       srv_info='I can receive files upto size 2 GB')
+        [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                                  svc_name='org.wi-fi.wfds.send.rx',
+                                                  srv_info='2 GB')
+
+        ev1, ev0 = p2ps_provision(dev[1], dev[0], adv_id, auto_accept=False,
+                                  handler=disconnect_handler, adv_role='2',
+                                  seeker_role='4')
+        p2ps_connect_pd(dev[0], dev[1], ev0, ev1)
+        freq = dev[0].get_group_status_field('freq')
+        if freq != '2462':
+            raise Exception('Unexpected frequency for group 2462!=' + freq)
+    finally:
+        dev[0].global_request("P2P_SERVICE_DEL asp all")
+        set_random_listen_chan(dev[1])
+
+@remote_compatible
+def test_p2ps_channel_active_go_and_station_different_mcc(dev, apdev):
+    """P2PS connection, active P2P GO and station on channel"""
+    if dev[0].get_mcc() == 1:
+        raise HwsimSkip('Skip due to MCC not being enabled')
+
+    set_no_group_iface(dev[0], 0)
+    set_no_group_iface(dev[1], 0)
+
+    try:
+        hapd = hostapd.add_ap(apdev[0],
+                              { "ssid": 'bss-channel-6', "channel": '6' })
+
+        dev[0].connect("bss-channel-6", key_mgmt="NONE", scan_freq="2437")
+
+        # Add a P2P GO on the seeker
+        dev[1].global_request("P2P_GROUP_ADD freq=2462 persistent")
+        ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=10)
+        if ev is None:
+            raise Exception("P2P-GROUP-STARTED timeout on " + dev[1].p2p_dev_addr())
+
+        dev[1].group_form_result(ev)
+
+        p2ps_advertise(r_dev=dev[0], r_role='2',
+                       svc_name='org.wi-fi.wfds.send.rx',
+                       srv_info='I can receive files upto size 2 GB')
+        [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[1], r_dev=dev[0],
+                                                  svc_name='org.wi-fi.wfds.send.rx',
+                                                  srv_info='2 GB')
+
+        ev1, ev0 = p2ps_provision(dev[1], dev[0], adv_id)
+        p2ps_connect_pd(dev[0], dev[1], ev0, ev1)
+    finally:
+        remove_group(dev[0], dev[1])
+        dev[0].request("DISCONNECT")
+        hapd.disable()
+        dev[0].global_request("P2P_SERVICE_DEL asp all")
+
+def test_p2ps_connect_p2p_device(dev):
+    """P2PS connection using cfg80211 P2P Device"""
+    run_p2ps_connect_p2p_device(dev, 0)
+
+def test_p2ps_connect_p2p_device_no_group_iface(dev):
+    """P2PS connection using cfg80211 P2P Device (no separate group interface)"""
+    run_p2ps_connect_p2p_device(dev, 1)
+
+def run_p2ps_connect_p2p_device(dev, no_group_iface):
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+        wpas.global_request("SET p2p_no_group_iface %d" % no_group_iface)
+
+        p2ps_advertise(r_dev=dev[0], r_role='1',
+                       svc_name='org.wi-fi.wfds.send.rx',
+                       srv_info='I can receive files upto size 2 GB')
+        [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=wpas, r_dev=dev[0],
+                                                  svc_name='org.wi-fi.wfds.send.rx',
+                                                  srv_info='2 GB')
+
+        ev1, ev0 = p2ps_provision(wpas, dev[0], adv_id)
+        p2ps_connect_pd(dev[0], wpas, ev0, ev1)
+
+        ev0 = dev[0].global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+        if ev0 is None:
+            raise Exception("Unable to remove the advertisement instance")
+        remove_group(dev[0], wpas)
+
+def test_p2ps_connect_p2p_device2(dev):
+    """P2PS connection using cfg80211 P2P Device (reverse)"""
+    run_p2ps_connect_p2p_device2(dev, 0)
+
+def test_p2ps_connect_p2p_device2_no_group_iface(dev):
+    """P2PS connection using cfg80211 P2P Device (reverse) (no separate group interface)"""
+    run_p2ps_connect_p2p_device2(dev, 1)
+
+def run_p2ps_connect_p2p_device2(dev, no_group_iface):
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+        wpas.global_request("SET p2p_no_group_iface %d" % no_group_iface)
+
+        p2ps_advertise(r_dev=wpas, r_role='1',
+                       svc_name='org.wi-fi.wfds.send.rx',
+                       srv_info='I can receive files upto size 2 GB')
+        [adv_id, rcvd_svc_name] = p2ps_exact_seek(i_dev=dev[0], r_dev=wpas,
+                                                  svc_name='org.wi-fi.wfds.send.rx',
+                                                  srv_info='2 GB')
+
+        ev1, ev0 = p2ps_provision(dev[0], wpas, adv_id)
+        p2ps_connect_pd(wpas, dev[0], ev0, ev1)
+
+        ev0 = wpas.global_request("P2P_SERVICE_DEL asp " + str(adv_id))
+        if ev0 is None:
+            raise Exception("Unable to remove the advertisement instance")
+        remove_group(wpas, dev[0])
+
+@remote_compatible
+def test_p2ps_connect_p2ps_method_no_pin(dev):
+    """P2P group formation using P2PS method without specifying PIN"""
+    dev[0].p2p_listen()
+    dev[1].p2p_go_neg_auth(dev[0].p2p_dev_addr(), None, "p2ps", go_intent=15)
+    dev[1].p2p_listen()
+    i_res = dev[0].p2p_go_neg_init(dev[1].p2p_dev_addr(), None, "p2ps",
+                                   timeout=20, go_intent=0)
+    r_res = dev[1].p2p_go_neg_auth_result()
+    logger.debug("i_res: " + str(i_res))
+    logger.debug("r_res: " + str(r_res))
+    check_grpform_results(i_res, r_res)
+    remove_group(dev[0], dev[1])
index aac4473..6f9b716 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 import time
@@ -13,13 +14,14 @@ import hostapd
 from utils import skip_with_fips
 from wlantest import Wlantest
 
+@remote_compatible
 def test_peerkey(dev, apdev):
     """RSN AP and PeerKey between two STAs"""
     ssid = "test-peerkey"
     passphrase = "12345678"
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     params['peerkey'] = "1"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412", peerkey=True)
     dev[1].connect(ssid, psk=passphrase, scan_freq="2412", peerkey=True)
@@ -38,7 +40,7 @@ def test_peerkey_unknown_peer(dev, apdev):
     passphrase = "12345678"
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     params['peerkey'] = "1"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412", peerkey=True)
     dev[1].connect(ssid, psk=passphrase, scan_freq="2412", peerkey=True)
@@ -47,18 +49,21 @@ def test_peerkey_unknown_peer(dev, apdev):
     dev[0].request("STKSTART " + dev[2].p2p_interface_addr())
     time.sleep(0.5)
 
+@remote_compatible
 def test_peerkey_pairwise_mismatch(dev, apdev):
     """RSN TKIP+CCMP AP and PeerKey between two STAs using different ciphers"""
     skip_with_fips(dev[0])
-    wt = Wlantest()
-    wt.flush()
-    wt.add_passphrase("12345678")
     ssid = "test-peerkey"
     passphrase = "12345678"
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
     params['peerkey'] = "1"
     params['rsn_pairwise'] = "TKIP CCMP"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    Wlantest.setup(hapd)
+    wt = Wlantest()
+    wt.flush()
+    wt.add_passphrase("12345678")
 
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412", peerkey=True,
                    pairwise="CCMP")
index 0899c84..e66cf17 100644 (file)
@@ -10,6 +10,7 @@ import subprocess
 import time
 
 import hostapd
+import hwsim_utils
 from wpasupplicant import WpaSupplicant
 from utils import alloc_fail
 from test_ap_eap import eap_connect
@@ -17,7 +18,7 @@ from test_ap_eap import eap_connect
 def test_pmksa_cache_on_roam_back(dev, apdev):
     """PMKSA cache to skip EAP on reassociation back to same AP"""
     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
     dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
                    eap="GPSK", identity="gpsk user",
@@ -29,7 +30,7 @@ def test_pmksa_cache_on_roam_back(dev, apdev):
     if pmksa['opportunistic'] != '0':
         raise Exception("Unexpected opportunistic PMKSA cache entry")
 
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
     bssid2 = apdev[1]['bssid']
 
     dev[0].dump_monitor()
@@ -78,10 +79,60 @@ def test_pmksa_cache_on_roam_back(dev, apdev):
     dev[0].wait_disconnected(timeout=5)
     dev[0].wait_connected(timeout=15, error="Reconnection timed out")
 
+def test_pmksa_cache_and_reauth(dev, apdev):
+    """PMKSA caching and EAPOL reauthentication"""
+    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+    dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
+                   eap="GPSK", identity="gpsk user",
+                   password="abcdefghijklmnop0123456789abcdef",
+                   scan_freq="2412")
+
+    hostapd.add_ap(apdev[1], params)
+    bssid2 = apdev[1]['bssid']
+
+    dev[0].dump_monitor()
+    logger.info("Roam to AP2")
+    # It can take some time for the second AP to become ready to reply to Probe
+    # Request frames especially under heavy CPU load, so allow couple of rounds
+    # of scanning to avoid reporting errors incorrectly just because of scans
+    # not having seen the target AP.
+    for i in range(0, 10):
+        dev[0].scan(freq="2412")
+        if dev[0].get_bss(bssid2) is not None:
+            break
+        logger.info("Scan again to find target AP")
+    dev[0].request("ROAM " + bssid2)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=10)
+    if ev is None:
+        raise Exception("EAP success timed out")
+    dev[0].wait_connected(timeout=10, error="Roaming timed out")
+
+    dev[0].dump_monitor()
+    logger.info("Roam back to AP1")
+    dev[0].scan(freq="2412")
+    dev[0].request("ROAM " + bssid)
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
+                            "CTRL-EVENT-CONNECTED"], timeout=10)
+    if ev is None:
+        raise Exception("Roaming with the AP timed out")
+    if "CTRL-EVENT-EAP-STARTED" in ev:
+        raise Exception("Unexpected EAP exchange")
+
+    # Verify EAPOL reauthentication after PMKSA caching
+    hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
+    if ev is None:
+        raise Exception("EAP authentication did not start")
+    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=5)
+    if ev is None:
+        raise Exception("EAP authentication did not succeed")
+
 def test_pmksa_cache_opportunistic_only_on_sta(dev, apdev):
     """Opportunistic PMKSA caching enabled only on station"""
     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
     dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
                    eap="GPSK", identity="gpsk user",
@@ -93,7 +144,7 @@ def test_pmksa_cache_opportunistic_only_on_sta(dev, apdev):
     if pmksa['opportunistic'] != '0':
         raise Exception("Unexpected opportunistic PMKSA cache entry")
 
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
     bssid2 = apdev[1]['bssid']
 
     dev[0].dump_monitor()
@@ -130,7 +181,7 @@ def test_pmksa_cache_opportunistic(dev, apdev):
     """Opportunistic PMKSA caching"""
     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
     params['okc'] = "1"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
     dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
                    eap="GPSK", identity="gpsk user",
@@ -142,7 +193,7 @@ def test_pmksa_cache_opportunistic(dev, apdev):
     if pmksa['opportunistic'] != '0':
         raise Exception("Unexpected opportunistic PMKSA cache entry")
 
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
     bssid2 = apdev[1]['bssid']
 
     dev[0].dump_monitor()
@@ -180,7 +231,7 @@ def test_pmksa_cache_opportunistic_connect(dev, apdev):
     """Opportunistic PMKSA caching with connect API"""
     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
     params['okc'] = "1"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
@@ -194,12 +245,12 @@ def test_pmksa_cache_opportunistic_connect(dev, apdev):
     if pmksa['opportunistic'] != '0':
         raise Exception("Unexpected opportunistic PMKSA cache entry")
 
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
     bssid2 = apdev[1]['bssid']
 
     wpas.dump_monitor()
     logger.info("Roam to AP2")
-    wpas.scan_for_bss(bssid2, freq="2412")
+    wpas.scan_for_bss(bssid2, freq="2412", force_scan=True)
     wpas.request("ROAM " + bssid2)
     ev = wpas.wait_event(["CTRL-EVENT-EAP-STARTED",
                             "CTRL-EVENT-CONNECTED"], timeout=10)
@@ -231,7 +282,7 @@ def test_pmksa_cache_opportunistic_connect(dev, apdev):
 def test_pmksa_cache_expiration(dev, apdev):
     """PMKSA cache entry expiration"""
     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
     dev[0].request("SET dot11RSNAConfigPMKLifetime 10")
     dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
@@ -255,7 +306,7 @@ def test_pmksa_cache_expiration(dev, apdev):
 def test_pmksa_cache_expiration_disconnect(dev, apdev):
     """PMKSA cache entry expiration (disconnect)"""
     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
     dev[0].request("SET dot11RSNAConfigPMKLifetime 2")
     dev[0].request("SET dot11RSNAConfigPMKReauthThreshold 100")
@@ -289,7 +340,7 @@ def test_pmksa_cache_and_cui(dev, apdev):
     params['acct_server_addr'] = "127.0.0.1"
     params['acct_server_port'] = "1813"
     params['acct_server_shared_secret'] = "radius"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
     dev[0].connect("cui", proto="RSN", key_mgmt="WPA-EAP",
                    eap="GPSK", identity="gpsk-cui",
@@ -331,22 +382,32 @@ def test_pmksa_cache_and_cui(dev, apdev):
     if state != "COMPLETED":
         raise Exception("Reauthentication did not complete")
 
-def test_pmksa_cache_preauth(dev, apdev):
-    """RSN pre-authentication to generate PMKSA cache entry"""
+def generic_pmksa_cache_preauth(dev, apdev, extraparams, identity, databridge,
+                                force_disconnect=False):
+    if not extraparams:
+        extraparams = [{}, {}]
     try:
         params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
         params['bridge'] = 'ap-br0'
-        hostapd.add_ap(apdev[0]['ifname'], params)
-        subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
-        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
-        eap_connect(dev[0], apdev[0], "PAX", "pax.user@example.com",
+        for key, value in extraparams[0].iteritems():
+            params[key] = value
+
+        hapd = hostapd.add_ap(apdev[0], params)
+        hapd.cmd_execute(['brctl', 'setfd', 'ap-br0', '0'])
+        hapd.cmd_execute(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
+        eap_connect(dev[0], hapd, "PAX", identity,
                     password_hex="0123456789abcdef0123456789abcdef")
 
+        # Verify connectivity in the correct VLAN
+        hwsim_utils.test_connectivity_iface(dev[0], hapd, databridge)
+
         params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
         params['bridge'] = 'ap-br0'
         params['rsn_preauth'] = '1'
-        params['rsn_preauth_interfaces'] = 'ap-br0'
-        hostapd.add_ap(apdev[1]['ifname'], params)
+        params['rsn_preauth_interfaces'] = databridge
+        for key, value in extraparams[1].iteritems():
+            params[key] = value
+        hostapd.add_ap(apdev[1], params)
         bssid1 = apdev[1]['bssid']
         dev[0].scan(freq="2412")
         success = False
@@ -382,133 +443,75 @@ def test_pmksa_cache_preauth(dev, apdev):
         if pmksa['pmkid'] != pmksa2['pmkid']:
             raise Exception("Unexpected PMKID change")
 
-    finally:
-        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'])
-        subprocess.call(['brctl', 'delbr', 'ap-br0'])
+        # Verify connectivity in the correct VLAN
+        hwsim_utils.test_connectivity_iface(dev[0], hapd, databridge)
 
-def test_pmksa_cache_preauth_vlan_enabled(dev, apdev):
-    """RSN pre-authentication to generate PMKSA cache entry (dynamic_vlan optional but station without VLAN set)"""
-    try:
-        params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-        params['bridge'] = 'ap-br0'
-        params['dynamic_vlan'] = '1'
-        hostapd.add_ap(apdev[0]['ifname'], params)
-        subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
-        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
-        eap_connect(dev[0], apdev[0], "PAX", "pax.user@example.com",
-                    password_hex="0123456789abcdef0123456789abcdef")
+        if not force_disconnect:
+            return
 
-        params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-        params['bridge'] = 'ap-br0'
-        params['rsn_preauth'] = '1'
-        params['rsn_preauth_interfaces'] = 'ap-br0'
-        params['dynamic_vlan'] = '1'
-        hostapd.add_ap(apdev[1]['ifname'], params)
-        bssid1 = apdev[1]['bssid']
-        dev[0].scan(freq="2412")
-        success = False
-        status_seen = False
-        for i in range(0, 50):
-            if not status_seen:
-                status = dev[0].request("STATUS")
-                if "Pre-authentication EAPOL state machines:" in status:
-                    status_seen = True
-            time.sleep(0.1)
-            pmksa = dev[0].get_pmksa(bssid1)
-            if pmksa:
-                success = True
-                break
-        if not success:
-            raise Exception("No PMKSA cache entry created from pre-authentication")
-        if not status_seen:
-            raise Exception("Pre-authentication EAPOL status was not available")
-
-        dev[0].scan(freq="2412")
-        if "[WPA2-EAP-CCMP-preauth]" not in dev[0].request("SCAN_RESULTS"):
-            raise Exception("Scan results missing RSN element info")
-        dev[0].request("ROAM " + bssid1)
-        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
-                                "CTRL-EVENT-CONNECTED"], timeout=10)
-        if ev is None:
-            raise Exception("Roaming with the AP timed out")
-        if "CTRL-EVENT-EAP-STARTED" in ev:
-            raise Exception("Unexpected EAP exchange")
-        pmksa2 = dev[0].get_pmksa(bssid1)
-        if pmksa2 is None:
-            raise Exception("No PMKSA cache entry")
-        if pmksa['pmkid'] != pmksa2['pmkid']:
-            raise Exception("Unexpected PMKID change")
+        # Disconnect the STA from both APs to avoid forceful ifdown by the
+        # test script on a VLAN that this has an associated STA. That used to
+        # trigger a mac80211 warning.
+        dev[0].request("DISCONNECT")
+        hapd.request("DISABLE")
 
     finally:
-        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'])
-        subprocess.call(['brctl', 'delbr', 'ap-br0'])
+        hostapd.cmd_execute(apdev[0], ['ip', 'link', 'set', 'dev',
+                                       'ap-br0', 'down', '2>', '/dev/null'],
+                            shell=True)
+        hostapd.cmd_execute(apdev[0], ['brctl', 'delbr', 'ap-br0',
+                                       '2>', '/dev/null'], shell=True)
+
+def test_pmksa_cache_preauth(dev, apdev):
+    """RSN pre-authentication to generate PMKSA cache entry"""
+    generic_pmksa_cache_preauth(dev, apdev, None,
+                                "pax.user@example.com", "ap-br0")
+
+def test_pmksa_cache_preauth_per_sta_vif(dev, apdev):
+    """RSN pre-authentication to generate PMKSA cache entry with per_sta_vif"""
+    extraparams = [{}, {}]
+    extraparams[0]['per_sta_vif'] = "1"
+    extraparams[1]['per_sta_vif'] = "1"
+    generic_pmksa_cache_preauth(dev, apdev, extraparams,
+                                "pax.user@example.com", "ap-br0")
+
+def test_pmksa_cache_preauth_vlan_enabled(dev, apdev):
+    """RSN pre-authentication to generate PMKSA cache entry (dynamic_vlan optional but station without VLAN set)"""
+    extraparams = [{}, {}]
+    extraparams[0]['dynamic_vlan'] = '1'
+    extraparams[1]['dynamic_vlan'] = '1'
+    generic_pmksa_cache_preauth(dev, apdev, extraparams,
+                                "pax.user@example.com", "ap-br0")
+
+def test_pmksa_cache_preauth_vlan_enabled_per_sta_vif(dev, apdev):
+    """RSN pre-authentication to generate PMKSA cache entry (dynamic_vlan optional but station without VLAN set, with per_sta_vif enabled)"""
+    extraparams = [{}, {}]
+    extraparams[0]['per_sta_vif'] = "1"
+    extraparams[1]['per_sta_vif'] = "1"
+    extraparams[0]['dynamic_vlan'] = '1'
+    extraparams[1]['dynamic_vlan'] = '1'
+    generic_pmksa_cache_preauth(dev, apdev, extraparams,
+                                "pax.user@example.com", "ap-br0")
 
 def test_pmksa_cache_preauth_vlan_used(dev, apdev):
     """RSN pre-authentication to generate PMKSA cache entry (station with VLAN set)"""
+    run_pmksa_cache_preauth_vlan_used(dev, apdev, None, force_disconnect=True)
+
+def run_pmksa_cache_preauth_vlan_used(dev, apdev, extraparams=None,
+                                      force_disconnect=False):
     try:
         subprocess.call(['brctl', 'addbr', 'brvlan1'])
         subprocess.call(['brctl', 'setfd', 'brvlan1', '0'])
-        params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-        params['bridge'] = 'ap-br0'
-        params['dynamic_vlan'] = '1'
-        params['vlan_file'] = 'hostapd.wlan3.vlan'
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
-        subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
-        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
-        eap_connect(dev[0], apdev[0], "PAX", "vlan1",
-                    password_hex="0123456789abcdef0123456789abcdef")
-
-        params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-        params['bridge'] = 'ap-br0'
-        params['rsn_preauth'] = '1'
-        params['rsn_preauth_interfaces'] = 'brvlan1'
-        params['dynamic_vlan'] = '1'
-        params['vlan_file'] = 'hostapd.wlan4.vlan'
-        hostapd.add_ap(apdev[1]['ifname'], params)
-        bssid1 = apdev[1]['bssid']
-        dev[0].scan(freq="2412")
-        success = False
-        status_seen = False
-        for i in range(0, 50):
-            if not status_seen:
-                status = dev[0].request("STATUS")
-                if "Pre-authentication EAPOL state machines:" in status:
-                    status_seen = True
-            time.sleep(0.1)
-            pmksa = dev[0].get_pmksa(bssid1)
-            if pmksa:
-                success = True
-                break
-        if not success:
-            raise Exception("No PMKSA cache entry created from pre-authentication")
-        if not status_seen:
-            raise Exception("Pre-authentication EAPOL status was not available")
-
-        dev[0].scan(freq="2412")
-        if "[WPA2-EAP-CCMP-preauth]" not in dev[0].request("SCAN_RESULTS"):
-            raise Exception("Scan results missing RSN element info")
-        dev[0].request("ROAM " + bssid1)
-        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
-                                "CTRL-EVENT-CONNECTED"], timeout=10)
-        if ev is None:
-            raise Exception("Roaming with the AP timed out")
-        if "CTRL-EVENT-EAP-STARTED" in ev:
-            raise Exception("Unexpected EAP exchange")
-        pmksa2 = dev[0].get_pmksa(bssid1)
-        if pmksa2 is None:
-            raise Exception("No PMKSA cache entry")
-        if pmksa['pmkid'] != pmksa2['pmkid']:
-            raise Exception("Unexpected PMKID change")
-
-        # Disconnect the STA from both APs to avoid forceful ifdown by the
-        # test script on a VLAN that this has an associated STA. That used to
-        # trigger a mac80211 warning.
-        dev[0].request("DISCONNECT")
-        hapd.request("DISABLE")
-
+        if not extraparams:
+            extraparams = [{}, {}]
+        extraparams[0]['dynamic_vlan'] = '1'
+        extraparams[0]['vlan_file'] = 'hostapd.wlan3.vlan'
+        extraparams[1]['dynamic_vlan'] = '1'
+        extraparams[1]['vlan_file'] = 'hostapd.wlan4.vlan'
+        generic_pmksa_cache_preauth(dev, apdev, extraparams,
+                                    "vlan1", "brvlan1",
+                                    force_disconnect=force_disconnect)
     finally:
-        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
-                        stderr=open('/dev/null', 'w'))
         subprocess.call(['ip', 'link', 'set', 'dev', 'brvlan1', 'down'])
         subprocess.call(['ip', 'link', 'set', 'dev', 'wlan3.1', 'down'],
                         stderr=open('/dev/null', 'w'))
@@ -518,22 +521,27 @@ def test_pmksa_cache_preauth_vlan_used(dev, apdev):
                         stderr=open('/dev/null', 'w'))
         subprocess.call(['brctl', 'delif', 'brvlan1', 'wlan4.1'],
                         stderr=open('/dev/null', 'w'))
-        subprocess.call(['brctl', 'delbr', 'ap-br0'],
-                        stderr=open('/dev/null', 'w'))
         subprocess.call(['brctl', 'delbr', 'brvlan1'])
 
+def test_pmksa_cache_preauth_vlan_used_per_sta_vif(dev, apdev):
+    """RSN pre-authentication to generate PMKSA cache entry (station with VLAN set, per_sta_vif=1)"""
+    extraparams = [{}, {}]
+    extraparams[0]['per_sta_vif'] = "1"
+    extraparams[1]['per_sta_vif'] = "1"
+    run_pmksa_cache_preauth_vlan_used(dev, apdev, extraparams)
+
 def test_pmksa_cache_disabled(dev, apdev):
     """PMKSA cache disabling on AP"""
     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
     params['disable_pmksa_caching'] = '1'
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
     dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
                    eap="GPSK", identity="gpsk user",
                    password="abcdefghijklmnop0123456789abcdef",
                    scan_freq="2412")
 
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
     bssid2 = apdev[1]['bssid']
 
     dev[0].dump_monitor()
@@ -562,7 +570,7 @@ def test_pmksa_cache_disabled(dev, apdev):
 def test_pmksa_cache_ap_expiration(dev, apdev):
     """PMKSA cache entry expiring on AP"""
     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
     dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
                    eap="GPSK", identity="gpsk-user-session-timeout",
@@ -589,8 +597,10 @@ def test_pmksa_cache_ap_expiration(dev, apdev):
 def test_pmksa_cache_multiple_sta(dev, apdev):
     """PMKSA cache with multiple stations"""
     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
+    for d in dev:
+        d.flush_scan_cache()
     dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
                    eap="GPSK", identity="gpsk-user-session-timeout",
                    password="abcdefghijklmnop0123456789abcdef",
@@ -606,23 +616,26 @@ def test_pmksa_cache_multiple_sta(dev, apdev):
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5")
+    wpas.flush_scan_cache()
     wpas.connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
                  eap="GPSK", identity="gpsk user",
                  password="abcdefghijklmnop0123456789abcdef",
                  scan_freq="2412")
 
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
     bssid2 = apdev[1]['bssid']
 
     logger.info("Roam to AP2")
     for sta in [ dev[1], dev[0], dev[2], wpas ]:
         sta.dump_monitor()
         sta.scan_for_bss(bssid2, freq="2412")
-        sta.request("ROAM " + bssid2)
+        if "OK" not in sta.request("ROAM " + bssid2):
+            raise Exception("ROAM command failed (" + sta.ifname + ")")
         ev = sta.wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=10)
         if ev is None:
             raise Exception("EAP success timed out")
         sta.wait_connected(timeout=10, error="Roaming timed out")
+        sta.dump_monitor()
 
     logger.info("Roam back to AP1")
     for sta in [ dev[1], wpas, dev[0], dev[2] ]:
@@ -648,17 +661,20 @@ def test_pmksa_cache_opportunistic_multiple_sta(dev, apdev):
     """Opportunistic PMKSA caching with multiple stations"""
     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
     params['okc'] = "1"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
+    for d in dev:
+        d.flush_scan_cache()
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5")
+    wpas.flush_scan_cache()
     for sta in [ dev[0], dev[1], dev[2], wpas ]:
         sta.connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
                     eap="GPSK", identity="gpsk user",
                     password="abcdefghijklmnop0123456789abcdef", okc=True,
                     scan_freq="2412")
 
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
     bssid2 = apdev[1]['bssid']
 
     logger.info("Roam to AP2")
@@ -676,6 +692,7 @@ def test_pmksa_cache_opportunistic_multiple_sta(dev, apdev):
         pmksa2 = sta.get_pmksa(bssid2)
         if pmksa2 is None:
             raise Exception("No PMKSA cache entry created")
+        sta.dump_monitor()
 
     logger.info("Roam back to AP1")
     for sta in [ dev[0], dev[1], dev[2], wpas ]:
@@ -694,16 +711,17 @@ def test_pmksa_cache_preauth_oom(dev, apdev):
     try:
         _test_pmksa_cache_preauth_oom(dev, apdev)
     finally:
-        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'])
-        subprocess.call(['brctl', 'delbr', 'ap-br0'])
+        hostapd.cmd_execute(apdev[0], ['ip', 'link', 'set', 'dev', 'ap-br0',
+                                       'down'])
+        hostapd.cmd_execute(apdev[0], ['brctl', 'delbr', 'ap-br0'])
 
 def _test_pmksa_cache_preauth_oom(dev, apdev):
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
     params['bridge'] = 'ap-br0'
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
-    subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
-    eap_connect(dev[0], apdev[0], "PAX", "pax.user@example.com",
+    hapd = hostapd.add_ap(apdev[0], params)
+    hostapd.cmd_execute(apdev[0], ['brctl', 'setfd', 'ap-br0', '0'])
+    hostapd.cmd_execute(apdev[0], ['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
+    eap_connect(dev[0], hapd, "PAX", "pax.user@example.com",
                 password_hex="0123456789abcdef0123456789abcdef",
                 bssid=apdev[0]['bssid'])
 
@@ -711,7 +729,7 @@ def _test_pmksa_cache_preauth_oom(dev, apdev):
     params['bridge'] = 'ap-br0'
     params['rsn_preauth'] = '1'
     params['rsn_preauth_interfaces'] = 'ap-br0'
-    hapd = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[1], params)
     bssid1 = apdev[1]['bssid']
 
     tests = [ (1, "rsn_preauth_receive"),
@@ -749,7 +767,7 @@ def test_pmksa_cache_size_limit(dev, apdev):
         _test_pmksa_cache_size_limit(dev, apdev)
     finally:
         try:
-            hapd = hostapd.HostapdGlobal()
+            hapd = hostapd.HostapdGlobal(apdev[0])
             hapd.flush()
             hapd.remove(apdev[0]['ifname'])
         except:
@@ -757,7 +775,7 @@ def test_pmksa_cache_size_limit(dev, apdev):
         params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
         bssid = apdev[0]['bssid']
         params['bssid'] = bssid
-        hostapd.add_ap(apdev[0]['ifname'], params)
+        hostapd.add_ap(apdev[0], params)
 
 def _test_pmksa_cache_size_limit(dev, apdev):
     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
@@ -769,7 +787,7 @@ def _test_pmksa_cache_size_limit(dev, apdev):
         bssid = apdev[0]['bssid'][0:15] + "%02x" % i
         logger.info("Iteration with BSSID " + bssid)
         params['bssid'] = bssid
-        hostapd.add_ap(apdev[0]['ifname'], params)
+        hostapd.add_ap(apdev[0], params)
         dev[0].request("BSS_FLUSH 0")
         dev[0].scan_for_bss(bssid, freq=2412, only_new=True)
         dev[0].select_network(id)
@@ -784,7 +802,7 @@ def _test_pmksa_cache_size_limit(dev, apdev):
         elif i + 1 != entries:
             raise Exception("Unexpected number of PMKSA entries")
 
-        hapd = hostapd.HostapdGlobal()
+        hapd = hostapd.HostapdGlobal(apdev[0])
         hapd.flush()
         hapd.remove(apdev[0]['ifname'])
 
@@ -798,8 +816,8 @@ def test_pmksa_cache_preauth_timeout(dev, apdev):
 def _test_pmksa_cache_preauth_timeout(dev, apdev):
     dev[0].request("SET dot11RSNAConfigSATimeout 1")
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "PAX", "pax.user@example.com",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "PAX", "pax.user@example.com",
                 password_hex="0123456789abcdef0123456789abcdef",
                 bssid=apdev[0]['bssid'])
     if "OK" not in dev[0].request("PREAUTH f2:11:22:33:44:55"):
@@ -813,8 +831,8 @@ def _test_pmksa_cache_preauth_timeout(dev, apdev):
 def test_pmksa_cache_preauth_wpas_oom(dev, apdev):
     """RSN pre-authentication OOM in wpa_supplicant"""
     params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    eap_connect(dev[0], apdev[0], "PAX", "pax.user@example.com",
+    hapd = hostapd.add_ap(apdev[0], params)
+    eap_connect(dev[0], hapd, "PAX", "pax.user@example.com",
                 password_hex="0123456789abcdef0123456789abcdef",
                 bssid=apdev[0]['bssid'])
     for i in range(1, 11):
@@ -826,3 +844,46 @@ def test_pmksa_cache_preauth_wpas_oom(dev, apdev):
                 if state.startswith('0:'):
                     break
                 time.sleep(0.05)
+
+def test_pmksa_cache_ctrl(dev, apdev):
+    """PMKSA cache control interface operations"""
+    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+    addr = dev[0].own_addr()
+
+    dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
+                   eap="GPSK", identity="gpsk user",
+                   password="abcdefghijklmnop0123456789abcdef",
+                   scan_freq="2412")
+
+    pmksa_sta = dev[0].get_pmksa(bssid)
+    if pmksa_sta is None:
+        raise Exception("No PMKSA cache entry created on STA")
+    pmksa_ap = hapd.get_pmksa(addr)
+    if pmksa_ap is None:
+        raise Exception("No PMKSA cache entry created on AP")
+    if pmksa_sta['pmkid'] != pmksa_ap['pmkid']:
+        raise Exception("PMKID mismatch in PMKSA cache entries")
+
+    if "OK" not in hapd.request("PMKSA_FLUSH"):
+        raise Exception("PMKSA_FLUSH failed")
+    pmksa_ap = hapd.get_pmksa(addr)
+    if pmksa_ap is not None:
+        raise Exception("PMKSA cache entry was not removed on AP")
+
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+    dev[0].request("RECONNECT")
+    dev[0].wait_connected()
+
+    pmksa_sta2 = dev[0].get_pmksa(bssid)
+    if pmksa_sta2 is None:
+        raise Exception("No PMKSA cache entry created on STA after reconnect")
+    pmksa_ap2 = hapd.get_pmksa(addr)
+    if pmksa_ap2 is None:
+        raise Exception("No PMKSA cache entry created on AP after reconnect")
+    if pmksa_sta2['pmkid'] != pmksa_ap2['pmkid']:
+        raise Exception("PMKID mismatch in PMKSA cache entries after reconnect")
+    if pmksa_sta2['pmkid'] == pmksa_sta['pmkid']:
+        raise Exception("PMKID did not change after reconnect")
index 83eb8f4..1369cf2 100644 (file)
@@ -7,7 +7,6 @@
 import time
 import logging
 logger = logging.getLogger()
-import subprocess
 
 import hostapd
 from wpasupplicant import WpaSupplicant
@@ -71,9 +70,9 @@ def test_ext_radio_work(dev, apdev):
     if ev is None:
         raise Exception("Timeout while waiting radio work to start")
     if "FAIL" not in dev[0].request("RADIO_WORK done 12345678"):
-        raise Exception("Invalid RADIO_WORK done accepted");
+        raise Exception("Invalid RADIO_WORK done accepted")
     if "FAIL" not in dev[0].request("RADIO_WORK foo"):
-        raise Exception("Invalid RADIO_WORK accepted");
+        raise Exception("Invalid RADIO_WORK accepted")
     dev[0].request("FLUSH")
     items = dev[0].request("RADIO_WORK show")
     if items != "":
@@ -82,7 +81,7 @@ def test_ext_radio_work(dev, apdev):
 def test_radio_work_cancel(dev, apdev):
     """Radio work items cancelled on interface removal"""
     params = hostapd.wpa2_params(ssid="radio", passphrase="12345678")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5")
     wpas.scan(freq="2412")
index 662285c..db84899 100644 (file)
@@ -1,9 +1,11 @@
 # RADIUS tests
-# Copyright (c) 2013-2015, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2013-2016, Jouni Malinen <j@w1.fi>
 #
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
+import binascii
 import hashlib
 import hmac
 import logging
@@ -16,7 +18,9 @@ import threading
 import time
 
 import hostapd
-from utils import HwsimSkip, require_under_vm
+from utils import HwsimSkip, require_under_vm, skip_with_fips, fail_test
+from test_ap_hs20 import build_dhcp_ack
+from test_ap_ft import ft_params1
 
 def connect(dev, ssid, wait_connect=True):
     dev.connect(ssid, key_mgmt="WPA-EAP", scan_freq="2412",
@@ -24,12 +28,12 @@ def connect(dev, ssid, wait_connect=True):
                 password_hex="0123456789abcdef0123456789abcdef",
                 wait_connect=wait_connect)
 
+@remote_compatible
 def test_radius_auth_unreachable(dev, apdev):
     """RADIUS Authentication server unreachable"""
     params = hostapd.wpa2_eap_params(ssid="radius-auth")
     params['auth_server_port'] = "18139"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     connect(dev[0], "radius-auth", wait_connect=False)
     ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"])
     if ev is None:
@@ -50,8 +54,7 @@ def test_radius_auth_unreachable2(dev, apdev):
     params = hostapd.wpa2_eap_params(ssid="radius-auth")
     params['auth_server_addr'] = "192.168.213.17"
     params['auth_server_port'] = "18139"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     subprocess.call(['ip', 'ro', 'del', '192.168.213.17', 'dev', 'lo'])
     connect(dev[0], "radius-auth", wait_connect=False)
     ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"])
@@ -70,8 +73,7 @@ def test_radius_auth_unreachable3(dev, apdev):
     subprocess.call(['ip', 'ro', 'replace', 'blackhole', '192.168.213.18'])
     params = hostapd.wpa2_eap_params(ssid="radius-auth")
     params['auth_server_addr'] = "192.168.213.18"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     connect(dev[0], "radius-auth", wait_connect=False)
     ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"])
     if ev is None:
@@ -90,8 +92,7 @@ def test_radius_acct_unreachable(dev, apdev):
     params['acct_server_addr'] = "127.0.0.1"
     params['acct_server_port'] = "18139"
     params['acct_server_shared_secret'] = "radius"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     connect(dev[0], "radius-acct")
     logger.info("Checking for RADIUS retries")
     time.sleep(4)
@@ -110,8 +111,7 @@ def test_radius_acct_unreachable2(dev, apdev):
     params['acct_server_addr'] = "192.168.213.17"
     params['acct_server_port'] = "18139"
     params['acct_server_shared_secret'] = "radius"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     subprocess.call(['ip', 'ro', 'del', '192.168.213.17', 'dev', 'lo'])
     connect(dev[0], "radius-acct")
     logger.info("Checking for RADIUS retries")
@@ -132,8 +132,7 @@ def test_radius_acct_unreachable3(dev, apdev):
     params['acct_server_addr'] = "192.168.213.18"
     params['acct_server_port'] = "1813"
     params['acct_server_shared_secret'] = "radius"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     connect(dev[0], "radius-acct")
     subprocess.call(['ip', 'ro', 'del', 'blackhole', '192.168.213.18'])
     time.sleep(0.1)
@@ -154,8 +153,7 @@ def test_radius_acct_unreachable4(dev, apdev):
     params['acct_server_addr'] = "127.0.0.1"
     params['acct_server_port'] = "18139"
     params['acct_server_shared_secret'] = "radius"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     for i in range(20):
         connect(dev[0], "radius-acct")
         dev[0].request("REMOVE_NETWORK all")
@@ -171,8 +169,7 @@ def test_radius_acct(dev, apdev):
     params['acct_server_shared_secret'] = "radius"
     params['radius_auth_req_attr'] = [ "126:s:Operator", "77:s:testing" ]
     params['radius_acct_req_attr'] = [ "126:s:Operator", "77:s:testing" ]
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     connect(dev[0], "radius-acct")
     dev[1].connect("radius-acct", key_mgmt="WPA-EAP", scan_freq="2412",
                    eap="PAX", identity="test-class",
@@ -207,6 +204,19 @@ def test_radius_acct(dev, apdev):
     if acc_e < acc_s + 1:
         raise Exception("Unexpected RADIUS server auth MIB value")
 
+def test_radius_acct_non_ascii_ssid(dev, apdev):
+    """RADIUS Accounting and non-ASCII SSID"""
+    params = hostapd.wpa2_eap_params()
+    params['acct_server_addr'] = "127.0.0.1"
+    params['acct_server_port'] = "1813"
+    params['acct_server_shared_secret'] = "radius"
+    ssid2 = "740665007374"
+    params['ssid2'] = ssid2
+    hostapd.add_ap(apdev[0], params)
+    dev[0].connect(ssid2=ssid2, key_mgmt="WPA-EAP", scan_freq="2412",
+                   eap="PSK", identity="psk.user@example.com",
+                   password_hex="0123456789abcdef0123456789abcdef")
+
 def test_radius_acct_pmksa_caching(dev, apdev):
     """RADIUS Accounting with PMKSA caching"""
     as_hapd = hostapd.Hostapd("as")
@@ -215,7 +225,7 @@ def test_radius_acct_pmksa_caching(dev, apdev):
     params['acct_server_addr'] = "127.0.0.1"
     params['acct_server_port'] = "1813"
     params['acct_server_shared_secret'] = "radius"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     connect(dev[0], "radius-acct")
     dev[1].connect("radius-acct", key_mgmt="WPA-EAP", scan_freq="2412",
                    eap="PAX", identity="test-class",
@@ -257,8 +267,7 @@ def test_radius_acct_interim(dev, apdev):
     params['acct_server_port'] = "1813"
     params['acct_server_shared_secret'] = "radius"
     params['radius_acct_interim_interval'] = "1"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
     connect(dev[0], "radius-acct")
     logger.info("Checking for RADIUS counters")
     as_mib_start = as_hapd.get_mib(param="radius_server")
@@ -276,7 +285,7 @@ def test_radius_acct_interim_unreachable(dev, apdev):
     params['acct_server_port'] = "18139"
     params['acct_server_shared_secret'] = "radius"
     params['radius_acct_interim_interval'] = "1"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     start = hapd.get_mib()
     connect(dev[0], "radius-acct")
     logger.info("Waiting for interium accounting updates")
@@ -287,6 +296,68 @@ def test_radius_acct_interim_unreachable(dev, apdev):
     if req_e < req_s + 2:
         raise Exception("Unexpected RADIUS server acct MIB value")
 
+def test_radius_acct_interim_unreachable2(dev, apdev):
+    """RADIUS Accounting interim update with unreachable server (retry)"""
+    params = hostapd.wpa2_eap_params(ssid="radius-acct")
+    params['acct_server_addr'] = "127.0.0.1"
+    params['acct_server_port'] = "18139"
+    params['acct_server_shared_secret'] = "radius"
+    # Use long enough interim update interval to allow RADIUS retransmission
+    # case (3 seconds) to trigger first.
+    params['radius_acct_interim_interval'] = "4"
+    hapd = hostapd.add_ap(apdev[0], params)
+    start = hapd.get_mib()
+    connect(dev[0], "radius-acct")
+    logger.info("Waiting for interium accounting updates")
+    time.sleep(7.5)
+    end = hapd.get_mib()
+    req_s = int(start['radiusAccClientTimeouts'])
+    req_e = int(end['radiusAccClientTimeouts'])
+    if req_e < req_s + 2:
+        raise Exception("Unexpected RADIUS server acct MIB value")
+
+def test_radius_acct_ipaddr(dev, apdev):
+    """RADIUS Accounting and Framed-IP-Address"""
+    try:
+        _test_radius_acct_ipaddr(dev, apdev)
+    finally:
+        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
+                        stderr=open('/dev/null', 'w'))
+        subprocess.call(['brctl', 'delbr', 'ap-br0'],
+                        stderr=open('/dev/null', 'w'))
+
+def _test_radius_acct_ipaddr(dev, apdev):
+    params = { "ssid": "radius-acct-open",
+               'acct_server_addr': "127.0.0.1",
+               'acct_server_port': "1813",
+               'acct_server_shared_secret': "radius",
+               'proxy_arp': '1',
+               'ap_isolate': '1',
+               'bridge': 'ap-br0' }
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
+    try:
+        hapd.enable()
+    except:
+        # For now, do not report failures due to missing kernel support
+        raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
+    bssid = apdev[0]['bssid']
+
+    subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
+    subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
+
+    dev[0].connect("radius-acct-open", key_mgmt="NONE", scan_freq="2412")
+    addr0 = dev[0].own_addr()
+
+    pkt = build_dhcp_ack(dst_ll="ff:ff:ff:ff:ff:ff", src_ll=bssid,
+                         ip_src="192.168.1.1", ip_dst="255.255.255.255",
+                         yiaddr="192.168.1.123", chaddr=addr0)
+    if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt)):
+        raise Exception("DATA_TEST_FRAME failed")
+
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+    hapd.disable()
+
 def send_and_check_reply(srv, req, code, error_cause=0):
     reply = srv.SendPacket(req)
     logger.debug("RADIUS response from hostapd")
@@ -300,6 +371,57 @@ def send_and_check_reply(srv, req, code, error_cause=0):
             if reply['Error-Cause'][0] != error_cause:
                 raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
 
+def test_radius_acct_psk(dev, apdev):
+    """RADIUS Accounting - PSK"""
+    as_hapd = hostapd.Hostapd("as")
+    params = hostapd.wpa2_params(ssid="radius-acct", passphrase="12345678")
+    params['acct_server_addr'] = "127.0.0.1"
+    params['acct_server_port'] = "1813"
+    params['acct_server_shared_secret'] = "radius"
+    hapd = hostapd.add_ap(apdev[0], params)
+    dev[0].connect("radius-acct", psk="12345678", scan_freq="2412")
+
+def test_radius_acct_psk_sha256(dev, apdev):
+    """RADIUS Accounting - PSK SHA256"""
+    as_hapd = hostapd.Hostapd("as")
+    params = hostapd.wpa2_params(ssid="radius-acct", passphrase="12345678")
+    params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
+    params['acct_server_addr'] = "127.0.0.1"
+    params['acct_server_port'] = "1813"
+    params['acct_server_shared_secret'] = "radius"
+    hapd = hostapd.add_ap(apdev[0], params)
+    dev[0].connect("radius-acct", key_mgmt="WPA-PSK-SHA256",
+                   psk="12345678", scan_freq="2412")
+
+def test_radius_acct_ft_psk(dev, apdev):
+    """RADIUS Accounting - FT-PSK"""
+    as_hapd = hostapd.Hostapd("as")
+    params = ft_params1(ssid="radius-acct", passphrase="12345678")
+    params['acct_server_addr'] = "127.0.0.1"
+    params['acct_server_port'] = "1813"
+    params['acct_server_shared_secret'] = "radius"
+    hapd = hostapd.add_ap(apdev[0], params)
+    dev[0].connect("radius-acct", key_mgmt="FT-PSK",
+                   psk="12345678", scan_freq="2412")
+
+def test_radius_acct_ieee8021x(dev, apdev):
+    """RADIUS Accounting - IEEE 802.1X"""
+    skip_with_fips(dev[0])
+    as_hapd = hostapd.Hostapd("as")
+    params = hostapd.radius_params()
+    params["ssid"] = "radius-acct-1x"
+    params["ieee8021x"] = "1"
+    params["wep_key_len_broadcast"] = "13"
+    params["wep_key_len_unicast"] = "13"
+    params['acct_server_addr'] = "127.0.0.1"
+    params['acct_server_port'] = "1813"
+    params['acct_server_shared_secret'] = "radius"
+    hapd = hostapd.add_ap(apdev[0], params)
+    dev[0].connect("radius-acct-1x", key_mgmt="IEEE8021X", eap="PSK",
+                   identity="psk.user@example.com",
+                   password_hex="0123456789abcdef0123456789abcdef",
+                   scan_freq="2412")
+
 def test_radius_das_disconnect(dev, apdev):
     """RADIUS Dynamic Authorization Extensions - Disconnect"""
     try:
@@ -316,7 +438,7 @@ def test_radius_das_disconnect(dev, apdev):
     params['radius_das_require_event_timestamp'] = "1"
     params['own_ip_addr'] = "127.0.0.1"
     params['nas_identifier'] = "nas.example.com"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     connect(dev[0], "radius-das")
     addr = dev[0].p2p_interface_addr()
     sta = hapd.get_sta(addr)
@@ -613,7 +735,7 @@ def test_radius_das_coa(dev, apdev):
     params['radius_das_port'] = "3799"
     params['radius_das_client'] = "127.0.0.1 secret"
     params['radius_das_require_event_timestamp'] = "1"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     connect(dev[0], "radius-das")
     addr = dev[0].p2p_interface_addr()
     sta = hapd.get_sta(addr)
@@ -647,7 +769,7 @@ def test_radius_ipv6(dev, apdev):
     params['ca_cert'] = 'auth_serv/ca.pem'
     params['server_cert'] = 'auth_serv/server.pem'
     params['private_key'] = 'auth_serv/server.key'
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     params = hostapd.wpa2_eap_params(ssid="radius-ipv6")
     params['auth_server_addr'] = "::0"
@@ -656,7 +778,7 @@ def test_radius_ipv6(dev, apdev):
     params['acct_server_port'] = "18139"
     params['acct_server_shared_secret'] = "radius"
     params['own_ip_addr'] = "::0"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     connect(dev[0], "radius-ipv6")
 
 def test_radius_macacl(dev, apdev):
@@ -664,7 +786,7 @@ def test_radius_macacl(dev, apdev):
     params = hostapd.radius_params()
     params["ssid"] = "radius"
     params["macaddr_acl"] = "2"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("radius", key_mgmt="NONE", scan_freq="2412")
 
 def test_radius_macacl_acct(dev, apdev):
@@ -675,7 +797,7 @@ def test_radius_macacl_acct(dev, apdev):
     params['acct_server_addr'] = "127.0.0.1"
     params['acct_server_port'] = "1813"
     params['acct_server_shared_secret'] = "radius"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[0].connect("radius", key_mgmt="NONE", scan_freq="2412")
     dev[1].connect("radius", key_mgmt="NONE", scan_freq="2412")
     dev[1].request("DISCONNECT")
@@ -695,7 +817,7 @@ def test_radius_failover(dev, apdev):
     params['acct_server_port'] = "1813"
     params['acct_server_shared_secret'] = "testing"
     params['radius_retry_primary_interval'] = "20"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params, no_enable=True)
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
     hapd.set("auth_server_addr", "127.0.0.1")
     hapd.set("auth_server_port", "1812")
     hapd.set("auth_server_shared_secret", "radius")
@@ -795,7 +917,7 @@ def test_radius_protocol(dev, apdev):
                         try:
                             fdo = self._fdmap[fd]
                             self._ProcessInput(fdo)
-                        except ServerPacketError as err:
+                        except pyrad.server.ServerPacketError as err:
                             logger.info("pyrad server dropping packet: " + str(err))
                         except pyrad.packet.PacketError as err:
                             logger.info("pyrad server received invalid packet: " + str(err))
@@ -819,7 +941,7 @@ def test_radius_protocol(dev, apdev):
     try:
         params = hostapd.wpa2_eap_params(ssid="radius-test")
         params['auth_server_port'] = "18138"
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
         connect(dev[0], "radius-test", wait_connect=False)
         ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=15)
         if ev is None:
@@ -900,7 +1022,7 @@ def test_radius_psk(dev, apdev):
                         try:
                             fdo = self._fdmap[fd]
                             self._ProcessInput(fdo)
-                        except ServerPacketError as err:
+                        except pyrad.server.ServerPacketError as err:
                             logger.info("pyrad server dropping packet: " + str(err))
                         except pyrad.packet.PacketError as err:
                             logger.info("pyrad server received invalid packet: " + str(err))
@@ -929,7 +1051,7 @@ def test_radius_psk(dev, apdev):
         params['macaddr_acl'] = '2'
         params['wpa_psk_radius'] = '2'
         params['auth_server_port'] = "18138"
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
         dev[0].connect(ssid, psk="12345678", scan_freq="2412")
         t_events['long'].set()
         dev[1].connect(ssid, psk="0123456789abcdef", scan_freq="2412")
@@ -937,19 +1059,94 @@ def test_radius_psk(dev, apdev):
         t_events['stop'].set()
         t.join()
 
+def test_radius_psk_invalid(dev, apdev):
+    """WPA2 with invalid PSK from RADIUS"""
+    try:
+        import pyrad.server
+        import pyrad.packet
+        import pyrad.dictionary
+    except ImportError:
+        raise HwsimSkip("No pyrad modules available")
+
+    class TestServer(pyrad.server.Server):
+        def _HandleAuthPacket(self, pkt):
+            pyrad.server.Server._HandleAuthPacket(self, pkt)
+            logger.info("Received authentication request")
+            reply = self.CreateReplyPacket(pkt)
+            reply.code = pyrad.packet.AccessAccept
+            a = "\xab\xcd"
+            secret = reply.secret
+            p = b'\x07' + "1234567" + 8 * b'\x00'
+            b = hashlib.md5(secret + pkt.authenticator + a).digest()
+            pp = bytearray(p)
+            bb = bytearray(b)
+            cc = bytearray(pp[i] ^ bb[i] for i in range(len(bb)))
+            data = '\x00' + a + bytes(cc)
+            reply.AddAttribute("Tunnel-Password", data)
+            self.SendReplyPacket(pkt.fd, reply)
+
+        def RunWithStop(self, t_events):
+            self._poll = select.poll()
+            self._fdmap = {}
+            self._PrepareSockets()
+            self.t_events = t_events
+
+            while not t_events['stop'].is_set():
+                for (fd, event) in self._poll.poll(1000):
+                    if event == select.POLLIN:
+                        try:
+                            fdo = self._fdmap[fd]
+                            self._ProcessInput(fdo)
+                        except pyrad.server.ServerPacketError as err:
+                            logger.info("pyrad server dropping packet: " + str(err))
+                        except pyrad.packet.PacketError as err:
+                            logger.info("pyrad server received invalid packet: " + str(err))
+                    else:
+                        logger.error("Unexpected event in pyrad server main loop")
+
+    srv = TestServer(dict=pyrad.dictionary.Dictionary("dictionary.radius"),
+                     authport=18138, acctport=18139)
+    srv.hosts["127.0.0.1"] = pyrad.server.RemoteHost("127.0.0.1",
+                                                     "radius",
+                                                     "localhost")
+    srv.BindToAddress("")
+    t_events = {}
+    t_events['stop'] = threading.Event()
+    t = threading.Thread(target=run_pyrad_server, args=(srv, t_events))
+    t.start()
+
+    try:
+        ssid = "test-wpa2-psk"
+        params = hostapd.radius_params()
+        params['ssid'] = ssid
+        params["wpa"] = "2"
+        params["wpa_key_mgmt"] = "WPA-PSK"
+        params["rsn_pairwise"] = "CCMP"
+        params['macaddr_acl'] = '2'
+        params['wpa_psk_radius'] = '2'
+        params['auth_server_port'] = "18138"
+        hapd = hostapd.add_ap(apdev[0], params)
+        dev[0].connect(ssid, psk="12345678", scan_freq="2412",
+                       wait_connect=False)
+        time.sleep(1)
+    finally:
+        t_events['stop'].set()
+        t.join()
+
 def test_radius_auth_force_client_addr(dev, apdev):
     """RADIUS client address specified"""
     params = hostapd.wpa2_eap_params(ssid="radius-auth")
     params['radius_client_addr'] = "127.0.0.1"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     connect(dev[0], "radius-auth")
 
+@remote_compatible
 def test_radius_auth_force_invalid_client_addr(dev, apdev):
     """RADIUS client address specified and invalid address"""
     params = hostapd.wpa2_eap_params(ssid="radius-auth")
     #params['radius_client_addr'] = "10.11.12.14"
     params['radius_client_addr'] = "1::2"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     connect(dev[0], "radius-auth", wait_connect=False)
     ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"])
     if ev is None:
@@ -1048,7 +1245,7 @@ def test_ap_vlan_wpa2_psk_radius_required(dev, apdev):
                         try:
                             fdo = self._fdmap[fd]
                             self._ProcessInput(fdo)
-                        except ServerPacketError as err:
+                        except pyrad.server.ServerPacketError as err:
                             logger.info("pyrad server dropping packet: " + str(err))
                         except pyrad.packet.PacketError as err:
                             logger.info("pyrad server received invalid packet: " + str(err))
@@ -1079,7 +1276,7 @@ def test_ap_vlan_wpa2_psk_radius_required(dev, apdev):
         params['dynamic_vlan'] = "2"
         params['wpa_passphrase'] = '0123456789abcdefghi'
         params['auth_server_port'] = "18138"
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
 
         logger.info("connecting without VLAN")
         dev[0].connect(ssid, psk="0123456789abcdefghi", scan_freq="2412",
@@ -1119,3 +1316,28 @@ def test_ap_vlan_wpa2_psk_radius_required(dev, apdev):
     finally:
         t_events['stop'].set()
         t.join()
+
+def test_radius_mppe_failure(dev, apdev):
+    """RADIUS failure when adding MPPE keys"""
+    params = { "ssid": "as", "beacon_int": "2000",
+               "radius_server_clients": "auth_serv/radius_clients.conf",
+               "radius_server_auth_port": '18127',
+               "eap_server": "1",
+               "eap_user_file": "auth_serv/eap_user.conf",
+               "ca_cert": "auth_serv/ca.pem",
+               "server_cert": "auth_serv/server.pem",
+               "private_key": "auth_serv/server.key" }
+    authsrv = hostapd.add_ap(apdev[1], params)
+
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    params['auth_server_port'] = "18127"
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    with fail_test(authsrv, 1, "os_get_random;radius_msg_add_mppe_keys"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
+                       identity="user", anonymous_identity="ttls",
+                       password="password",
+                       ca_cert="auth_serv/ca.pem", phase2="autheap=GTC",
+                       wait_connect=False, scan_freq="2412")
+        dev[0].wait_disconnected()
+        dev[0].request("REMOVE_NETWORK all")
index 425b40f..d137531 100644 (file)
@@ -14,6 +14,7 @@ import hwsim_utils
 from wpasupplicant import WpaSupplicant
 from rfkill import RFKill
 from utils import HwsimSkip
+from hwsim import HWSimRadio
 
 def get_rfkill(dev):
     phy = dev.get_driver_status_field("phyname")
@@ -29,7 +30,7 @@ def test_rfkill_open(dev, apdev):
     """rfkill block/unblock during open mode connection"""
     rfk = get_rfkill(dev[0])
 
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
     try:
         logger.info("rfkill block")
@@ -61,7 +62,7 @@ def test_rfkill_wpa2_psk(dev, apdev):
     ssid = "test-wpa2-psk"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
     try:
         logger.info("rfkill block")
@@ -116,9 +117,72 @@ def test_rfkill_autogo(dev, apdev):
         rfk0.unblock()
         rfk1.unblock()
 
+def _test_rfkill_p2p_discovery(dev0, dev1):
+    """rfkill block/unblock P2P Discovery"""
+    rfk0 = get_rfkill(dev0)
+    rfk1 = get_rfkill(dev1)
+
+    try:
+        addr0 = dev0.p2p_dev_addr()
+
+        logger.info("rfkill block 0")
+        rfk0.block()
+        logger.info("rfkill block 1")
+        rfk1.block()
+
+        for i in range(10):
+            time.sleep(0.1)
+            if dev0.get_status_field("wpa_state") == "INTERFACE_DISABLED" and dev1.get_status_field("wpa_state") == "INTERFACE_DISABLED":
+                break
+
+        if "OK" in dev0.p2p_listen():
+            raise Exception("P2P Listen success although in rfkill")
+
+        if "OK" in dev1.p2p_find():
+            raise Exception("P2P Find success although in rfkill")
+
+        dev0.dump_monitor()
+        dev1.dump_monitor()
+
+        logger.info("rfkill unblock 0")
+        rfk0.unblock()
+        logger.info("rfkill unblock 1")
+        rfk1.unblock()
+
+        for i in range(10):
+            time.sleep(0.1)
+            if dev0.get_status_field("wpa_state") != "INTERFACE_DISABLED" and dev1.get_status_field("wpa_state") != "INTERFACE_DISABLED":
+                break
+
+        if not "OK" in dev0.p2p_listen():
+            raise Exception("P2P Listen failed after unblocking rfkill")
+
+        if not dev1.discover_peer(addr0, social=True):
+            raise Exception("Failed to discover peer after unblocking rfkill")
+
+    finally:
+        rfk0.unblock()
+        rfk1.unblock()
+        dev0.p2p_stop_find()
+        dev1.p2p_stop_find()
+        dev0.dump_monitor()
+        dev1.dump_monitor()
+
+def test_rfkill_p2p_discovery(dev, apdev):
+    """rfkill block/unblock P2P Discovery"""
+    _test_rfkill_p2p_discovery(dev[0], dev[1])
+
+def test_rfkill_p2p_discovery_p2p_dev(dev, apdev):
+    """rfkill block/unblock P2P Discovery with P2P Device"""
+    with HWSimRadio(use_p2p_device=True) as (radio, iface):
+        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas.interface_add(iface)
+        _test_rfkill_p2p_discovery(dev[0], wpas)
+        _test_rfkill_p2p_discovery(wpas, dev[1])
+
 def test_rfkill_hostapd(dev, apdev):
     """rfkill block/unblock during and prior to hostapd operations"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
 
     rfk = get_rfkill(hapd)
 
@@ -143,11 +207,11 @@ def test_rfkill_hostapd(dev, apdev):
         dev[0].request("DISCONNECT")
         hapd.disable()
 
-        hglobal = HostapdGlobal()
+        hglobal = HostapdGlobal(apdev[0])
         hglobal.flush()
         hglobal.remove(apdev[0]['ifname'])
 
-        hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open2" },
+        hapd = hostapd.add_ap(apdev[0], { "ssid": "open2" },
                               no_enable=True)
         if "FAIL" not in hapd.request("ENABLE"):
             raise Exception("ENABLE succeeded unexpectedly (rfkill)")
index ba70f75..e6d5dc2 100644 (file)
@@ -1,21 +1,22 @@
 # Test cases for SAE
-# Copyright (c) 2013-2015, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2013-2016, Jouni Malinen <j@w1.fi>
 #
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import binascii
 import os
 import time
-import subprocess
 import logging
 logger = logging.getLogger()
 
 import hwsim_utils
 import hostapd
-from utils import HwsimSkip, alloc_fail, fail_test
+from utils import HwsimSkip, alloc_fail, fail_test, wait_fail_trigger
 from test_ap_psk import find_wpas_process, read_process_memory, verify_not_present, get_key_locations
 
+@remote_compatible
 def test_sae(dev, apdev):
     """SAE with default group"""
     if "SAE" not in dev[0].get_capability("auth_alg"):
@@ -23,7 +24,7 @@ def test_sae(dev, apdev):
     params = hostapd.wpa2_params(ssid="test-sae",
                                  passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     key_mgmt = hapd.get_config()['key_mgmt']
     if key_mgmt.split(' ')[0] != "SAE":
         raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
@@ -39,6 +40,7 @@ def test_sae(dev, apdev):
     if "[WPA2-SAE-CCMP]" not in bss['flags']:
         raise Exception("Unexpected BSS flags: " + bss['flags'])
 
+@remote_compatible
 def test_sae_password_ecc(dev, apdev):
     """SAE with number of different passwords (ECC)"""
     if "SAE" not in dev[0].get_capability("auth_alg"):
@@ -46,7 +48,7 @@ def test_sae_password_ecc(dev, apdev):
     params = hostapd.wpa2_params(ssid="test-sae",
                                  passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].request("SET sae_groups 19")
 
@@ -58,6 +60,7 @@ def test_sae_password_ecc(dev, apdev):
         dev[0].request("REMOVE_NETWORK all")
         dev[0].wait_disconnected()
 
+@remote_compatible
 def test_sae_password_ffc(dev, apdev):
     """SAE with number of different passwords (FFC)"""
     if "SAE" not in dev[0].get_capability("auth_alg"):
@@ -66,7 +69,7 @@ def test_sae_password_ffc(dev, apdev):
                                  passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
     params['sae_groups'] = '22'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].request("SET sae_groups 22")
 
@@ -78,6 +81,7 @@ def test_sae_password_ffc(dev, apdev):
         dev[0].request("REMOVE_NETWORK all")
         dev[0].wait_disconnected()
 
+@remote_compatible
 def test_sae_pmksa_caching(dev, apdev):
     """SAE and PMKSA caching"""
     if "SAE" not in dev[0].get_capability("auth_alg"):
@@ -85,7 +89,7 @@ def test_sae_pmksa_caching(dev, apdev):
     params = hostapd.wpa2_params(ssid="test-sae",
                                  passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].request("SET sae_groups ")
     dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
@@ -100,6 +104,7 @@ def test_sae_pmksa_caching(dev, apdev):
     if dev[0].get_status_field('sae_group') is not None:
             raise Exception("SAE group claimed to have been used")
 
+@remote_compatible
 def test_sae_pmksa_caching_disabled(dev, apdev):
     """SAE and PMKSA caching disabled"""
     if "SAE" not in dev[0].get_capability("auth_alg"):
@@ -108,7 +113,7 @@ def test_sae_pmksa_caching_disabled(dev, apdev):
                                  passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
     params['disable_pmksa_caching'] = '1'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].request("SET sae_groups ")
     dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
@@ -142,7 +147,7 @@ def test_sae_groups(dev, apdev):
                                  passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
     params['sae_groups'] = ' '.join(groups)
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     for g in groups:
         logger.info("Testing SAE group " + g)
@@ -173,6 +178,7 @@ def test_sae_groups(dev, apdev):
         dev[0].wait_disconnected()
         dev[0].dump_monitor()
 
+@remote_compatible
 def test_sae_group_nego(dev, apdev):
     """SAE group negotiation"""
     if "SAE" not in dev[0].get_capability("auth_alg"):
@@ -181,7 +187,7 @@ def test_sae_group_nego(dev, apdev):
                                  passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
     params['sae_groups'] = '19'
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].request("SET sae_groups 25 26 20 19")
     dev[0].connect("test-sae-group-nego", psk="12345678", key_mgmt="SAE",
@@ -189,6 +195,7 @@ def test_sae_group_nego(dev, apdev):
     if dev[0].get_status_field('sae_group') != '19':
         raise Exception("Expected SAE group not used")
 
+@remote_compatible
 def test_sae_anti_clogging(dev, apdev):
     """SAE anti clogging"""
     if "SAE" not in dev[0].get_capability("auth_alg"):
@@ -196,7 +203,7 @@ def test_sae_anti_clogging(dev, apdev):
     params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
     params['sae_anti_clogging_threshold'] = '1'
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].request("SET sae_groups ")
     dev[1].request("SET sae_groups ")
@@ -217,7 +224,7 @@ def test_sae_forced_anti_clogging(dev, apdev):
     params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE WPA-PSK'
     params['sae_anti_clogging_threshold'] = '0'
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     dev[2].connect("test-sae", psk="12345678", scan_freq="2412")
     for i in range(0, 2):
         dev[i].request("SET sae_groups ")
@@ -231,7 +238,7 @@ def test_sae_mixed(dev, apdev):
     params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE WPA-PSK'
     params['sae_anti_clogging_threshold'] = '0'
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[2].connect("test-sae", psk="12345678", scan_freq="2412")
     for i in range(0, 2):
@@ -239,6 +246,7 @@ def test_sae_mixed(dev, apdev):
         dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
                        scan_freq="2412")
 
+@remote_compatible
 def test_sae_missing_password(dev, apdev):
     """SAE and missing password"""
     if "SAE" not in dev[0].get_capability("auth_alg"):
@@ -246,7 +254,7 @@ def test_sae_missing_password(dev, apdev):
     params = hostapd.wpa2_params(ssid="test-sae",
                                  passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].request("SET sae_groups ")
     id = dev[0].connect("test-sae",
@@ -264,7 +272,7 @@ def test_sae_key_lifetime_in_memory(dev, apdev, params):
     password = "5ad144a7c1f5a5503baa6fa01dabc15b1843e8c01662d78d16b70b5cd23cf8b"
     p = hostapd.wpa2_params(ssid="test-sae", passphrase=password)
     p['wpa_key_mgmt'] = 'SAE'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], p)
+    hapd = hostapd.add_ap(apdev[0], p)
 
     pid = find_wpas_process(dev[0])
 
@@ -272,7 +280,11 @@ def test_sae_key_lifetime_in_memory(dev, apdev, params):
     id = dev[0].connect("test-sae", psk=password, key_mgmt="SAE",
                         scan_freq="2412")
 
+    # The decrypted copy of GTK is freed only after the CTRL-EVENT-CONNECTED
+    # event has been delivered, so verify that wpa_supplicant has returned to
+    # eloop before reading process memory.
     time.sleep(1)
+    dev[0].ping()
     buf = read_process_memory(pid, password)
 
     dev[0].request("DISCONNECT")
@@ -331,6 +343,7 @@ def test_sae_key_lifetime_in_memory(dev, apdev, params):
     if tk in buf:
         raise Exception("TK found from memory")
     if gtk in buf:
+        get_key_locations(buf, gtk, "GTK")
         raise Exception("GTK found from memory")
     verify_not_present(buf, sae_k, fname, "SAE(k)")
     verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
@@ -376,6 +389,7 @@ def test_sae_key_lifetime_in_memory(dev, apdev, params):
     verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
     verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
 
+@remote_compatible
 def test_sae_oom_wpas(dev, apdev):
     """SAE and OOM in wpa_supplicant"""
     if "SAE" not in dev[0].get_capability("auth_alg"):
@@ -383,7 +397,7 @@ def test_sae_oom_wpas(dev, apdev):
     params = hostapd.wpa2_params(ssid="test-sae",
                                  passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].request("SET sae_groups 25")
     tls = dev[0].request("GET tls_library")
@@ -400,6 +414,30 @@ def test_sae_oom_wpas(dev, apdev):
                        scan_freq="2412")
         dev[0].request("REMOVE_NETWORK all")
 
+    with alloc_fail(dev[0], 1, "wpabuf_alloc;sme_auth_build_sae_commit"):
+        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
+                       scan_freq="2412")
+        dev[0].request("REMOVE_NETWORK all")
+
+    with alloc_fail(dev[0], 1, "wpabuf_alloc;sme_auth_build_sae_confirm"):
+        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
+                       scan_freq="2412", wait_connect=False)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+
+    with alloc_fail(dev[0], 1, "=sme_authenticate"):
+        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
+                       scan_freq="2412", wait_connect=False)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+
+    with alloc_fail(dev[0], 1, "radio_add_work;sme_authenticate"):
+        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
+                       scan_freq="2412", wait_connect=False)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+
+@remote_compatible
 def test_sae_proto_ecc(dev, apdev):
     """SAE protocol testing (ECC)"""
     if "SAE" not in dev[0].get_capability("auth_alg"):
@@ -407,7 +445,7 @@ def test_sae_proto_ecc(dev, apdev):
     params = hostapd.wpa2_params(ssid="test-sae",
                                  passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
 
     dev[0].request("SET sae_groups 19")
@@ -498,6 +536,7 @@ def test_sae_proto_ecc(dev, apdev):
         hapd.set("ext_mgmt_frame_handling", "0")
         hapd.dump_monitor()
 
+@remote_compatible
 def test_sae_proto_ffc(dev, apdev):
     """SAE protocol testing (FFC)"""
     if "SAE" not in dev[0].get_capability("auth_alg"):
@@ -505,7 +544,7 @@ def test_sae_proto_ffc(dev, apdev):
     params = hostapd.wpa2_params(ssid="test-sae",
                                  passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
 
     dev[0].request("SET sae_groups 2")
@@ -578,13 +617,14 @@ def test_sae_proto_ffc(dev, apdev):
         hapd.set("ext_mgmt_frame_handling", "0")
         hapd.dump_monitor()
 
+@remote_compatible
 def test_sae_no_ffc_by_default(dev, apdev):
     """SAE and default groups rejecting FFC"""
     if "SAE" not in dev[0].get_capability("auth_alg"):
         raise HwsimSkip("SAE not supported")
     params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].request("SET sae_groups 5")
     dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412",
@@ -603,7 +643,7 @@ def sae_reflection_attack(apdev, dev, group):
     params = hostapd.wpa2_params(ssid="test-sae",
                                  passphrase="no-knowledge-of-passphrase")
     params['wpa_key_mgmt'] = 'SAE'
-    hapd = hostapd.add_ap(apdev['ifname'], params)
+    hapd = hostapd.add_ap(apdev, params)
     bssid = apdev['bssid']
 
     dev.scan_for_bss(bssid, freq=2412)
@@ -638,14 +678,17 @@ def sae_reflection_attack(apdev, dev, group):
         if req['subtype'] == 11:
             raise Exception("Unexpected Authentication frame seen")
 
+@remote_compatible
 def test_sae_reflection_attack_ecc(dev, apdev):
     """SAE reflection attack (ECC)"""
     sae_reflection_attack(apdev[0], dev[0], 19)
 
+@remote_compatible
 def test_sae_reflection_attack_ffc(dev, apdev):
     """SAE reflection attack (FFC)"""
     sae_reflection_attack(apdev[0], dev[0], 5)
 
+@remote_compatible
 def test_sae_anti_clogging_proto(dev, apdev):
     """SAE anti clogging protocol testing"""
     if "SAE" not in dev[0].get_capability("auth_alg"):
@@ -653,7 +696,7 @@ def test_sae_anti_clogging_proto(dev, apdev):
     params = hostapd.wpa2_params(ssid="test-sae",
                                  passphrase="no-knowledge-of-passphrase")
     params['wpa_key_mgmt'] = 'SAE'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
 
     dev[0].scan_for_bss(bssid, freq=2412)
@@ -688,13 +731,14 @@ def test_sae_anti_clogging_proto(dev, apdev):
         if req['subtype'] == 11:
             raise Exception("Unexpected Authentication frame seen")
 
+@remote_compatible
 def test_sae_no_random(dev, apdev):
     """SAE and no random numbers available"""
     if "SAE" not in dev[0].get_capability("auth_alg"):
         raise HwsimSkip("SAE not supported")
     params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
     params['wpa_key_mgmt'] = 'SAE'
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].request("SET sae_groups ")
     tests = [ (1, "os_get_random;sae_get_rand"),
@@ -707,3 +751,195 @@ def test_sae_no_random(dev, apdev):
                            scan_freq="2412")
             dev[0].request("REMOVE_NETWORK all")
             dev[0].wait_disconnected()
+
+@remote_compatible
+def test_sae_pwe_failure(dev, apdev):
+    """SAE and pwe failure"""
+    if "SAE" not in dev[0].get_capability("auth_alg"):
+        raise HwsimSkip("SAE not supported")
+    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
+    params['wpa_key_mgmt'] = 'SAE'
+    params['sae_groups'] = '19 5'
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].request("SET sae_groups 19")
+    with fail_test(dev[0], 1, "hmac_sha256_vector;sae_derive_pwe_ecc"):
+        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
+                       scan_freq="2412")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+    with fail_test(dev[0], 1, "sae_test_pwd_seed_ecc"):
+        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
+                       scan_freq="2412")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    dev[0].request("SET sae_groups 5")
+    with fail_test(dev[0], 1, "hmac_sha256_vector;sae_derive_pwe_ffc"):
+        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
+                       scan_freq="2412")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+    dev[0].request("SET sae_groups 5")
+    with fail_test(dev[0], 1, "sae_test_pwd_seed_ffc"):
+        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
+                       scan_freq="2412")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+    with fail_test(dev[0], 2, "sae_test_pwd_seed_ffc"):
+        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
+                       scan_freq="2412")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
+@remote_compatible
+def test_sae_bignum_failure(dev, apdev):
+    """SAE and bignum failure"""
+    if "SAE" not in dev[0].get_capability("auth_alg"):
+        raise HwsimSkip("SAE not supported")
+    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
+    params['wpa_key_mgmt'] = 'SAE'
+    params['sae_groups'] = '19 5 22'
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].request("SET sae_groups 19")
+    tests = [ (1, "crypto_bignum_init_set;get_rand_1_to_p_1"),
+              (1, "crypto_bignum_init;is_quadratic_residue_blind"),
+              (1, "crypto_bignum_mulmod;is_quadratic_residue_blind"),
+              (2, "crypto_bignum_mulmod;is_quadratic_residue_blind"),
+              (3, "crypto_bignum_mulmod;is_quadratic_residue_blind"),
+              (1, "crypto_bignum_legendre;is_quadratic_residue_blind"),
+              (1, "crypto_bignum_init_set;sae_test_pwd_seed_ecc"),
+              (1, "crypto_ec_point_compute_y_sqr;sae_test_pwd_seed_ecc"),
+              (1, "crypto_bignum_init_set;get_random_qr_qnr"),
+              (1, "crypto_bignum_to_bin;sae_derive_pwe_ecc"),
+              (1, "crypto_ec_point_init;sae_derive_pwe_ecc"),
+              (1, "crypto_ec_point_solve_y_coord;sae_derive_pwe_ecc"),
+              (1, "crypto_ec_point_init;sae_derive_commit_element_ecc"),
+              (1, "crypto_ec_point_mul;sae_derive_commit_element_ecc"),
+              (1, "crypto_ec_point_invert;sae_derive_commit_element_ecc"),
+              (1, "crypto_bignum_init;=sae_derive_commit"),
+              (1, "crypto_ec_point_init;sae_derive_k_ecc"),
+              (1, "crypto_ec_point_mul;sae_derive_k_ecc"),
+              (1, "crypto_ec_point_add;sae_derive_k_ecc"),
+              (2, "crypto_ec_point_mul;sae_derive_k_ecc"),
+              (1, "crypto_ec_point_to_bin;sae_derive_k_ecc"),
+              (1, "crypto_bignum_legendre;get_random_qr_qnr"),
+              (1, "sha256_prf;sae_derive_keys"),
+              (1, "crypto_bignum_init;sae_derive_keys"),
+              (1, "crypto_bignum_init_set;sae_parse_commit_scalar"),
+              (1, "crypto_bignum_to_bin;sae_parse_commit_element_ecc"),
+              (1, "crypto_ec_point_from_bin;sae_parse_commit_element_ecc") ]
+    for count, func in tests:
+        with fail_test(dev[0], count, func):
+            dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
+                           scan_freq="2412", wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+
+    dev[0].request("SET sae_groups 5")
+    tests = [ (1, "crypto_bignum_init_set;sae_set_group"),
+              (2, "crypto_bignum_init_set;sae_set_group"),
+              (1, "crypto_bignum_init_set;sae_get_rand"),
+              (1, "crypto_bignum_init_set;sae_test_pwd_seed_ffc"),
+              (1, "crypto_bignum_exptmod;sae_test_pwd_seed_ffc"),
+              (1, "crypto_bignum_init;sae_derive_pwe_ffc"),
+              (1, "crypto_bignum_init;sae_derive_commit_element_ffc"),
+              (1, "crypto_bignum_exptmod;sae_derive_commit_element_ffc"),
+              (1, "crypto_bignum_inverse;sae_derive_commit_element_ffc"),
+              (1, "crypto_bignum_init;sae_derive_k_ffc"),
+              (1, "crypto_bignum_exptmod;sae_derive_k_ffc"),
+              (1, "crypto_bignum_mulmod;sae_derive_k_ffc"),
+              (2, "crypto_bignum_exptmod;sae_derive_k_ffc"),
+              (1, "crypto_bignum_to_bin;sae_derive_k_ffc"),
+              (1, "crypto_bignum_init_set;sae_parse_commit_element_ffc"),
+              (1, "crypto_bignum_init;sae_parse_commit_element_ffc"),
+              (2, "crypto_bignum_init_set;sae_parse_commit_element_ffc"),
+              (1, "crypto_bignum_exptmod;sae_parse_commit_element_ffc") ]
+    for count, func in tests:
+        with fail_test(dev[0], count, func):
+            dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
+                           scan_freq="2412", wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+
+    dev[0].request("SET sae_groups 22")
+    tests = [ (1, "crypto_bignum_init_set;sae_test_pwd_seed_ffc"),
+              (1, "crypto_bignum_sub;sae_test_pwd_seed_ffc"),
+              (1, "crypto_bignum_div;sae_test_pwd_seed_ffc") ]
+    for count, func in tests:
+        with fail_test(dev[0], count, func):
+            dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
+                           scan_freq="2412", wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+
+def test_sae_invalid_anti_clogging_token_req(dev, apdev):
+    """SAE and invalid anti-clogging token request"""
+    if "SAE" not in dev[0].get_capability("auth_alg"):
+        raise HwsimSkip("SAE not supported")
+    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
+    params['wpa_key_mgmt'] = 'SAE'
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+
+    dev[0].request("SET sae_groups 19")
+    dev[0].scan_for_bss(bssid, freq=2412)
+    hapd.set("ext_mgmt_frame_handling", "1")
+    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
+                   scan_freq="2412", wait_connect=False)
+    ev = dev[0].wait_event(["SME: Trying to authenticate"])
+    if ev is None:
+        raise Exception("No authentication attempt seen")
+    dev[0].dump_monitor()
+
+    for i in range(0, 10):
+        req = hapd.mgmt_rx()
+        if req is None:
+            raise Exception("MGMT RX wait timed out (commit)")
+        if req['subtype'] == 11:
+            break
+        req = None
+    if not req:
+        raise Exception("Authentication frame (commit) not received")
+
+    hapd.dump_monitor()
+    resp = {}
+    resp['fc'] = req['fc']
+    resp['da'] = req['sa']
+    resp['sa'] = req['da']
+    resp['bssid'] = req['bssid']
+    resp['payload'] = binascii.unhexlify("030001004c0013")
+    hapd.mgmt_tx(resp)
+
+    ev = dev[0].wait_event(["SME: Trying to authenticate"])
+    if ev is None:
+        raise Exception("No authentication attempt seen")
+    dev[0].dump_monitor()
+
+    for i in range(0, 10):
+        req = hapd.mgmt_rx()
+        if req is None:
+            raise Exception("MGMT RX wait timed out (commit) (2)")
+        if req['subtype'] == 11:
+            break
+        req = None
+    if not req:
+        raise Exception("Authentication frame (commit) not received (2)")
+
+    hapd.dump_monitor()
+    resp = {}
+    resp['fc'] = req['fc']
+    resp['da'] = req['sa']
+    resp['sa'] = req['da']
+    resp['bssid'] = req['bssid']
+    resp['payload'] = binascii.unhexlify("030001000100")
+    hapd.mgmt_tx(resp)
+
+    ev = dev[0].wait_event(["SME: Trying to authenticate"])
+    if ev is None:
+        raise Exception("No authentication attempt seen")
+    dev[0].dump_monitor()
+
+    dev[0].request("DISCONNECT")
index fa1bcc9..1ca4bd0 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import time
 import logging
 logger = logging.getLogger()
@@ -12,7 +13,7 @@ import subprocess
 
 import hostapd
 from wpasupplicant import WpaSupplicant
-from utils import HwsimSkip, fail_test
+from utils import HwsimSkip, fail_test, alloc_fail, wait_fail_trigger
 from tshark import run_tshark
 
 def check_scan(dev, params, other_started=False, test_busy=False):
@@ -62,9 +63,10 @@ def check_scan_retry(dev, params, bssid):
             return
     raise Exception("Unexpectedly old BSS entry")
 
+@remote_compatible
 def test_scan(dev, apdev):
     """Control interface behavior on scan parameters"""
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan" })
+    hostapd.add_ap(apdev[0], { "ssid": "test-scan" })
     bssid = apdev[0]['bssid']
 
     logger.info("Full scan")
@@ -86,10 +88,11 @@ def test_scan(dev, apdev):
     logger.info("Active single-channel scan on AP's operating channel")
     check_scan_retry(dev[0], "freq=2412 passive=0 use_id=1", bssid)
 
+@remote_compatible
 def test_scan_tsf(dev, apdev):
     """Scan and TSF updates from Beacon/Probe Response frames"""
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan",
-                                         'beacon_int': "100" })
+    hostapd.add_ap(apdev[0], { "ssid": "test-scan",
+                               'beacon_int': "100" })
     bssid = apdev[0]['bssid']
 
     tsf = []
@@ -110,9 +113,10 @@ def test_scan_tsf(dev, apdev):
     if 0 in tsf:
         raise Exception("0 TSF reported")
 
+@remote_compatible
 def test_scan_only(dev, apdev):
     """Control interface behavior on scan parameters with type=only"""
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan" })
+    hostapd.add_ap(apdev[0], { "ssid": "test-scan" })
     bssid = apdev[0]['bssid']
 
     logger.info("Full scan")
@@ -134,11 +138,12 @@ def test_scan_only(dev, apdev):
     logger.info("Active single-channel scan on AP's operating channel")
     check_scan_retry(dev[0], "type=only freq=2412 passive=0 use_id=1", bssid)
 
+@remote_compatible
 def test_scan_external_trigger(dev, apdev):
     """Avoid operations during externally triggered scan"""
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan" })
+    hostapd.add_ap(apdev[0], { "ssid": "test-scan" })
     bssid = apdev[0]['bssid']
-    subprocess.call(['iw', dev[0].ifname, 'scan', 'trigger'])
+    dev[0].cmd_execute(['iw', dev[0].ifname, 'scan', 'trigger'])
     check_scan(dev[0], "use_id=1", other_started=True)
 
 def test_scan_bss_expiration_count(dev, apdev):
@@ -147,7 +152,7 @@ def test_scan_bss_expiration_count(dev, apdev):
         raise Exception("Invalid BSS_EXPIRE_COUNT accepted")
     if "OK" not in dev[0].request("BSS_EXPIRE_COUNT 2"):
         raise Exception("BSS_EXPIRE_COUNT failed")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-scan" })
     bssid = apdev[0]['bssid']
     dev[0].scan(freq="2412", only_new=True)
     if bssid not in dev[0].request("SCAN_RESULTS"):
@@ -160,6 +165,7 @@ def test_scan_bss_expiration_count(dev, apdev):
     if bssid in dev[0].request("SCAN_RESULTS"):
         raise Exception("BSS found after two scans without match")
 
+@remote_compatible
 def test_scan_bss_expiration_age(dev, apdev):
     """BSS entry expiration based on age"""
     try:
@@ -167,9 +173,13 @@ def test_scan_bss_expiration_age(dev, apdev):
             raise Exception("Invalid BSS_EXPIRE_AGE accepted")
         if "OK" not in dev[0].request("BSS_EXPIRE_AGE 10"):
             raise Exception("BSS_EXPIRE_AGE failed")
-        hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan" })
+        hapd = hostapd.add_ap(apdev[0], { "ssid": "test-scan" })
         bssid = apdev[0]['bssid']
-        dev[0].scan(freq="2412")
+        # Allow couple more retries to avoid reporting errors during heavy load
+        for i in range(5):
+            dev[0].scan(freq="2412")
+            if bssid in dev[0].request("SCAN_RESULTS"):
+                break
         if bssid not in dev[0].request("SCAN_RESULTS"):
             raise Exception("BSS not found in initial scan")
         hapd.request("DISABLE")
@@ -185,15 +195,16 @@ def test_scan_bss_expiration_age(dev, apdev):
     finally:
         dev[0].request("BSS_EXPIRE_AGE 180")
 
+@remote_compatible
 def test_scan_filter(dev, apdev):
     """Filter scan results based on SSID"""
     try:
         if "OK" not in dev[0].request("SET filter_ssids 1"):
             raise Exception("SET failed")
         id = dev[0].connect("test-scan", key_mgmt="NONE", only_add_network=True)
-        hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan" })
+        hostapd.add_ap(apdev[0], { "ssid": "test-scan" })
         bssid = apdev[0]['bssid']
-        hostapd.add_ap(apdev[1]['ifname'], { "ssid": "test-scan2" })
+        hostapd.add_ap(apdev[1], { "ssid": "test-scan2" })
         bssid2 = apdev[1]['bssid']
         dev[0].scan(freq="2412", only_new=True)
         if bssid not in dev[0].request("SCAN_RESULTS"):
@@ -207,6 +218,7 @@ def test_scan_filter(dev, apdev):
     finally:
         dev[0].request("SET filter_ssids 0")
 
+@remote_compatible
 def test_scan_int(dev, apdev):
     """scan interval configuration"""
     try:
@@ -237,9 +249,9 @@ def test_scan_int(dev, apdev):
 
 def test_scan_bss_operations(dev, apdev):
     """Control interface behavior on BSS parameters"""
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan" })
+    hostapd.add_ap(apdev[0], { "ssid": "test-scan" })
     bssid = apdev[0]['bssid']
-    hostapd.add_ap(apdev[1]['ifname'], { "ssid": "test2-scan" })
+    hostapd.add_ap(apdev[1], { "ssid": "test2-scan" })
     bssid2 = apdev[1]['bssid']
 
     dev[0].scan(freq="2412")
@@ -321,6 +333,7 @@ def test_scan_bss_operations(dev, apdev):
     if len(res) != 0:
         raise Exception("Unexpected result after BSS_FLUSH 0")
 
+@remote_compatible
 def test_scan_and_interface_disabled(dev, apdev):
     """Scan operation when interface gets disabled"""
     try:
@@ -342,9 +355,10 @@ def test_scan_and_interface_disabled(dev, apdev):
     finally:
         dev[0].request("DRIVER_EVENT INTERFACE_ENABLED")
 
+@remote_compatible
 def test_scan_for_auth(dev, apdev):
     """cfg80211 workaround with scan-for-auth"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
     # Block sme-connect radio work with an external radio work item, so that
     # SELECT_NETWORK can decide to use fast associate without a new scan while
@@ -358,10 +372,9 @@ def test_scan_for_auth(dev, apdev):
                    wait_connect=False)
     dev[0].dump_monitor()
     # Clear cfg80211 BSS table.
-    try:
-        subprocess.check_call(['iw', dev[0].ifname, 'scan', 'trigger',
-                               'freq', '2457', 'flush'])
-    except subprocess.CalledProcessError, e:
+    res, data = dev[0].cmd_execute(['iw', dev[0].ifname, 'scan', 'trigger',
+                                    'freq', '2457', 'flush'])
+    if res != 0:
         raise HwsimSkip("iw scan trigger flush not supported")
     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 5)
     if ev is None:
@@ -372,9 +385,10 @@ def test_scan_for_auth(dev, apdev):
 
     dev[0].wait_connected(timeout=15)
 
+@remote_compatible
 def test_scan_for_auth_fail(dev, apdev):
     """cfg80211 workaround with scan-for-auth failing"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
     # Block sme-connect radio work with an external radio work item, so that
     # SELECT_NETWORK can decide to use fast associate without a new scan while
@@ -389,10 +403,9 @@ def test_scan_for_auth_fail(dev, apdev):
     dev[0].dump_monitor()
     hapd.disable()
     # Clear cfg80211 BSS table.
-    try:
-        subprocess.check_call(['iw', dev[0].ifname, 'scan', 'trigger',
-                               'freq', '2457', 'flush'])
-    except subprocess.CalledProcessError, e:
+    res, data = dev[0].cmd_execute(['iw', dev[0].ifname, 'scan', 'trigger',
+                                    'freq', '2457', 'flush'])
+    if res != 0:
         raise HwsimSkip("iw scan trigger flush not supported")
     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 5)
     if ev is None:
@@ -409,10 +422,11 @@ def test_scan_for_auth_fail(dev, apdev):
         raise Exception("Unexpected connection")
     dev[0].request("DISCONNECT")
 
+@remote_compatible
 def test_scan_for_auth_wep(dev, apdev):
     """cfg80211 scan-for-auth workaround with WEP keys"""
     dev[0].flush_scan_cache()
-    hapd = hostapd.add_ap(apdev[0]['ifname'],
+    hapd = hostapd.add_ap(apdev[0],
                           { "ssid": "wep", "wep_key0": '"abcde"',
                             "auth_algs": "2" })
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
@@ -428,10 +442,9 @@ def test_scan_for_auth_wep(dev, apdev):
                    auth_alg="SHARED", scan_freq="2412", wait_connect=False)
     dev[0].dump_monitor()
     # Clear cfg80211 BSS table.
-    try:
-        subprocess.check_call(['iw', dev[0].ifname, 'scan', 'trigger',
-                               'freq', '2457', 'flush'])
-    except subprocess.CalledProcessError, e:
+    res, data = dev[0].cmd_execute(['iw', dev[0].ifname, 'scan', 'trigger',
+                                    'freq', '2457', 'flush'])
+    if res != 0:
         raise HwsimSkip("iw scan trigger flush not supported")
     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 5)
     if ev is None:
@@ -442,10 +455,11 @@ def test_scan_for_auth_wep(dev, apdev):
 
     dev[0].wait_connected(timeout=15)
 
+@remote_compatible
 def test_scan_hidden(dev, apdev):
     """Control interface behavior on scan parameters"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan",
-                                                "ignore_broadcast_ssid": "1" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-scan",
+                                      "ignore_broadcast_ssid": "1" })
     bssid = apdev[0]['bssid']
 
     check_scan(dev[0], "freq=2412 use_id=1")
@@ -477,6 +491,9 @@ def test_scan_hidden(dev, apdev):
     if "FAIL" not in dev[0].request("SCAN scan_id=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17"):
         raise Exception("Too many scan_id values accepted")
 
+    # Duplicate SSID removal
+    check_scan(dev[0], "scan_id=%d,%d,%d freq=2412 use_id=1" % (id1, id1, id2))
+
     dev[0].request("REMOVE_NETWORK all")
     hapd.disable()
     dev[0].flush_scan_cache(freq=2432)
@@ -484,9 +501,9 @@ def test_scan_hidden(dev, apdev):
 
 def test_scan_and_bss_entry_removed(dev, apdev):
     """Last scan result and connect work processing on BSS entry update"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open",
-                                                "eap_server": "1",
-                                                "wps_state": "2" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open",
+                                      "eap_server": "1",
+                                      "wps_state": "2" })
     bssid = apdev[0]['bssid']
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
@@ -568,6 +585,7 @@ def test_scan_and_bss_entry_removed(dev, apdev):
     dev[0].flush_scan_cache()
     wpas.flush_scan_cache()
 
+@remote_compatible
 def test_scan_reqs_with_non_scan_radio_work(dev, apdev):
     """SCAN commands while non-scan radio_work is in progress"""
     id = dev[0].request("RADIO_WORK add test-work-a")
@@ -615,13 +633,13 @@ def test_scan_setband(dev, apdev):
                    "hw_mode": "a",
                    "channel": "36",
                    "country_code": "US" }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
         bssid = apdev[0]['bssid']
 
         params = { "ssid": "test-setband",
                    "hw_mode": "g",
                    "channel": "1" }
-        hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+        hapd2 = hostapd.add_ap(apdev[1], params)
         bssid2 = apdev[1]['bssid']
 
         if "FAIL" not in dev[0].request("SET setband FOO"):
@@ -633,13 +651,21 @@ def test_scan_setband(dev, apdev):
         if "OK" not in dev[2].request("SET setband 2G"):
             raise Exception("Failed to set setband")
 
-        for i in range(3):
-            dev[i].request("SCAN only_new=1")
+        # Allow a retry to avoid reporting errors during heavy load
+        for j in range(5):
+            for i in range(3):
+                dev[i].request("SCAN only_new=1")
 
-        for i in range(3):
-            ev = dev[i].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 15)
-            if ev is None:
-                raise Exception("Scan timed out")
+            for i in range(3):
+                ev = dev[i].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 15)
+                if ev is None:
+                    raise Exception("Scan timed out")
+
+            res0 = dev[0].request("SCAN_RESULTS")
+            res1 = dev[1].request("SCAN_RESULTS")
+            res2 = dev[2].request("SCAN_RESULTS")
+            if bssid in res0 and bssid2 in res0 and bssid in res1 and bssid2 in res2:
+                break
 
         res = dev[0].request("SCAN_RESULTS")
         if bssid not in res or bssid2 not in res:
@@ -666,6 +692,7 @@ def test_scan_setband(dev, apdev):
             dev[i].request("SET setband AUTO")
             dev[i].flush_scan_cache()
 
+@remote_compatible
 def test_scan_hidden_many(dev, apdev):
     """scan_ssid=1 with large number of profile with hidden SSID"""
     try:
@@ -676,8 +703,8 @@ def test_scan_hidden_many(dev, apdev):
         dev[0].request("SCAN_INTERVAL 5")
 
 def _test_scan_hidden_many(dev, apdev):
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan-ssid",
-                                                "ignore_broadcast_ssid": "1" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-scan-ssid",
+                                      "ignore_broadcast_ssid": "1" })
     bssid = apdev[0]['bssid']
 
     dev[0].request("SCAN_INTERVAL 1")
@@ -717,7 +744,7 @@ def test_scan_random_mac(dev, apdev, params):
         dev[0].request("MAC_RAND_SCAN all enable=0")
 
 def _test_scan_random_mac(dev, apdev, params):
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan" })
+    hostapd.add_ap(apdev[0], { "ssid": "test-scan" })
     bssid = apdev[0]['bssid']
 
     tests = [ "",
@@ -763,9 +790,10 @@ def _test_scan_random_mac(dev, apdev, params):
         if not found:
             raise Exception("Fixed OUI random address not seen")
 
+@remote_compatible
 def test_scan_trigger_failure(dev, apdev):
     """Scan trigger to the driver failing"""
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan" })
+    hostapd.add_ap(apdev[0], { "ssid": "test-scan" })
     bssid = apdev[0]['bssid']
 
     if "OK" not in dev[0].request("SET test_failure 1"):
@@ -806,22 +834,27 @@ def test_scan_trigger_failure(dev, apdev):
         raise Exception("wpa_state COMPLETED not restored")
     dev[0].request("SET test_failure 0")
 
+@remote_compatible
 def test_scan_specify_ssid(dev, apdev):
     """Control interface behavior on scan SSID parameter"""
     dev[0].flush_scan_cache()
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-hidden",
-                                                "ignore_broadcast_ssid": "1" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-hidden",
+                                      "ignore_broadcast_ssid": "1" })
     bssid = apdev[0]['bssid']
     check_scan(dev[0], "freq=2412 use_id=1 ssid 414243")
     bss = dev[0].get_bss(bssid)
     if bss is not None and bss['ssid'] == 'test-hidden':
         raise Exception("BSS entry for hidden AP present unexpectedly")
-    check_scan(dev[0], "freq=2412 ssid 414243 ssid 746573742d68696464656e ssid 616263313233 use_id=1")
-    bss = dev[0].get_bss(bssid)
+    # Allow couple more retries to avoid reporting errors during heavy load
+    for i in range(5):
+        check_scan(dev[0], "freq=2412 ssid 414243 ssid 746573742d68696464656e ssid 616263313233 use_id=1")
+        bss = dev[0].get_bss(bssid)
+        if bss and 'test-hidden' in dev[0].request("SCAN_RESULTS"):
+            break
     if bss is None:
         raise Exception("BSS entry for hidden AP not found")
     if 'test-hidden' not in dev[0].request("SCAN_RESULTS"):
-        raise Exception("Expected SSID not included in the scan results");
+        raise Exception("Expected SSID not included in the scan results")
 
     hapd.disable()
     dev[0].flush_scan_cache(freq=2432)
@@ -830,6 +863,7 @@ def test_scan_specify_ssid(dev, apdev):
     if "FAIL" not in dev[0].request("SCAN ssid foo"):
         raise Exception("Invalid SCAN command accepted")
 
+@remote_compatible
 def test_scan_ap_scan_2_ap_mode(dev, apdev):
     """AP_SCAN 2 AP mode and scan()"""
     try:
@@ -880,12 +914,12 @@ def _test_scan_ap_scan_2_ap_mode(dev, apdev):
 def test_scan_bss_expiration_on_ssid_change(dev, apdev):
     """BSS entry expiration when AP changes SSID"""
     dev[0].flush_scan_cache()
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-scan" })
     bssid = apdev[0]['bssid']
     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
 
     hapd.request("DISABLE")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     if "OK" not in dev[0].request("BSS_EXPIRE_COUNT 3"):
         raise Exception("BSS_EXPIRE_COUNT failed")
     dev[0].scan(freq="2412")
@@ -905,3 +939,218 @@ def test_scan_bss_expiration_on_ssid_change(dev, apdev):
         raise Exception("The BSS entry with the old SSID was not removed")
     dev[0].request("DISCONNECT")
     dev[0].wait_disconnected()
+
+def test_scan_dfs(dev, apdev, params):
+    """Scan on DFS channels"""
+    try:
+        _test_scan_dfs(dev, apdev, params)
+    finally:
+        subprocess.call(['iw', 'reg', 'set', '00'])
+
+def _test_scan_dfs(dev, apdev, params):
+    subprocess.call(['iw', 'reg', 'set', 'US'])
+    for i in range(2):
+        for j in range(5):
+            ev = dev[i].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=5)
+            if ev is None:
+                raise Exception("No regdom change event")
+            if "alpha2=US" in ev:
+                break
+        dev[i].dump_monitor()
+
+    if "OK" not in dev[0].request("SCAN"):
+        raise Exception("SCAN command failed")
+    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"])
+    if ev is None:
+        raise Exception("Scan did not complete")
+
+    if "OK" not in dev[0].request("SCAN freq=2412,5180,5260,5500,5600,5745"):
+        raise Exception("SCAN command failed")
+    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"])
+    if ev is None:
+        raise Exception("Scan did not complete")
+
+    out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
+                     "wlan.fc.type_subtype == 4", [ "radiotap.channel.freq" ])
+    if out is not None:
+        freq = out.splitlines()
+        freq = [int(f) for f in freq]
+        freq = list(set(freq))
+        freq.sort()
+        logger.info("Active scan seen on channels: " + str(freq))
+        for f in freq:
+            if (f >= 5260 and f <= 5320) or (f >= 5500 and f <= 5700):
+                raise Exception("Active scan on DFS channel: %d" % f)
+            if f in [ 2467, 2472 ]:
+                raise Exception("Active scan on US-disallowed channel: %d" % f)
+
+@remote_compatible
+def test_scan_abort(dev, apdev):
+    """Aborting a full scan"""
+    dev[0].request("SCAN")
+    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"])
+    if ev is None:
+        raise Exception("Scan did not start")
+    if "OK" not in dev[0].request("ABORT_SCAN"):
+        raise Exception("ABORT_SCAN command failed")
+    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=2)
+    if ev is None:
+        raise Exception("Scan did not terminate")
+
+@remote_compatible
+def test_scan_abort_on_connect(dev, apdev):
+    """Aborting a full scan on connection request"""
+    hostapd.add_ap(apdev[0], { "ssid": "test-scan" })
+    bssid = apdev[0]['bssid']
+
+    dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
+    dev[0].dump_monitor()
+    dev[0].request("SCAN")
+    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"])
+    if ev is None:
+        raise Exception("Scan did not start")
+    dev[0].connect("test-scan", key_mgmt="NONE")
+
+@remote_compatible
+def test_scan_ext(dev, apdev):
+    """Custom IE in Probe Request frame"""
+    hostapd.add_ap(apdev[0], { "ssid": "test-scan" })
+    bssid = apdev[0]['bssid']
+
+    try:
+        if "OK" not in dev[0].request("VENDOR_ELEM_ADD 14 dd050011223300"):
+            raise Exception("VENDOR_ELEM_ADD failed")
+        check_scan(dev[0], "freq=2412 use_id=1")
+    finally:
+        dev[0].request("VENDOR_ELEM_REMOVE 14 *")
+
+def test_scan_fail(dev, apdev):
+    """Scan failures"""
+    with fail_test(dev[0], 1, "wpa_driver_nl80211_scan"):
+        dev[0].request("DISCONNECT")
+        if "OK" not in dev[0].request("SCAN freq=2412"):
+            raise Exception("SCAN failed")
+        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-FAILED"], timeout=5)
+        if ev is None:
+            raise Exception("Did not see scan failure event")
+    dev[0].dump_monitor()
+
+    for i in range(1, 5):
+        with alloc_fail(dev[0], i,
+                        "wpa_scan_clone_params;wpa_supplicant_trigger_scan"):
+            if "OK" not in dev[0].request("SCAN ssid 112233 freq=2412"):
+                raise Exception("SCAN failed")
+            ev = dev[0].wait_event(["CTRL-EVENT-SCAN-FAILED"], timeout=5)
+            if ev is None:
+                raise Exception("Did not see scan failure event")
+        dev[0].dump_monitor()
+
+    with alloc_fail(dev[0], 1, "radio_add_work;wpa_supplicant_trigger_scan"):
+        if "OK" not in dev[0].request("SCAN freq=2412"):
+            raise Exception("SCAN failed")
+        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-FAILED"], timeout=5)
+        if ev is None:
+            raise Exception("Did not see scan failure event")
+    dev[0].dump_monitor()
+
+    try:
+        if "OK" not in dev[0].request("SET filter_ssids 1"):
+            raise Exception("SET failed")
+        id = dev[0].connect("test-scan", key_mgmt="NONE", only_add_network=True)
+        with alloc_fail(dev[0], 1, "wpa_supplicant_build_filter_ssids"):
+            # While the filter list cannot be created due to memory allocation
+            # failure, this scan is expected to be completed without SSID
+            # filtering.
+            if "OK" not in dev[0].request("SCAN freq=2412"):
+                raise Exception("SCAN failed")
+            ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"])
+            if ev is None:
+                raise Exception("Scan did not complete")
+        dev[0].remove_network(id)
+    finally:
+        dev[0].request("SET filter_ssids 0")
+    dev[0].dump_monitor()
+
+    with alloc_fail(dev[0], 1, "nl80211_get_scan_results"):
+        if "OK" not in dev[0].request("SCAN freq=2412"):
+            raise Exception("SCAN failed")
+        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=5)
+        if ev is None:
+            raise Exception("Did not see scan started event")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+    dev[0].dump_monitor()
+
+    try:
+        if "OK" not in dev[0].request("SET setband 2G"):
+            raise Exception("SET setband failed")
+        with alloc_fail(dev[0], 1, "=wpa_setband_scan_freqs_list"):
+            # While the frequency list cannot be created due to memory
+            # allocation failure, this scan is expected to be completed without
+            # frequency filtering.
+            if "OK" not in dev[0].request("SCAN"):
+                raise Exception("SCAN failed")
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("ABORT_SCAN")
+            ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"])
+            if ev is None:
+                raise Exception("Scan did not complete")
+    finally:
+        dev[0].request("SET setband AUTO")
+    dev[0].dump_monitor()
+
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    wpas.interface_add("wlan5")
+    wpas.request("SET preassoc_mac_addr 1")
+    with fail_test(wpas, 1, "nl80211_set_mac_addr;wpas_trigger_scan_cb"):
+        if "OK" not in wpas.request("SCAN freq=2412"):
+            raise Exception("SCAN failed")
+        ev = wpas.wait_event(["CTRL-EVENT-SCAN-FAILED"], timeout=5)
+        if ev is None:
+            raise Exception("Did not see scan failure event")
+    wpas.request("SET preassoc_mac_addr 0")
+    wpas.dump_monitor()
+
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
+    with alloc_fail(dev[0], 1, "wpa_bss_add"):
+        dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
+
+@remote_compatible
+def test_scan_freq_list(dev, apdev):
+    """Scan with SET freq_list and scan_cur_freq"""
+    try:
+        if "OK" not in dev[0].request("SET freq_list 2412 2417"):
+            raise Exception("SET freq_list failed")
+        check_scan(dev[0], "use_id=1")
+    finally:
+        dev[0].request("SET freq_list ")
+
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-scan" })
+    dev[0].connect("test-scan", key_mgmt="NONE", scan_freq="2412")
+    try:
+        if "OK" not in dev[0].request("SET scan_cur_freq 1"):
+            raise Exception("SET scan_cur_freq failed")
+        check_scan(dev[0], "use_id=1")
+    finally:
+        dev[0].request("SET scan_cur_freq 0")
+    dev[0].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+
+def test_scan_bss_limit(dev, apdev):
+    """Scan and wpa_supplicant BSS entry limit"""
+    try:
+        _test_scan_bss_limit(dev, apdev)
+    finally:
+        dev[0].request("SET bss_max_count 200")
+        pass
+
+def _test_scan_bss_limit(dev, apdev):
+    # Trigger 'Increasing the MAX BSS count to 2 because all BSSes are in use.
+    # We should normally not get here!' message by limiting the maximum BSS
+    # count to one so that the second AP would not fit in the BSS list and the
+    # first AP cannot be removed from the list since it is still in use.
+    dev[0].request("SET bss_max_count 1")
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-scan" })
+    dev[0].connect("test-scan", key_mgmt="NONE", scan_freq="2412")
+    hapd2 = hostapd.add_ap(apdev[1], { "ssid": "test-scan-2",
+                                       "channel": "6" })
+    dev[0].scan_for_bss(apdev[1]['bssid'], freq=2437, force_scan=True)
index ca0479e..738c782 100644 (file)
@@ -5,20 +5,22 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 
 import hostapd
 
+@remote_compatible
 def test_ssid_hex_encoded(dev, apdev):
     """SSID configuration using hex encoded version"""
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid2": '68656c6c6f' })
+    hostapd.add_ap(apdev[0], { "ssid2": '68656c6c6f' })
     dev[0].connect("hello", key_mgmt="NONE", scan_freq="2412")
     dev[1].connect(ssid2="68656c6c6f", key_mgmt="NONE", scan_freq="2412")
 
 def test_ssid_printf_encoded(dev, apdev):
     """SSID configuration using printf encoded version"""
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid2": 'P"\\0hello\\nthere"' })
+    hostapd.add_ap(apdev[0], { "ssid2": 'P"\\0hello\\nthere"' })
     dev[0].connect(ssid2="0068656c6c6f0a7468657265", key_mgmt="NONE",
                    scan_freq="2412")
     dev[1].connect(ssid2='P"\\x00hello\\nthere"', key_mgmt="NONE",
@@ -29,22 +31,25 @@ def test_ssid_printf_encoded(dev, apdev):
         raise Exception("Unexpected difference in SSID")
     dev[2].connect(ssid2='P"' + ssid + '"', key_mgmt="NONE", scan_freq="2412")
 
+@remote_compatible
 def test_ssid_1_octet(dev, apdev):
     """SSID with one octet"""
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": '1' })
+    hostapd.add_ap(apdev[0], { "ssid": '1' })
     dev[0].connect("1", key_mgmt="NONE", scan_freq="2412")
 
+@remote_compatible
 def test_ssid_32_octets(dev, apdev):
     """SSID with 32 octets"""
-    hostapd.add_ap(apdev[0]['ifname'],
+    hostapd.add_ap(apdev[0],
                    { "ssid": '1234567890abcdef1234567890ABCDEF' })
     dev[0].connect("1234567890abcdef1234567890ABCDEF", key_mgmt="NONE",
                    scan_freq="2412")
 
+@remote_compatible
 def test_ssid_utf8(dev, apdev):
     """SSID with UTF8 encoding"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": 'testi-åäöÅÄÖ-testi',
-                                                "utf8_ssid": "1" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": 'testi-åäöÅÄÖ-testi',
+                                      "utf8_ssid": "1" })
     dev[0].connect("testi-åäöÅÄÖ-testi", key_mgmt="NONE", scan_freq="2412")
     dev[1].connect(ssid2="74657374692dc3a5c3a4c3b6c385c384c3962d7465737469",
                    key_mgmt="NONE", scan_freq="2412")
@@ -60,60 +65,51 @@ def test_ssid_utf8(dev, apdev):
     if len(sta3) != 0:
         raise Exception("Unexpected STA iteration result (did not stop)")
 
+def clear_scan_cache(hapd, dev):
+    # clear BSS table to avoid issues in following test cases
+    dev[0].request("REMOVE_NETWORK all")
+    dev[1].request("REMOVE_NETWORK all")
+    dev[0].wait_disconnected()
+    hapd.disable()
+    dev[0].flush_scan_cache()
+    dev[1].flush_scan_cache()
+
+@remote_compatible
 def test_ssid_hidden(dev, apdev):
     """Hidden SSID"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": 'secret',
-                                                "ignore_broadcast_ssid": "1" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": 'secret',
+                                      "ignore_broadcast_ssid": "1" })
     dev[1].connect("secret", key_mgmt="NONE", scan_freq="2412",
                    wait_connect=False)
     dev[0].connect("secret", key_mgmt="NONE", scan_freq="2412", scan_ssid="1")
     ev = dev[1].wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
     if ev is not None:
         raise Exception("Unexpected connection")
-    dev[0].request("DISCONNECT")
-    dev[1].request("DISCONNECT")
-    # clear BSS table to avoid issues in following test cases
-    hapd.disable()
-    dev[0].request("BSS_FLUSH 0")
-    dev[0].request("SCAN freq=2412 only_new=1")
-    dev[1].request("BSS_FLUSH 0")
-    dev[1].request("SCAN freq=2412 only_new=1")
+    clear_scan_cache(hapd, dev)
 
+@remote_compatible
 def test_ssid_hidden2(dev, apdev):
     """Hidden SSID using zero octets as payload"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": 'secret2',
-                                                "ignore_broadcast_ssid": "2" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": 'secret2',
+                                      "ignore_broadcast_ssid": "2" })
     dev[1].connect("secret2", key_mgmt="NONE", scan_freq="2412",
                    wait_connect=False)
     dev[0].connect("secret2", key_mgmt="NONE", scan_freq="2412", scan_ssid="1")
     ev = dev[1].wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
     if ev is not None:
         raise Exception("Unexpected connection")
-    dev[0].request("DISCONNECT")
-    dev[1].request("DISCONNECT")
-    # clear BSS table to avoid issues in following test cases
-    hapd.disable()
-    dev[0].request("BSS_FLUSH 0")
-    dev[0].request("SCAN freq=2412 only_new=1")
-    dev[1].request("BSS_FLUSH 0")
-    dev[1].request("SCAN freq=2412 only_new=1")
+    clear_scan_cache(hapd, dev)
 
+@remote_compatible
 def test_ssid_hidden_wpa2(dev, apdev):
     """Hidden SSID with WPA2-PSK"""
     params = hostapd.wpa2_params(ssid="secret", passphrase="12345678")
     params["ignore_broadcast_ssid"] = "1"
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[1].connect("secret", psk="12345678", scan_freq="2412",
                    wait_connect=False)
     dev[0].connect("secret", psk="12345678", scan_freq="2412", scan_ssid="1")
     ev = dev[1].wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
     if ev is not None:
         raise Exception("Unexpected connection")
-    dev[0].request("DISCONNECT")
-    dev[1].request("DISCONNECT")
-    # clear BSS table to avoid issues in following test cases
-    hapd.disable()
-    dev[0].request("BSS_FLUSH 0")
-    dev[0].request("SCAN freq=2412 only_new=1")
-    dev[1].request("BSS_FLUSH 0")
-    dev[1].request("SCAN freq=2412 only_new=1")
+    clear_scan_cache(hapd, dev)
index 49c1ae4..efb2f00 100644 (file)
@@ -16,7 +16,7 @@ from wpasupplicant import WpaSupplicant
 def test_sta_dynamic(dev, apdev):
     """Dynamically added wpa_supplicant interface"""
     params = hostapd.wpa2_params(ssid="sta-dynamic", passphrase="12345678")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     logger.info("Create a dynamic wpa_supplicant interface and connect")
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
@@ -26,7 +26,7 @@ def test_sta_dynamic(dev, apdev):
 
 def test_sta_ap_scan_0(dev, apdev):
     """Dynamically added wpa_supplicant interface with AP_SCAN 0 connection"""
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test" })
+    hostapd.add_ap(apdev[0], { "ssid": "test" })
     bssid = apdev[0]['bssid']
 
     logger.info("Create a dynamic wpa_supplicant interface and connect")
@@ -48,7 +48,7 @@ def test_sta_ap_scan_0(dev, apdev):
 
 def test_sta_ap_scan_2(dev, apdev):
     """Dynamically added wpa_supplicant interface with AP_SCAN 2 connection"""
-    hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test" })
+    hostapd.add_ap(apdev[0], { "ssid": "test" })
     bssid = apdev[0]['bssid']
 
     logger.info("Create a dynamic wpa_supplicant interface and connect")
@@ -80,7 +80,7 @@ def test_sta_ap_scan_2(dev, apdev):
 
 def test_sta_ap_scan_2b(dev, apdev):
     """Dynamically added wpa_supplicant interface with AP_SCAN 2 operation"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test" })
     bssid = apdev[0]['bssid']
 
     logger.info("Create a dynamic wpa_supplicant interface and connect")
@@ -113,7 +113,7 @@ def test_sta_ap_scan_2b(dev, apdev):
 def test_sta_dynamic_down_up(dev, apdev):
     """Dynamically added wpa_supplicant interface down/up"""
     params = hostapd.wpa2_params(ssid="sta-dynamic", passphrase="12345678")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     logger.info("Create a dynamic wpa_supplicant interface and connect")
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
@@ -131,7 +131,7 @@ def test_sta_dynamic_down_up(dev, apdev):
 def test_sta_dynamic_ext_mac_addr_change(dev, apdev):
     """Dynamically added wpa_supplicant interface with external MAC address change"""
     params = hostapd.wpa2_params(ssid="sta-dynamic", passphrase="12345678")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     logger.info("Create a dynamic wpa_supplicant interface and connect")
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
@@ -164,7 +164,7 @@ def test_sta_dynamic_ext_mac_addr_change(dev, apdev):
 def test_sta_dynamic_random_mac_addr(dev, apdev):
     """Dynamically added wpa_supplicant interface and random MAC address"""
     params = hostapd.wpa2_params(ssid="sta-dynamic", passphrase="12345678")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5")
@@ -202,7 +202,7 @@ def test_sta_dynamic_random_mac_addr(dev, apdev):
 def test_sta_dynamic_random_mac_addr_keep_oui(dev, apdev):
     """Dynamically added wpa_supplicant interface and random MAC address (keep OUI)"""
     params = hostapd.wpa2_params(ssid="sta-dynamic", passphrase="12345678")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5")
@@ -244,7 +244,7 @@ def test_sta_dynamic_random_mac_addr_keep_oui(dev, apdev):
 def test_sta_dynamic_random_mac_addr_scan(dev, apdev):
     """Dynamically added wpa_supplicant interface and random MAC address for scan"""
     params = hostapd.wpa2_params(ssid="sta-dynamic", passphrase="12345678")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5")
@@ -261,7 +261,7 @@ def test_sta_dynamic_random_mac_addr_scan(dev, apdev):
 def test_sta_dynamic_random_mac_addr_scan_keep_oui(dev, apdev):
     """Dynamically added wpa_supplicant interface and random MAC address for scan (keep OUI)"""
     params = hostapd.wpa2_params(ssid="sta-dynamic", passphrase="12345678")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
     wpas.interface_add("wlan5")
index 1a32c69..e4531e8 100644 (file)
@@ -9,7 +9,7 @@ import logging
 logger = logging.getLogger()
 
 import hostapd
-from utils import HwsimSkip
+from utils import HwsimSkip, fail_test
 
 def check_suite_b_capa(dev):
     if "GCMP" not in dev[0].get_capability("pairwise"):
@@ -23,7 +23,7 @@ def check_suite_b_capa(dev):
 def check_suite_b_tls_lib(dev):
     tls = dev[0].request("GET tls_library")
     if not tls.startswith("OpenSSL"):
-        raise HwsimSkip("TLS library not supported for Suite B: " + tls);
+        raise HwsimSkip("TLS library not supported for Suite B: " + tls)
     supported = False
     for ver in [ '1.0.2', '1.1.0' ]:
         if "build=OpenSSL " + ver in tls and "run=OpenSSL " + ver in tls:
@@ -32,10 +32,7 @@ def check_suite_b_tls_lib(dev):
     if not supported:
         raise HwsimSkip("OpenSSL version not supported for Suite B: " + tls)
 
-def test_suite_b(dev, apdev):
-    """WPA2/GCMP connection at Suite B 128-bit level"""
-    check_suite_b_capa(dev)
-    dev[0].flush_scan_cache()
+def suite_b_ap_params():
     params = { "ssid": "test-suite-b",
                "wpa": "2",
                "wpa_key_mgmt": "WPA-EAP-SUITE-B",
@@ -50,7 +47,14 @@ def test_suite_b(dev, apdev):
                "ca_cert": "auth_serv/ec-ca.pem",
                "server_cert": "auth_serv/ec-server.pem",
                "private_key": "auth_serv/ec-server.key" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    return params
+
+def test_suite_b(dev, apdev):
+    """WPA2/GCMP connection at Suite B 128-bit level"""
+    check_suite_b_capa(dev)
+    dev[0].flush_scan_cache()
+    params = suite_b_ap_params()
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-suite-b", key_mgmt="WPA-EAP-SUITE-B", ieee80211w="2",
                    openssl_ciphers="SUITEB128",
@@ -99,7 +103,7 @@ def test_suite_b_radius(dev, apdev):
     check_suite_b_capa(dev)
     dev[0].flush_scan_cache()
     params = suite_b_as_params()
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     params = { "ssid": "test-suite-b",
                "wpa": "2",
@@ -112,7 +116,7 @@ def test_suite_b_radius(dev, apdev):
                'auth_server_port': "18129",
                'auth_server_shared_secret': "radius",
                'nas_identifier': "nas.w1.fi" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-suite-b", key_mgmt="WPA-EAP-SUITE-B", ieee80211w="2",
                    openssl_ciphers="SUITEB128",
@@ -131,10 +135,7 @@ def check_suite_b_192_capa(dev):
         raise HwsimSkip("WPA-EAP-SUITE-B-192 not supported")
     check_suite_b_tls_lib(dev)
 
-def test_suite_b_192(dev, apdev):
-    """WPA2/GCMP-256 connection at Suite B 192-bit level"""
-    check_suite_b_192_capa(dev)
-    dev[0].flush_scan_cache()
+def suite_b_192_ap_params():
     params = { "ssid": "test-suite-b",
                "wpa": "2",
                "wpa_key_mgmt": "WPA-EAP-SUITE-B-192",
@@ -148,7 +149,14 @@ def test_suite_b_192(dev, apdev):
                "ca_cert": "auth_serv/ec2-ca.pem",
                "server_cert": "auth_serv/ec2-server.pem",
                "private_key": "auth_serv/ec2-server.key" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    return params
+
+def test_suite_b_192(dev, apdev):
+    """WPA2/GCMP-256 connection at Suite B 192-bit level"""
+    check_suite_b_192_capa(dev)
+    dev[0].flush_scan_cache()
+    params = suite_b_192_ap_params()
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-suite-b", key_mgmt="WPA-EAP-SUITE-B-192",
                    ieee80211w="2",
@@ -188,7 +196,7 @@ def test_suite_b_192_radius(dev, apdev):
     params['server_cert'] = 'auth_serv/ec2-server.pem'
     params['private_key'] = 'auth_serv/ec2-server.key'
     params['openssl_ciphers'] = 'SUITEB192'
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
 
     params = { "ssid": "test-suite-b",
                "wpa": "2",
@@ -201,7 +209,7 @@ def test_suite_b_192_radius(dev, apdev):
                'auth_server_port': "18129",
                'auth_server_shared_secret': "radius",
                'nas_identifier': "nas.w1.fi" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-suite-b", key_mgmt="WPA-EAP-SUITE-B-192",
                    ieee80211w="2",
@@ -211,3 +219,75 @@ def test_suite_b_192_radius(dev, apdev):
                    client_cert="auth_serv/ec2-user.pem",
                    private_key="auth_serv/ec2-user.key",
                    pairwise="GCMP-256", group="GCMP-256", scan_freq="2412")
+
+def test_suite_b_pmkid_failure(dev, apdev):
+    """WPA2/GCMP connection at Suite B 128-bit level and PMKID derivation failure"""
+    check_suite_b_capa(dev)
+    dev[0].flush_scan_cache()
+    params = suite_b_ap_params()
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    with fail_test(dev[0], 1, "rsn_pmkid_suite_b"):
+        dev[0].connect("test-suite-b", key_mgmt="WPA-EAP-SUITE-B",
+                       ieee80211w="2",
+                       openssl_ciphers="SUITEB128",
+                       eap="TLS", identity="tls user",
+                       ca_cert="auth_serv/ec-ca.pem",
+                       client_cert="auth_serv/ec-user.pem",
+                       private_key="auth_serv/ec-user.key",
+                       pairwise="GCMP", group="GCMP", scan_freq="2412")
+
+def test_suite_b_192_pmkid_failure(dev, apdev):
+    """WPA2/GCMP-256 connection at Suite B 192-bit level and PMKID derivation failure"""
+    check_suite_b_192_capa(dev)
+    dev[0].flush_scan_cache()
+    params = suite_b_192_ap_params()
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    with fail_test(dev[0], 1, "rsn_pmkid_suite_b"):
+        dev[0].connect("test-suite-b", key_mgmt="WPA-EAP-SUITE-B-192",
+                       ieee80211w="2",
+                       openssl_ciphers="SUITEB192",
+                       eap="TLS", identity="tls user",
+                       ca_cert="auth_serv/ec2-ca.pem",
+                       client_cert="auth_serv/ec2-user.pem",
+                       private_key="auth_serv/ec2-user.key",
+                       pairwise="GCMP-256", group="GCMP-256", scan_freq="2412")
+
+def test_suite_b_mic_failure(dev, apdev):
+    """WPA2/GCMP connection at Suite B 128-bit level and MIC derivation failure"""
+    check_suite_b_capa(dev)
+    dev[0].flush_scan_cache()
+    params = suite_b_ap_params()
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    with fail_test(dev[0], 1, "wpa_eapol_key_mic"):
+        dev[0].connect("test-suite-b", key_mgmt="WPA-EAP-SUITE-B",
+                       ieee80211w="2",
+                       openssl_ciphers="SUITEB128",
+                       eap="TLS", identity="tls user",
+                       ca_cert="auth_serv/ec-ca.pem",
+                       client_cert="auth_serv/ec-user.pem",
+                       private_key="auth_serv/ec-user.key",
+                       pairwise="GCMP", group="GCMP", scan_freq="2412",
+                       wait_connect=False)
+        dev[0].wait_disconnected()
+
+def test_suite_b_192_mic_failure(dev, apdev):
+    """WPA2/GCMP connection at Suite B 192-bit level and MIC derivation failure"""
+    check_suite_b_capa(dev)
+    dev[0].flush_scan_cache()
+    params = suite_b_192_ap_params()
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    with fail_test(dev[0], 1, "wpa_eapol_key_mic"):
+        dev[0].connect("test-suite-b", key_mgmt="WPA-EAP-SUITE-B-192",
+                       ieee80211w="2",
+                       openssl_ciphers="SUITEB192",
+                       eap="TLS", identity="tls user",
+                       ca_cert="auth_serv/ec2-ca.pem",
+                       client_cert="auth_serv/ec2-user.pem",
+                       private_key="auth_serv/ec2-user.key",
+                       pairwise="GCMP-256", group="GCMP-256", scan_freq="2412",
+                       wait_connect=False)
+        dev[0].wait_disconnected()
index ba9e8e9..84ff453 100644 (file)
@@ -8,21 +8,21 @@
 import os.path
 
 import hostapd
-from utils import HwsimSkip
+from utils import HwsimSkip, alloc_fail, fail_test, wait_fail_trigger
 from test_ap_eap import int_eap_server_params, check_eap_capa
 
 def test_tnc_peap_soh(dev, apdev):
     """TNC PEAP-SoH"""
     params = int_eap_server_params()
     params["tnc"] = "1"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
                    eap="PEAP", identity="user", password="password",
                    ca_cert="auth_serv/ca.pem",
                    phase1="peapver=0 tnc=soh cryptobinding=0",
                    phase2="auth=MSCHAPV2",
-                   wait_connect=False)
+                   scan_freq="2412", wait_connect=False)
     dev[0].wait_connected(timeout=10)
 
     dev[1].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
@@ -30,7 +30,7 @@ def test_tnc_peap_soh(dev, apdev):
                    ca_cert="auth_serv/ca.pem",
                    phase1="peapver=0 tnc=soh1 cryptobinding=1",
                    phase2="auth=MSCHAPV2",
-                   wait_connect=False)
+                   scan_freq="2412", wait_connect=False)
     dev[1].wait_connected(timeout=10)
 
     dev[2].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
@@ -38,15 +38,46 @@ def test_tnc_peap_soh(dev, apdev):
                    ca_cert="auth_serv/ca.pem",
                    phase1="peapver=0 tnc=soh2 cryptobinding=2",
                    phase2="auth=MSCHAPV2",
-                   wait_connect=False)
+                   scan_freq="2412", wait_connect=False)
     dev[2].wait_connected(timeout=10)
 
+def test_tnc_peap_soh_errors(dev, apdev):
+    """TNC PEAP-SoH local error cases"""
+    params = int_eap_server_params()
+    params["tnc"] = "1"
+    hostapd.add_ap(apdev[0], params)
+
+    tests = [ (1, "tncc_build_soh"),
+              (1, "eap_msg_alloc;=eap_peap_phase2_request") ]
+    for count, func in tests:
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
+                           eap="PEAP", identity="user", password="password",
+                           ca_cert="auth_serv/ca.pem",
+                           phase1="peapver=0 tnc=soh cryptobinding=0",
+                           phase2="auth=MSCHAPV2",
+                           scan_freq="2412", wait_connect=False)
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+
+    with fail_test(dev[0], 1, "os_get_random;tncc_build_soh"):
+        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
+                       eap="PEAP", identity="user", password="password",
+                       ca_cert="auth_serv/ca.pem",
+                       phase1="peapver=0 tnc=soh cryptobinding=0",
+                       phase2="auth=MSCHAPV2",
+                       scan_freq="2412", wait_connect=False)
+        wait_fail_trigger(dev[0], "GET_FAIL")
+        dev[0].request("REMOVE_NETWORK all")
+        dev[0].wait_disconnected()
+
 def test_tnc_ttls(dev, apdev):
     """TNC TTLS"""
     check_eap_capa(dev[0], "MSCHAPV2")
     params = int_eap_server_params()
     params["tnc"] = "1"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     if not os.path.exists("tnc/libhostap_imc.so"):
         raise HwsimSkip("No IMC installed")
@@ -56,7 +87,7 @@ def test_tnc_ttls(dev, apdev):
                    anonymous_identity="ttls", password="password",
                    phase2="auth=MSCHAPV2",
                    ca_cert="auth_serv/ca.pem",
-                   wait_connect=False)
+                   scan_freq="2412", wait_connect=False)
     dev[0].wait_connected(timeout=10)
 
 def test_tnc_ttls_fragmentation(dev, apdev):
@@ -65,7 +96,7 @@ def test_tnc_ttls_fragmentation(dev, apdev):
     params = int_eap_server_params()
     params["tnc"] = "1"
     params["fragment_size"] = "150"
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     if not os.path.exists("tnc/libhostap_imc.so"):
         raise HwsimSkip("No IMC installed")
@@ -76,9 +107,67 @@ def test_tnc_ttls_fragmentation(dev, apdev):
                    phase2="auth=MSCHAPV2",
                    ca_cert="auth_serv/ca.pem",
                    fragment_size="150",
-                   wait_connect=False)
+                   scan_freq="2412", wait_connect=False)
     dev[0].wait_connected(timeout=10)
 
+def test_tnc_ttls_errors(dev, apdev):
+    """TNC TTLS local error cases"""
+    if not os.path.exists("tnc/libhostap_imc.so"):
+        raise HwsimSkip("No IMC installed")
+    check_eap_capa(dev[0], "MSCHAPV2")
+
+    params = int_eap_server_params()
+    params["tnc"] = "1"
+    params["fragment_size"] = "150"
+    hostapd.add_ap(apdev[0], params)
+
+    tests = [ (1, "eap_ttls_process_phase2_eap;eap_ttls_process_tnc_start",
+               "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
+              (1, "eap_ttls_process_phase2_eap;eap_ttls_process_tnc_start",
+               "mschap user", "auth=MSCHAP"),
+              (1, "=eap_tnc_init", "chap user", "auth=CHAP"),
+              (1, "tncc_init;eap_tnc_init", "pap user", "auth=PAP"),
+              (1, "eap_msg_alloc;eap_tnc_build_frag_ack",
+               "pap user", "auth=PAP"),
+              (1, "eap_msg_alloc;eap_tnc_build_msg",
+               "pap user", "auth=PAP"),
+              (1, "wpabuf_alloc;=eap_tnc_process_fragment",
+               "pap user", "auth=PAP"),
+              (1, "eap_msg_alloc;=eap_tnc_process", "pap user", "auth=PAP"),
+              (1, "wpabuf_alloc;=eap_tnc_process", "pap user", "auth=PAP"),
+              (1, "dup_binstr;tncc_process_if_tnccs", "pap user", "auth=PAP"),
+              (1, "tncc_get_base64;tncc_process_if_tnccs",
+               "pap user", "auth=PAP"),
+              (1, "tncc_if_tnccs_start", "pap user", "auth=PAP"),
+              (1, "tncc_if_tnccs_end", "pap user", "auth=PAP"),
+              (1, "tncc_parse_imc", "pap user", "auth=PAP"),
+              (2, "tncc_parse_imc", "pap user", "auth=PAP"),
+              (3, "tncc_parse_imc", "pap user", "auth=PAP"),
+              (1, "os_readfile;tncc_read_config", "pap user", "auth=PAP"),
+              (1, "tncc_init", "pap user", "auth=PAP"),
+              (1, "TNC_TNCC_ReportMessageTypes", "pap user", "auth=PAP"),
+              (1, "base64_encode;TNC_TNCC_SendMessage", "pap user", "auth=PAP"),
+              (1, "=TNC_TNCC_SendMessage", "pap user", "auth=PAP"),
+              (1, "tncc_get_base64;tncc_process_if_tnccs",
+               "pap user", "auth=PAP") ]
+    for count, func, identity, phase2 in tests:
+        with alloc_fail(dev[0], count, func):
+            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
+                           scan_freq="2412",
+                           eap="TTLS", anonymous_identity="ttls",
+                           identity=identity, password="password",
+                           ca_cert="auth_serv/ca.pem", phase2=phase2,
+                           fragment_size="150", wait_connect=False)
+            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
+                                   timeout=15)
+            if ev is None:
+                raise Exception("Timeout on EAP start")
+            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL",
+                              note="Allocation failure not triggered for: %d:%s" % (count, func))
+            dev[0].request("REMOVE_NETWORK all")
+            dev[0].wait_disconnected()
+            dev[0].dump_monitor()
+
 def test_tnc_fast(dev, apdev):
     """TNC FAST"""
     check_eap_capa(dev[0], "FAST")
@@ -88,7 +177,7 @@ def test_tnc_fast(dev, apdev):
     params["eap_fast_a_id"] = "101112131415161718191a1b1c1d1e00"
     params["eap_fast_a_id_info"] = "test server2"
 
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     if not os.path.exists("tnc/libhostap_imc.so"):
         raise HwsimSkip("No IMC installed")
@@ -100,5 +189,5 @@ def test_tnc_fast(dev, apdev):
                    phase1="fast_provisioning=2",
                    pac_file="blob://fast_pac_auth_tnc",
                    ca_cert="auth_serv/ca.pem",
-                   wait_connect=False)
+                   scan_freq="2412", wait_connect=False)
     dev[0].wait_connected(timeout=10)
index bd8fec0..85ed028 100644 (file)
@@ -4,12 +4,18 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+import logging
+logger = logging.getLogger()
+import subprocess
+
+from remotehost import remote_compatible
 import hostapd
 import hwsim_utils
 
+@remote_compatible
 def test_wep_open_auth(dev, apdev):
     """WEP Open System authentication"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'],
+    hapd = hostapd.add_ap(apdev[0],
                           { "ssid": "wep-open",
                             "wep_key0": '"hello"' })
     dev[0].flush_scan_cache()
@@ -25,9 +31,10 @@ def test_wep_open_auth(dev, apdev):
     if "[WEP]" not in bss['flags']:
         raise Exception("Unexpected BSS flags: " + bss['flags'])
 
+@remote_compatible
 def test_wep_shared_key_auth(dev, apdev):
     """WEP Shared Key authentication"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'],
+    hapd = hostapd.add_ap(apdev[0],
                           { "ssid": "wep-shared-key",
                             "wep_key0": '"hello12345678"',
                             "auth_algs": "2" })
@@ -39,9 +46,10 @@ def test_wep_shared_key_auth(dev, apdev):
                    wep_key0='"hello12345678"',
                    scan_freq="2412")
 
+@remote_compatible
 def test_wep_shared_key_auth_not_allowed(dev, apdev):
     """WEP Shared Key authentication not allowed"""
-    hostapd.add_ap(apdev[0]['ifname'],
+    hostapd.add_ap(apdev[0],
                    { "ssid": "wep-shared-key",
                      "wep_key0": '"hello12345678"',
                      "auth_algs": "1" })
@@ -54,7 +62,7 @@ def test_wep_shared_key_auth_not_allowed(dev, apdev):
 
 def test_wep_shared_key_auth_multi_key(dev, apdev):
     """WEP Shared Key authentication with multiple keys"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'],
+    hapd = hostapd.add_ap(apdev[0],
                           { "ssid": "wep-shared-key",
                             "wep_key0": '"hello12345678"',
                             "wep_key1": '"other12345678"',
@@ -80,3 +88,38 @@ def test_wep_shared_key_auth_multi_key(dev, apdev):
     dev[2].request("REASSOCIATE")
     dev[2].wait_connected(timeout=10, error="Reassociation timed out")
     hwsim_utils.test_connectivity(dev[2], hapd)
+
+def test_wep_ht_vht(dev, apdev):
+    """WEP and HT/VHT"""
+    dev[0].flush_scan_cache()
+    try:
+        hapd = None
+        params = { "ssid": "test-vht40-wep",
+                   "country_code": "SE",
+                   "hw_mode": "a",
+                   "channel": "36",
+                   "ieee80211n": "1",
+                   "ieee80211ac": "1",
+                   "ht_capab": "[HT40+]",
+                   "vht_capab": "",
+                   "vht_oper_chwidth": "0",
+                   "vht_oper_centr_freq_seg0_idx": "0",
+                   "wep_key0": '"hello"' }
+        hapd = hostapd.add_ap(apdev[0], params)
+        dev[0].connect("test-vht40-wep", scan_freq="5180", key_mgmt="NONE",
+                       wep_key0='"hello"')
+        hwsim_utils.test_connectivity(dev[0], hapd)
+        status = hapd.get_status()
+        logger.info("hostapd STATUS: " + str(status))
+        if status["ieee80211n"] != "0":
+            raise Exception("Unexpected STATUS ieee80211n value")
+        if status["ieee80211ac"] != "0":
+            raise Exception("Unexpected STATUS ieee80211ac value")
+        if status["secondary_channel"] != "0":
+            raise Exception("Unexpected STATUS secondary_channel value")
+    finally:
+        dev[0].request("DISCONNECT")
+        if hapd:
+            hapd.request("DISABLE")
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        dev[0].flush_scan_cache()
index 83bd8dd..9c1c0c8 100644 (file)
@@ -31,7 +31,7 @@ def test_wext_open(dev, apdev):
     wpas = get_wext_interface()
 
     params = { "ssid": "wext-open" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     wpas.connect("wext-open", key_mgmt="NONE")
     hwsim_utils.test_connectivity(wpas, hapd)
@@ -41,7 +41,7 @@ def test_wext_wpa2_psk(dev, apdev):
     wpas = get_wext_interface()
 
     params = hostapd.wpa2_params(ssid="wext-wpa2-psk", passphrase="12345678")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     wpas.connect("wext-wpa2-psk", psk="12345678")
     hwsim_utils.test_connectivity(wpas, hapd)
@@ -58,7 +58,7 @@ def test_wext_wpa_psk(dev, apdev):
     wpas = get_wext_interface()
 
     params = hostapd.wpa_params(ssid="wext-wpa-psk", passphrase="12345678")
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     testfile = "/sys/kernel/debug/ieee80211/%s/netdev:%s/tkip_mic_test" % (hapd.get_driver_status_field("phyname"), apdev[0]['ifname'])
     if not os.path.exists(testfile):
         wpas.close_ctrl()
@@ -85,7 +85,7 @@ def test_wext_pmksa_cache(dev, apdev):
     wpas = get_wext_interface()
 
     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     bssid = apdev[0]['bssid']
     wpas.connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
                    eap="GPSK", identity="gpsk user",
@@ -97,7 +97,7 @@ def test_wext_pmksa_cache(dev, apdev):
     if pmksa['opportunistic'] != '0':
         raise Exception("Unexpected opportunistic PMKSA cache entry")
 
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
     bssid2 = apdev[1]['bssid']
 
     wpas.dump_monitor()
@@ -150,7 +150,7 @@ def test_wext_wep_open_auth(dev, apdev):
     """WEP Open System authentication"""
     wpas = get_wext_interface()
 
-    hapd = hostapd.add_ap(apdev[0]['ifname'],
+    hapd = hostapd.add_ap(apdev[0],
                           { "ssid": "wep-open",
                             "wep_key0": '"hello"' })
     wpas.connect("wep-open", key_mgmt="NONE", wep_key0='"hello"',
@@ -163,7 +163,7 @@ def test_wext_wep_shared_key_auth(dev, apdev):
     """WEP Shared Key authentication"""
     wpas = get_wext_interface()
 
-    hapd = hostapd.add_ap(apdev[0]['ifname'],
+    hapd = hostapd.add_ap(apdev[0],
                           { "ssid": "wep-shared-key",
                             "wep_key0": '"hello12345678"',
                             "auth_algs": "2" })
@@ -180,9 +180,9 @@ def test_wext_pmf(dev, apdev):
     wpas = get_wext_interface()
 
     params = hostapd.wpa2_params(ssid="wext-wpa2-psk", passphrase="12345678")
-    params["wpa_key_mgmt"] = "WPA-PSK-SHA256";
-    params["ieee80211w"] = "2";
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
+    params["ieee80211w"] = "2"
+    hapd = hostapd.add_ap(apdev[0], params)
 
     wpas.connect("wext-wpa2-psk", psk="12345678", ieee80211w="1",
                  key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
@@ -197,10 +197,10 @@ def test_wext_scan_hidden(dev, apdev):
     """WEXT with hidden SSID"""
     wpas = get_wext_interface()
 
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "test-scan",
-                                                "ignore_broadcast_ssid": "1" })
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], { "ssid": "test-scan2",
-                                                 "ignore_broadcast_ssid": "1" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "test-scan",
+                                      "ignore_broadcast_ssid": "1" })
+    hapd2 = hostapd.add_ap(apdev[1], { "ssid": "test-scan2",
+                                       "ignore_broadcast_ssid": "1" })
 
     id1 = wpas.connect("test-scan", key_mgmt="NONE", scan_ssid="1",
                        only_add_network=True)
@@ -234,7 +234,7 @@ def test_wext_rfkill(dev, apdev):
 
     wpas = get_wext_interface()
 
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     wpas.connect("open", key_mgmt="NONE", scan_freq="2412")
     try:
         logger.info("rfkill block")
index c30436e..ffdbcbe 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import binascii
 import struct
 import time
@@ -12,8 +13,11 @@ logger = logging.getLogger()
 import subprocess
 
 import hostapd
+from wpasupplicant import WpaSupplicant
+from utils import alloc_fail, wait_fail_trigger
 from wlantest import Wlantest
 
+@remote_compatible
 def test_wnm_bss_transition_mgmt(dev, apdev):
     """WNM BSS Transition Management"""
     params = { "ssid": "test-wnm",
@@ -21,11 +25,12 @@ def test_wnm_bss_transition_mgmt(dev, apdev):
                "time_zone": "EST5",
                "wnm_sleep_mode": "1",
                "bss_transition": "1" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
     dev[0].request("WNM_BSS_QUERY 0")
 
+@remote_compatible
 def test_wnm_disassoc_imminent(dev, apdev):
     """WNM Disassociation Imminent"""
     params = { "ssid": "test-wnm",
@@ -33,8 +38,7 @@ def test_wnm_disassoc_imminent(dev, apdev):
                "time_zone": "EST5",
                "wnm_sleep_mode": "1",
                "bss_transition": "1" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
     addr = dev[0].p2p_interface_addr()
@@ -48,6 +52,7 @@ def test_wnm_disassoc_imminent(dev, apdev):
     if ev is None:
         raise Exception("Timeout while waiting for re-connection scan")
 
+@remote_compatible
 def test_wnm_ess_disassoc_imminent(dev, apdev):
     """WNM ESS Disassociation Imminent"""
     params = { "ssid": "test-wnm",
@@ -55,8 +60,7 @@ def test_wnm_ess_disassoc_imminent(dev, apdev):
                "time_zone": "EST5",
                "wnm_sleep_mode": "1",
                "bss_transition": "1" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
     addr = dev[0].p2p_interface_addr()
@@ -70,14 +74,34 @@ def test_wnm_ess_disassoc_imminent(dev, apdev):
     if ev is None:
         raise Exception("Timeout while waiting for re-connection scan")
 
+def test_wnm_ess_disassoc_imminent_reject(dev, apdev):
+    """WNM ESS Disassociation Imminent getting rejected"""
+    params = { "ssid": "test-wnm",
+               "bss_transition": "1" }
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
+    addr = dev[0].own_addr()
+    if "OK" not in dev[0].request("SET reject_btm_req_reason 123"):
+        raise Exception("Failed to set reject_btm_req_reason")
+
+    hapd.request("ESS_DISASSOC " + addr + " 1 http://example.com/session-info")
+    ev = hapd.wait_event(["BSS-TM-RESP"], timeout=10)
+    if ev is None:
+        raise Exception("BSS-TM-RESP not seen")
+    if "status_code=123" not in ev:
+        raise Exception("Unexpected response status: " + ev)
+    dev[0].wait_disconnected()
+    dev[0].request("DISCONNECT")
+
+@remote_compatible
 def test_wnm_ess_disassoc_imminent_pmf(dev, apdev):
     """WNM ESS Disassociation Imminent"""
     params = hostapd.wpa2_params("test-wnm-rsn", "12345678")
-    params["wpa_key_mgmt"] = "WPA-PSK-SHA256";
-    params["ieee80211w"] = "2";
+    params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
+    params["ieee80211w"] = "2"
     params["bss_transition"] = "1"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-wnm-rsn", psk="12345678", ieee80211w="2",
                    key_mgmt="WPA-PSK-SHA256", proto="WPA2", scan_freq="2412")
@@ -128,6 +152,7 @@ def check_wnm_sleep_mode_enter_exit(hapd, dev, interval=None, tfs_req=None):
     if not ok:
         raise Exception("Station failed to exit WNM-Sleep Mode")
 
+@remote_compatible
 def test_wnm_sleep_mode_open(dev, apdev):
     """WNM Sleep Mode - open"""
     params = { "ssid": "test-wnm",
@@ -135,8 +160,7 @@ def test_wnm_sleep_mode_open(dev, apdev):
                "time_zone": "EST5",
                "wnm_sleep_mode": "1",
                "bss_transition": "1" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
     ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
@@ -153,6 +177,7 @@ def test_wnm_sleep_mode_open(dev, apdev):
         if "FAIL" not in dev[0].request("WNM_SLEEP " + cmd):
             raise Exception("Invalid WNM_SLEEP accepted")
 
+@remote_compatible
 def test_wnm_sleep_mode_rsn(dev, apdev):
     """WNM Sleep Mode - RSN"""
     params = hostapd.wpa2_params("test-wnm-rsn", "12345678")
@@ -160,8 +185,7 @@ def test_wnm_sleep_mode_rsn(dev, apdev):
     params["time_zone"] = "EST5"
     params["wnm_sleep_mode"] = "1"
     params["bss_transition"] = "1"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
 
     dev[0].connect("test-wnm-rsn", psk="12345678", scan_freq="2412")
     ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
@@ -169,20 +193,40 @@ def test_wnm_sleep_mode_rsn(dev, apdev):
         raise Exception("No connection event received from hostapd")
     check_wnm_sleep_mode_enter_exit(hapd, dev[0])
 
+@remote_compatible
+def test_wnm_sleep_mode_ap_oom(dev, apdev):
+    """WNM Sleep Mode - AP side OOM"""
+    params = { "ssid": "test-wnm",
+               "wnm_sleep_mode": "1" }
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
+    ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
+    if ev is None:
+        raise Exception("No connection event received from hostapd")
+    with alloc_fail(hapd, 1, "ieee802_11_send_wnmsleep_resp"):
+        dev[0].request("WNM_SLEEP enter")
+        wait_fail_trigger(hapd, "GET_ALLOC_FAIL")
+    with alloc_fail(hapd, 2, "ieee802_11_send_wnmsleep_resp"):
+        dev[0].request("WNM_SLEEP exit")
+        wait_fail_trigger(hapd, "GET_ALLOC_FAIL")
+
+@remote_compatible
 def test_wnm_sleep_mode_rsn_pmf(dev, apdev):
     """WNM Sleep Mode - RSN with PMF"""
-    wt = Wlantest()
-    wt.flush()
-    wt.add_passphrase("12345678")
     params = hostapd.wpa2_params("test-wnm-rsn", "12345678")
-    params["wpa_key_mgmt"] = "WPA-PSK-SHA256";
-    params["ieee80211w"] = "2";
+    params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
+    params["ieee80211w"] = "2"
     params["time_advertisement"] = "2"
     params["time_zone"] = "EST5"
     params["wnm_sleep_mode"] = "1"
     params["bss_transition"] = "1"
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    hapd = hostapd.Hostapd(apdev[0]['ifname'])
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    Wlantest.setup(hapd)
+    wt = Wlantest()
+    wt.flush()
+    wt.add_passphrase("12345678")
 
     dev[0].connect("test-wnm-rsn", psk="12345678", ieee80211w="2",
                    key_mgmt="WPA-PSK-SHA256", proto="WPA2", scan_freq="2412")
@@ -195,6 +239,24 @@ MGMT_SUBTYPE_ACTION = 13
 ACTION_CATEG_WNM = 10
 WNM_ACT_BSS_TM_REQ = 7
 WNM_ACT_BSS_TM_RESP = 8
+WNM_ACT_SLEEP_MODE_REQ = 16
+WNM_ACT_SLEEP_MODE_RESP = 17
+WNM_ACT_NOTIFICATION_REQ = 26
+WNM_ACT_NOTIFICATION_RESP = 27
+WNM_NOTIF_TYPE_FW_UPGRADE = 0
+WNM_NOTIF_TYPE_WFA = 1
+WLAN_EID_TFS_RESP = 92
+WLAN_EID_WNMSLEEP = 93
+WNM_SLEEP_MODE_ENTER = 0
+WNM_SLEEP_MODE_EXIT = 1
+WNM_STATUS_SLEEP_ACCEPT = 0
+WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE = 1
+WNM_STATUS_DENIED_ACTION = 2
+WNM_STATUS_DENIED_TMP = 3
+WNM_STATUS_DENIED_KEY = 4
+WNM_STATUS_DENIED_OTHER_WNM_SERVICE = 5
+WNM_SLEEP_SUBELEM_GTK = 0
+WNM_SLEEP_SUBELEM_IGTK = 1
 
 def bss_tm_req(dst, src, dialog_token=1, req_mode=0, disassoc_timer=0,
                validity_interval=1):
@@ -247,12 +309,13 @@ def expect_ack(hapd):
     if "ok=1" not in ev:
         raise Exception("Action frame not acknowledged")
 
+@remote_compatible
 def test_wnm_bss_tm_req(dev, apdev):
     """BSS Transition Management Request"""
     params = { "ssid": "test-wnm", "bss_transition": "1" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
-    hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+    hapd2 = hostapd.add_ap(apdev[1], params)
 
     hapd.set("ext_mgmt_frame_handling", "1")
 
@@ -383,11 +446,23 @@ def test_wnm_bss_tm_req(dev, apdev):
     hapd.mgmt_tx(req)
     resp = rx_bss_tm_resp(hapd, expect_dialog=8, expect_status=7)
 
+    # Preferred Candidate List followed by vendor element
+    req = bss_tm_req(dev[0].p2p_interface_addr(), apdev[0]['bssid'],
+                     req_mode=0x01, dialog_token=8)
+    subelems = ""
+    req['payload'] += struct.pack("<BB6BLBBB", 52, 13 + len(subelems),
+                                  1, 2, 3, 4, 5, 6,
+                                  0, 81, 1, 7) + subelems
+    req['payload'] += binascii.unhexlify("DD0411223344")
+    hapd.mgmt_tx(req)
+    resp = rx_bss_tm_resp(hapd, expect_dialog=8, expect_status=7)
+
+@remote_compatible
 def test_wnm_bss_keep_alive(dev, apdev):
     """WNM keep-alive"""
     params = { "ssid": "test-wnm",
                "ap_max_inactivity": "1" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
 
     addr = dev[0].p2p_interface_addr()
     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
@@ -426,7 +501,7 @@ def test_wnm_bss_tm(dev, apdev):
                    "hw_mode": "g",
                    "channel": "1",
                    "bss_transition": "1" }
-        hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+        hapd = hostapd.add_ap(apdev[0], params)
 
         id = dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
         dev[0].set_network(id, "scan_freq", "")
@@ -437,7 +512,7 @@ def test_wnm_bss_tm(dev, apdev):
                    "hw_mode": "a",
                    "channel": "36",
                    "bss_transition": "1" }
-        hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
+        hapd2 = hostapd.add_ap(apdev[1], params)
 
         addr = dev[0].p2p_interface_addr()
         dev[0].dump_monitor()
@@ -510,7 +585,153 @@ def test_wnm_bss_tm(dev, apdev):
             raise Exception("Unexpected scan started")
         ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=0.5)
         if ev is not None:
-            raise Exception("Unexpected reassociation");
+            raise Exception("Unexpected reassociation")
+    finally:
+        dev[0].request("DISCONNECT")
+        if hapd:
+            hapd.request("DISABLE")
+        if hapd2:
+            hapd2.request("DISABLE")
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        dev[0].flush_scan_cache()
+
+def test_wnm_bss_tm_scan_not_needed(dev, apdev):
+    """WNM BSS Transition Management and scan not needed"""
+    run_wnm_bss_tm_scan_not_needed(dev, apdev)
+
+def test_wnm_bss_tm_nei_vht(dev, apdev):
+    """WNM BSS Transition Management and VHT neighbor"""
+    run_wnm_bss_tm_scan_not_needed(dev, apdev, vht=True, nei_info="115,36,9")
+
+def test_wnm_bss_tm_nei_11a(dev, apdev):
+    """WNM BSS Transition Management and 11a neighbor"""
+    run_wnm_bss_tm_scan_not_needed(dev, apdev, ht=False, nei_info="115,36,4")
+
+def test_wnm_bss_tm_nei_11g(dev, apdev):
+    """WNM BSS Transition Management and 11g neighbor"""
+    run_wnm_bss_tm_scan_not_needed(dev, apdev, ht=False, hwmode='g',
+                                   channel='2', freq=2417, nei_info="81,2,6")
+
+def test_wnm_bss_tm_nei_11b(dev, apdev):
+    """WNM BSS Transition Management and 11g neighbor"""
+    run_wnm_bss_tm_scan_not_needed(dev, apdev, ht=False, hwmode='b',
+                                   channel='3', freq=2422, nei_info="81,2,5")
+
+def run_wnm_bss_tm_scan_not_needed(dev, apdev, ht=True, vht=False, hwmode='a',
+                                   channel='36', freq=5180,
+                                   nei_info="115,36,7,0301ff"):
+    try:
+        hapd = None
+        hapd2 = None
+        params = { "ssid": "test-wnm",
+                   "country_code": "FI",
+                   "ieee80211d": "1",
+                   "hw_mode": "g",
+                   "channel": "1",
+                   "bss_transition": "1" }
+        hapd = hostapd.add_ap(apdev[0], params)
+
+        params = { "ssid": "test-wnm",
+                   "country_code": "FI",
+                   "ieee80211d": "1",
+                   "hw_mode": hwmode,
+                   "channel": channel,
+                   "bss_transition": "1" }
+        if not ht:
+            params['ieee80211n'] = '0'
+        if vht:
+            params['ieee80211ac'] = "1"
+            params["vht_oper_chwidth"] = "0"
+            params["vht_oper_centr_freq_seg0_idx"] = "0"
+
+        hapd2 = hostapd.add_ap(apdev[1], params)
+
+        dev[0].scan_for_bss(apdev[1]['bssid'], freq)
+
+        id = dev[0].connect("test-wnm", key_mgmt="NONE",
+                            bssid=apdev[0]['bssid'], scan_freq="2412")
+        dev[0].set_network(id, "scan_freq", "")
+        dev[0].set_network(id, "bssid", "")
+
+        addr = dev[0].own_addr()
+        dev[0].dump_monitor()
+
+        logger.info("Preferred Candidate List (matching neighbor for another BSS) without Disassociation Imminent")
+        if "OK" not in hapd.request("BSS_TM_REQ " + addr + " pref=1 abridged=1 valid_int=255 neighbor=" + apdev[1]['bssid'] + ",0x0000," + nei_info):
+            raise Exception("BSS_TM_REQ command failed")
+        ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
+        if ev is None:
+            raise Exception("No BSS Transition Management Response")
+        if "status_code=0" not in ev:
+            raise Exception("BSS transition request was not accepted: " + ev)
+        if "target_bssid=" + apdev[1]['bssid'] not in ev:
+            raise Exception("Unexpected target BSS: " + ev)
+        dev[0].wait_connected(timeout=15, error="No reassociation seen")
+        if apdev[1]['bssid'] not in ev:
+            raise Exception("Unexpected reassociation target: " + ev)
+        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=0.1)
+        if ev is not None:
+            raise Exception("Unexpected scan started")
+        dev[0].dump_monitor()
+    finally:
+        dev[0].request("DISCONNECT")
+        if hapd:
+            hapd.request("DISABLE")
+        if hapd2:
+            hapd2.request("DISABLE")
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        dev[0].flush_scan_cache()
+
+def test_wnm_bss_tm_scan_needed(dev, apdev):
+    """WNM BSS Transition Management and scan needed"""
+    try:
+        hapd = None
+        hapd2 = None
+        params = { "ssid": "test-wnm",
+                   "country_code": "FI",
+                   "ieee80211d": "1",
+                   "hw_mode": "g",
+                   "channel": "1",
+                   "bss_transition": "1" }
+        hapd = hostapd.add_ap(apdev[0], params)
+
+        params = { "ssid": "test-wnm",
+                   "country_code": "FI",
+                   "ieee80211d": "1",
+                   "hw_mode": "a",
+                   "channel": "36",
+                   "bss_transition": "1" }
+        hapd2 = hostapd.add_ap(apdev[1], params)
+
+        dev[0].scan_for_bss(apdev[1]['bssid'], 5180)
+
+        id = dev[0].connect("test-wnm", key_mgmt="NONE",
+                            bssid=apdev[0]['bssid'], scan_freq="2412")
+        dev[0].set_network(id, "scan_freq", "")
+        dev[0].set_network(id, "bssid", "")
+
+        addr = dev[0].own_addr()
+        dev[0].dump_monitor()
+
+        logger.info("Wait 11 seconds for the last scan result to be too old, but still present in BSS table")
+        time.sleep(11)
+        logger.info("Preferred Candidate List (matching neighbor for another BSS) without Disassociation Imminent")
+        if "OK" not in hapd.request("BSS_TM_REQ " + addr + " pref=1 abridged=1 valid_int=255 neighbor=" + apdev[1]['bssid'] + ",0x0000,115,36,7,0301ff"):
+            raise Exception("BSS_TM_REQ command failed")
+        ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
+        if ev is None:
+            raise Exception("No BSS Transition Management Response")
+        if "status_code=0" not in ev:
+            raise Exception("BSS transition request was not accepted: " + ev)
+        if "target_bssid=" + apdev[1]['bssid'] not in ev:
+            raise Exception("Unexpected target BSS: " + ev)
+        dev[0].wait_connected(timeout=15, error="No reassociation seen")
+        if apdev[1]['bssid'] not in ev:
+            raise Exception("Unexpected reassociation target: " + ev)
+        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=0.1)
+        if ev is not None:
+            raise Exception("Unexpected scan started")
+        dev[0].dump_monitor()
     finally:
         dev[0].request("DISCONNECT")
         if hapd:
@@ -527,7 +748,7 @@ def start_wnm_tm(ap, country, dev):
                "hw_mode": "g",
                "channel": "1",
                "bss_transition": "1" }
-    hapd = hostapd.add_ap(ap['ifname'], params)
+    hapd = hostapd.add_ap(ap, params)
     id = dev.connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
     dev.dump_monitor()
     dev.set_network(id, "scan_freq", "")
@@ -653,3 +874,569 @@ def test_wnm_bss_tm_global(dev, apdev):
         wnm_bss_tm_check(hapd, dev[0], "pref=1 neighbor=00:11:22:33:44:00,0x0000,124,162,7 neighbor=00:11:22:33:44:01,0x0000,125,148,7 neighbor=00:11:22:33:44:02,0x0000,125,170,7 neighbor=00:11:22:33:44:03,0x0000,128,35,7 neighbor=00:11:22:33:44:04,0x0000,128,162,7 neighbor=00:11:22:33:44:05,0x0000,129,49,7 neighbor=00:11:22:33:44:06,0x0000,129,115,7 neighbor=00:11:22:33:44:07,0x0000,180,0,7 neighbor=00:11:22:33:44:08,0x0000,180,5,7 neighbor=00:11:22:33:44:09,0x0000,0,0,7")
     finally:
         stop_wnm_tm(hapd, dev[0])
+
+def test_wnm_bss_tm_op_class_0(dev, apdev):
+    """WNM BSS Transition Management with invalid operating class"""
+    try:
+        hapd = None
+        hapd, id = start_wnm_tm(apdev[0], "US", dev[0])
+
+        logger.info("Preferred Candidate List (no matching neighbor, invalid op class specified for channels)")
+        wnm_bss_tm_check(hapd, dev[0], "pref=1 neighbor=00:11:22:33:44:59,0x0000,0,149,7 neighbor=00:11:22:33:44:5b,0x0000,0,1,7")
+    finally:
+        stop_wnm_tm(hapd, dev[0])
+
+def test_wnm_action_proto(dev, apdev):
+    """WNM Action protocol testing"""
+    params = { "ssid": "test-wnm" }
+    params['wnm_sleep_mode'] = '1'
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+    dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
+    dev[0].request("WNM_SLEEP enter")
+    time.sleep(0.1)
+    hapd.set("ext_mgmt_frame_handling", "1")
+
+    msg = {}
+    msg['fc'] = MGMT_SUBTYPE_ACTION << 4
+    msg['da'] = dev[0].own_addr()
+    msg['sa'] = bssid
+    msg['bssid'] = bssid
+
+    dialog_token = 1
+
+    logger.debug("Unexpected WNM-Notification Response")
+    # Note: This is actually not registered for user space processing in
+    # driver_nl80211.c nl80211_mgmt_subscribe_non_ap() and as such, won't make
+    # it to wpa_supplicant.
+    msg['payload'] = struct.pack("<BBBB",
+                                 ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_RESP,
+                                 dialog_token, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("Truncated WNM-Notification Request (no Type field)")
+    msg['payload'] = struct.pack("<BBB",
+                                 ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
+                                 dialog_token)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WFA WNM-Notification Request with truncated IE (min)")
+    msg['payload'] = struct.pack("<BBBBBB",
+                                 ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
+                                 dialog_token, WNM_NOTIF_TYPE_WFA, 0, 1)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WFA WNM-Notification Request with truncated IE (max)")
+    msg['payload'] = struct.pack("<BBBBBB",
+                                 ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
+                                 dialog_token, WNM_NOTIF_TYPE_WFA, 0, 255)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WFA WNM-Notification Request with too short IE")
+    msg['payload'] = struct.pack("<BBBBBB",
+                                 ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
+                                 dialog_token, WNM_NOTIF_TYPE_WFA, 0, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WFA WNM-Notification Request with truncated Sub Rem URL")
+    msg['payload'] = struct.pack(">BBBBBBLB",
+                                 ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
+                                 dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 5,
+                                 0x506f9a00, 1)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WFA WNM-Notification Request with truncated Sub Rem URL(2)")
+    msg['payload'] = struct.pack(">BBBBBBLBB",
+                                 ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
+                                 dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 6,
+                                 0x506f9a00, 1, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WFA WNM-Notification Request with truncated Sub Rem URL(3)")
+    msg['payload'] = struct.pack(">BBBBBBLB",
+                                 ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
+                                 dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 5,
+                                 0x506f9a00, 0xff)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WFA WNM-Notification Request with truncated Deauth Imminent URL(min)")
+    msg['payload'] = struct.pack(">BBBBBBLBHB",
+                                 ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
+                                 dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 8,
+                                 0x506f9a01, 0, 0, 1)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WFA WNM-Notification Request with truncated Deauth Imminent URL(max)")
+    msg['payload'] = struct.pack(">BBBBBBLBHB",
+                                 ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
+                                 dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 8,
+                                 0x506f9a01, 0, 0, 0xff)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WFA WNM-Notification Request with unsupported IE")
+    msg['payload'] = struct.pack("<BBBBBBL",
+                                 ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
+                                 dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 4, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WNM-Notification Request with unknown WNM-Notification type 0")
+    msg['payload'] = struct.pack("<BBBB",
+                                 ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
+                                 dialog_token, WNM_NOTIF_TYPE_FW_UPGRADE)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("Truncated WNM Sleep Mode Response - no Dialog Token")
+    msg['payload'] = struct.pack("<BB",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("Truncated WNM Sleep Mode Response - no Key Data Length")
+    msg['payload'] = struct.pack("<BBB",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("Truncated WNM Sleep Mode Response - truncated Key Data (min)")
+    msg['payload'] = struct.pack("<BBBH",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
+                                 1)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("Truncated WNM Sleep Mode Response - truncated Key Data (max)")
+    msg['payload'] = struct.pack("<BBBH",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
+                                 0xffff)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WNM Sleep Mode Response - truncated IE header")
+    msg['payload'] = struct.pack("<BBBHB",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
+                                 0, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WNM Sleep Mode Response - truncated IE")
+    msg['payload'] = struct.pack("<BBBHBB",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
+                                 0, 0, 1)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WNM Sleep Mode Response - Empty TFS Response")
+    msg['payload'] = struct.pack("<BBBHBB",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
+                                 0, WLAN_EID_TFS_RESP, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WNM Sleep Mode Response - EID 0 not recognized")
+    msg['payload'] = struct.pack("<BBBHBB",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
+                                 0, 0, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WNM Sleep Mode Response - Empty WNM Sleep Mode element and TFS Response element")
+    msg['payload'] = struct.pack("<BBBHBBBB",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
+                                 0, WLAN_EID_WNMSLEEP, 0, WLAN_EID_TFS_RESP, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WNM Sleep Mode Response - WNM Sleep Mode element and empty TFS Response element")
+    msg['payload'] = struct.pack("<BBBHBBBBHBB",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
+                                 0, WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_ENTER,
+                                 WNM_STATUS_SLEEP_ACCEPT, 0,
+                                 WLAN_EID_TFS_RESP, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WNM Sleep Mode Response - WNM Sleep Mode element(exit, deny key) and empty TFS Response element")
+    msg['payload'] = struct.pack("<BBBHBBBBHBB",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
+                                 0, WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
+                                 WNM_STATUS_DENIED_KEY, 0,
+                                 WLAN_EID_TFS_RESP, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WNM Sleep Mode Response - WNM Sleep Mode element(enter, deny key) and empty TFS Response element")
+    msg['payload'] = struct.pack("<BBBHBBBBHBB",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
+                                 0, WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_ENTER,
+                                 WNM_STATUS_DENIED_KEY, 0,
+                                 WLAN_EID_TFS_RESP, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+@remote_compatible
+def test_wnm_action_proto_pmf(dev, apdev):
+    """WNM Action protocol testing (PMF enabled)"""
+    ssid = "test-wnm-pmf"
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
+    params["ieee80211w"] = "2"
+    params['wnm_sleep_mode'] = '1'
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+    dev[0].connect(ssid, psk="12345678", key_mgmt="WPA-PSK-SHA256",
+                   proto="WPA2", ieee80211w="2", scan_freq="2412")
+    dev[0].request("WNM_SLEEP enter")
+    time.sleep(0.1)
+    hapd.set("ext_mgmt_frame_handling", "1")
+
+    msg = {}
+    msg['fc'] = MGMT_SUBTYPE_ACTION << 4
+    msg['da'] = dev[0].own_addr()
+    msg['sa'] = bssid
+    msg['bssid'] = bssid
+
+    logger.debug("WNM Sleep Mode Response - Invalid Key Data element length")
+    keydata = struct.pack("<BB", 0, 1)
+    msg['payload'] = struct.pack("<BBBH",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
+                                 len(keydata))
+    msg['payload'] += keydata
+    msg['payload'] += struct.pack("<BBBBHBB",
+                                  WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
+                                  WNM_STATUS_SLEEP_ACCEPT, 0,
+                                  WLAN_EID_TFS_RESP, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WNM Sleep Mode Response - Too short GTK subelem")
+    keydata = struct.pack("<BB", WNM_SLEEP_SUBELEM_GTK, 0)
+    msg['payload'] = struct.pack("<BBBH",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
+                                 len(keydata))
+    msg['payload'] += keydata
+    msg['payload'] += struct.pack("<BBBBHBB",
+                                  WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
+                                  WNM_STATUS_SLEEP_ACCEPT, 0,
+                                  WLAN_EID_TFS_RESP, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WNM Sleep Mode Response - Invalid GTK subelem")
+    keydata = struct.pack("<BBHB2L4L", WNM_SLEEP_SUBELEM_GTK, 11 + 16,
+                          0, 17, 0, 0, 0, 0, 0, 0)
+    msg['payload'] = struct.pack("<BBBH",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
+                                 len(keydata))
+    msg['payload'] += keydata
+    msg['payload'] += struct.pack("<BBBBHBB",
+                                  WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
+                                  WNM_STATUS_SLEEP_ACCEPT, 0,
+                                  WLAN_EID_TFS_RESP, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WNM Sleep Mode Response - Invalid GTK subelem (2)")
+    keydata = struct.pack("<BBHB2L4L", WNM_SLEEP_SUBELEM_GTK, 11 + 16,
+                          0, 0, 0, 0, 0, 0, 0, 0)
+    msg['payload'] = struct.pack("<BBBH",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
+                                 len(keydata))
+    msg['payload'] += keydata
+    msg['payload'] += struct.pack("<BBBBHBB",
+                                  WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
+                                  WNM_STATUS_SLEEP_ACCEPT, 0,
+                                  WLAN_EID_TFS_RESP, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WNM Sleep Mode Response - GTK subelem and too short IGTK subelem")
+    keydata = struct.pack("<BBHB", WNM_SLEEP_SUBELEM_GTK, 11 + 16, 0, 16)
+    keydata += struct.pack(">2L4L", 0x01020304, 0x05060708,
+                           0x11223344, 0x55667788, 0x9900aabb, 0xccddeeff)
+    keydata += struct.pack("<BB", WNM_SLEEP_SUBELEM_IGTK, 0)
+    msg['payload'] = struct.pack("<BBBH",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
+                                 len(keydata))
+    msg['payload'] += keydata
+    msg['payload'] += struct.pack("<BBBBHBB",
+                                  WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
+                                  WNM_STATUS_SLEEP_ACCEPT, 0,
+                                  WLAN_EID_TFS_RESP, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    logger.debug("WNM Sleep Mode Response - Unknown subelem")
+    keydata = struct.pack("<BB", 255, 0)
+    msg['payload'] = struct.pack("<BBBH",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
+                                 len(keydata))
+    msg['payload'] += keydata
+    msg['payload'] += struct.pack("<BBBBHBB",
+                                  WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
+                                  WNM_STATUS_SLEEP_ACCEPT, 0,
+                                  WLAN_EID_TFS_RESP, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+@remote_compatible
+def test_wnm_action_proto_no_pmf(dev, apdev):
+    """WNM Action protocol testing (PMF disabled)"""
+    ssid = "test-wnm-no-pmf"
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    params['wnm_sleep_mode'] = '1'
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+    dev[0].connect(ssid, psk="12345678", key_mgmt="WPA-PSK",
+                   proto="WPA2", ieee80211w="0", scan_freq="2412")
+    dev[0].request("WNM_SLEEP enter")
+    time.sleep(0.1)
+    hapd.set("ext_mgmt_frame_handling", "1")
+
+    msg = {}
+    msg['fc'] = MGMT_SUBTYPE_ACTION << 4
+    msg['da'] = dev[0].own_addr()
+    msg['sa'] = bssid
+    msg['bssid'] = bssid
+
+    logger.debug("WNM Sleep Mode Response - GTK subelem and IGTK subelem")
+    keydata = struct.pack("<BBHB", WNM_SLEEP_SUBELEM_GTK, 11 + 16, 0, 16)
+    keydata += struct.pack(">2L4L", 0x01020304, 0x05060708,
+                           0x11223344, 0x55667788, 0x9900aabb, 0xccddeeff)
+    keydata += struct.pack("<BBHLH4L", WNM_SLEEP_SUBELEM_IGTK, 2 + 6 + 16, 0,
+                           0x10203040, 0x5060,
+                           0xf1f2f3f4, 0xf5f6f7f8, 0xf9f0fafb, 0xfcfdfeff)
+    msg['payload'] = struct.pack("<BBBH",
+                                 ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
+                                 len(keydata))
+    msg['payload'] += keydata
+    msg['payload'] += struct.pack("<BBBBHBB",
+                                  WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
+                                  WNM_STATUS_SLEEP_ACCEPT, 0,
+                                  WLAN_EID_TFS_RESP, 0)
+    hapd.mgmt_tx(msg)
+    expect_ack(hapd)
+
+    ev = dev[0].wait_event(["WNM: Ignore Key Data"], timeout=5)
+    if ev is None:
+        raise Exception("Key Data not ignored")
+
+def test_wnm_bss_tm_req_with_mbo_ie(dev, apdev):
+    """WNM BSS transition request with MBO IE and reassociation delay attribute"""
+    ssid = "test-wnm-mbo"
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+    if "OK" not in dev[0].request("SET mbo_cell_capa 1"):
+        raise Exception("Failed to set STA as cellular data capable")
+
+    dev[0].connect(ssid, psk="12345678", key_mgmt="WPA-PSK",
+                   proto="WPA2", ieee80211w="0", scan_freq="2412")
+
+    logger.debug("BTM request with MBO reassociation delay when disassoc imminent is not set")
+    if 'FAIL' not in hapd.request("BSS_TM_REQ " + dev[0].own_addr() + " mbo=3:2:1"):
+        raise Exception("BSS transition management succeeded unexpectedly")
+
+    logger.debug("BTM request with invalid MBO transition reason code")
+    if 'FAIL' not in hapd.request("BSS_TM_REQ " + dev[0].own_addr() + " mbo=10:2:1"):
+        raise Exception("BSS transition management succeeded unexpectedly")
+
+    logger.debug("BTM request with MBO reassociation retry delay of 5 seconds")
+    if 'OK' not in hapd.request("BSS_TM_REQ " + dev[0].own_addr() + " disassoc_imminent=1 disassoc_timer=3 mbo=3:5:1"):
+        raise Exception("BSS transition management command failed")
+
+    ev = dev[0].wait_event(['MBO-CELL-PREFERENCE'], 1)
+    if ev is None or "preference=1" not in ev:
+        raise Exception("Timeout waiting for MBO-CELL-PREFERENCE event")
+
+    ev = dev[0].wait_event(['MBO-TRANSITION-REASON'], 1)
+    if ev is None or "reason=3" not in ev:
+        raise Exception("Timeout waiting for MBO-TRANSITION-REASON event")
+
+    ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
+    if ev is None:
+        raise Exception("No BSS Transition Management Response")
+    if dev[0].own_addr() not in ev:
+        raise Exception("Unexpected BSS Transition Management Response address")
+
+    ev = dev[0].wait_event(['CTRL-EVENT-DISCONNECTED'], 5)
+    if ev is None:
+        raise Exception("Station did not disconnect although disassoc imminent was set")
+
+    # Set the scan interval to make dev[0] look for connections
+    if 'OK' not in dev[0].request("SCAN_INTERVAL 1"):
+        raise Exception("Failed to set scan interval")
+
+    # Make sure no connection is made during the retry delay
+    ev = dev[0].wait_event(['CTRL-EVENT-CONNECTED'], 5)
+    if ev is not None:
+        raise Exception("Station connected before assoc retry delay was over")
+
+    # After the assoc retry delay is over, we can reconnect
+    ev = dev[0].wait_event(['CTRL-EVENT-CONNECTED'], 5)
+    if ev is None:
+        raise Exception("Station did not connect after assoc retry delay is over")
+
+    if "OK" not in dev[0].request("SET mbo_cell_capa 3"):
+        raise Exception("Failed to set STA as cellular data not-capable")
+
+@remote_compatible
+def test_wnm_bss_transition_mgmt_query(dev, apdev):
+    """WNM BSS Transition Management query"""
+    params = { "ssid": "test-wnm",
+               "bss_transition": "1" }
+    hapd = hostapd.add_ap(apdev[0], params)
+    params = { "ssid": "another" }
+    hapd2 = hostapd.add_ap(apdev[1], params)
+
+    dev[0].scan_for_bss(apdev[1]['bssid'], 2412)
+    dev[0].scan_for_bss(apdev[0]['bssid'], 2412)
+
+    dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
+    dev[0].request("WNM_BSS_QUERY 0 list")
+
+    ev = dev[0].wait_event(["WNM: BSS Transition Management Request"],
+                           timeout=5)
+    if ev is None:
+        raise Exception("No BSS Transition Management Request frame seen")
+
+    ev = hapd.wait_event(["BSS-TM-RESP"], timeout=5)
+    if ev is None:
+        raise Exception("No BSS Transition Management Response frame seen")
+
+@remote_compatible
+def test_wnm_bss_tm_security_mismatch(dev, apdev):
+    """WNM BSS Transition Management and security mismatch"""
+    params = { "ssid": "test-wnm",
+               "wpa": "2",
+               "wpa_key_mgmt": "WPA-PSK",
+               "rsn_pairwise": "CCMP",
+               "wpa_passphrase": "12345678",
+               "hw_mode": "g",
+               "channel": "1",
+               "bss_transition": "1" }
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    params = { "ssid": "test-wnm",
+               "hw_mode": "g",
+               "channel": "11",
+               "bss_transition": "1" }
+    hapd2 = hostapd.add_ap(apdev[1], params)
+
+    dev[0].scan_for_bss(apdev[1]['bssid'], 2462)
+
+    id = dev[0].connect("test-wnm", psk="12345678",
+                        bssid=apdev[0]['bssid'], scan_freq="2412")
+    dev[0].set_network(id, "scan_freq", "")
+    dev[0].set_network(id, "bssid", "")
+
+    addr = dev[0].own_addr()
+    dev[0].dump_monitor()
+
+    logger.info("Preferred Candidate List (matching neighbor for another BSS) without Disassociation Imminent")
+    if "OK" not in hapd.request("BSS_TM_REQ " + addr + " pref=1 abridged=1 valid_int=255 neighbor=" + apdev[1]['bssid'] + ",0x0000,115,36,7,0301ff"):
+        raise Exception("BSS_TM_REQ command failed")
+    ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
+    if ev is None:
+        raise Exception("No BSS Transition Management Response")
+    if "status_code=7" not in ev:
+        raise Exception("Unexpected BSS transition request response: " + ev)
+
+def test_wnm_bss_tm_connect_cmd(dev, apdev):
+    """WNM BSS Transition Management and cfg80211 connect command"""
+    params = { "ssid": "test-wnm",
+               "hw_mode": "g",
+               "channel": "1",
+               "bss_transition": "1" }
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    params = { "ssid": "test-wnm",
+               "hw_mode": "g",
+               "channel": "11",
+               "bss_transition": "1" }
+    hapd2 = hostapd.add_ap(apdev[1], params)
+
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
+
+    wpas.scan_for_bss(apdev[1]['bssid'], 2462)
+
+    id = wpas.connect("test-wnm", key_mgmt="NONE",
+                      bssid=apdev[0]['bssid'], scan_freq="2412")
+    wpas.set_network(id, "scan_freq", "")
+    wpas.set_network(id, "bssid", "")
+
+    addr = wpas.own_addr()
+    wpas.dump_monitor()
+
+    logger.info("Preferred Candidate List (matching neighbor for another BSS) without Disassociation Imminent")
+    if "OK" not in hapd.request("BSS_TM_REQ " + addr + " pref=1 abridged=1 valid_int=255 neighbor=" + apdev[1]['bssid'] + ",0x0000,115,36,7,0301ff"):
+        raise Exception("BSS_TM_REQ command failed")
+    ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
+    if ev is None:
+        raise Exception("No BSS Transition Management Response")
+    if "status_code=0" not in ev:
+        raise Exception("BSS transition request was not accepted: " + ev)
+    if "target_bssid=" + apdev[1]['bssid'] not in ev:
+        raise Exception("Unexpected target BSS: " + ev)
+    ev = wpas.wait_event(["CTRL-EVENT-CONNECTED",
+                          "CTRL-EVENT-DISCONNECTED"], timeout=10)
+    if ev is None:
+        raise Exception("No reassociation seen")
+    if "CTRL-EVENT-DISCONNECTED" in ev:
+        #TODO: Uncomment this once kernel side changes for Connect command
+        #reassociation are in upstream.
+        #raise Exception("Unexpected disconnection reported")
+        logger.info("Unexpected disconnection reported")
+        ev = wpas.wait_event(["CTRL-EVENT-CONNECTED"], timeout=10)
+        if ev is None:
+            raise Exception("No reassociation seen")
+    if apdev[1]['bssid'] not in ev:
+        raise Exception("Unexpected reassociation target: " + ev)
+
+def test_wnm_bss_tm_reject(dev, apdev):
+    """WNM BSS Transition Management request getting rejected"""
+    try:
+        hapd = None
+        params = { "ssid": "test-wnm",
+                   "country_code": "FI",
+                   "ieee80211d": "1",
+                   "hw_mode": "g",
+                   "channel": "1",
+                   "bss_transition": "1" }
+        hapd = hostapd.add_ap(apdev[0], params)
+
+        id = dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
+        addr = dev[0].own_addr()
+        dev[0].dump_monitor()
+
+        if "OK" not in dev[0].request("SET reject_btm_req_reason 123"):
+            raise Exception("Failed to set reject_btm_req_reason")
+
+        if "OK" not in hapd.request("BSS_TM_REQ " + addr + " disassoc_timer=1"):
+            raise Exception("BSS_TM_REQ command failed")
+        ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
+        if ev is None:
+            raise Exception("No BSS Transition Management Response")
+        if addr not in ev:
+            raise Exception("Unexpected BSS Transition Management Response address")
+        if "status_code=123" not in ev:
+            raise Exception("Unexpected BSS Transition Management Response status: " + ev)
+        dev[0].wait_disconnected()
+    finally:
+        dev[0].request("DISCONNECT")
+        if hapd:
+            hapd.request("DISABLE")
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        dev[0].flush_scan_cache()
index 53de399..5e0e816 100644 (file)
@@ -4,12 +4,14 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import time
 import logging
 logger = logging.getLogger()
 
 import hwsim_utils
-from utils import HwsimSkip
+from utils import HwsimSkip, alloc_fail
+from wpasupplicant import WpaSupplicant
 from test_p2p_channel import set_country
 
 def wait_ap_ready(dev):
@@ -76,6 +78,7 @@ def test_wpas_ap_open(dev):
     dev[1].request("DISCONNECT")
     dev[2].request("DISCONNECT")
 
+@remote_compatible
 def test_wpas_ap_wep(dev):
     """wpa_supplicant AP mode - WEP"""
     id = dev[0].add_network()
@@ -93,6 +96,7 @@ def test_wpas_ap_wep(dev):
     hwsim_utils.test_connectivity(dev[0], dev[1])
     dev[1].request("DISCONNECT")
 
+@remote_compatible
 def test_wpas_ap_no_ssid(dev):
     """wpa_supplicant AP mode - invalid network configuration"""
     id = dev[0].add_network()
@@ -105,6 +109,7 @@ def test_wpas_ap_no_ssid(dev):
     if ev is not None:
         raise Exception("Unexpected AP start")
 
+@remote_compatible
 def test_wpas_ap_default_frequency(dev):
     """wpa_supplicant AP mode - default frequency"""
     id = dev[0].add_network()
@@ -117,6 +122,7 @@ def test_wpas_ap_default_frequency(dev):
     dev[1].connect("wpas-ap-open", key_mgmt="NONE", scan_freq="2462")
     dev[1].request("DISCONNECT")
 
+@remote_compatible
 def test_wpas_ap_invalid_frequency(dev):
     """wpa_supplicant AP mode - invalid frequency configuration"""
     id = dev[0].add_network()
@@ -237,6 +243,25 @@ def test_wpas_ap_wps(dev):
     if "FAIL" not in dev[0].request("WPS_AP_PIN set"):
         raise Exception("Invalid WPS_AP_PIN command not rejected")
 
+def test_wpas_ap_wps_frag(dev):
+    """wpa_supplicant AP mode - WPS operations with fragmentation"""
+    id = dev[0].add_network()
+    dev[0].set_network(id, "mode", "2")
+    dev[0].set_network_quoted(id, "ssid", "wpas-ap-wps")
+    dev[0].set_network_quoted(id, "psk", "1234567890")
+    dev[0].set_network(id, "frequency", "2412")
+    dev[0].set_network(id, "scan_freq", "2412")
+    dev[0].set_network(id, "fragment_size", "300")
+    dev[0].select_network(id)
+    wait_ap_ready(dev[0])
+    bssid = dev[0].own_addr()
+
+    pin = dev[1].wps_read_pin()
+    dev[0].request("WPS_PIN any " + pin)
+    dev[1].scan_for_bss(bssid, freq="2412")
+    dev[1].request("WPS_PIN " + bssid + " " + pin)
+    dev[1].wait_connected(timeout=30)
+
 def test_wpas_ap_wps_pbc_overlap(dev):
     """wpa_supplicant AP mode - WPS operations with PBC overlap"""
     id = dev[0].add_network()
@@ -277,8 +302,28 @@ def test_wpas_ap_wps_pbc_overlap(dev):
     dev[1].request("WPS_CANCEL")
     dev[2].request("WPS_CANCEL")
 
+@remote_compatible
+def test_wpas_ap_wps_disabled(dev):
+    """wpa_supplicant AP mode - WPS disabled"""
+    id = dev[0].add_network()
+    dev[0].set_network(id, "mode", "2")
+    dev[0].set_network_quoted(id, "ssid", "wpas-ap-no-wps")
+    dev[0].set_network_quoted(id, "psk", "12345678")
+    dev[0].set_network(id, "frequency", "2412")
+    dev[0].set_network(id, "scan_freq", "2412")
+    dev[0].set_network(id, "wps_disabled", "1")
+    dev[0].select_network(id)
+    wait_ap_ready(dev[0])
+
+    dev[1].connect("wpas-ap-no-wps", psk="12345678", scan_freq="2412")
+    dev[1].request("DISCONNECT")
+    dev[1].wait_disconnected()
+
 def test_wpas_ap_dfs(dev):
     """wpa_supplicant AP mode - DFS"""
+    if dev[0].get_mcc() > 1:
+        raise HwsimSkip("DFS is not supported with multi channel contexts")
+
     try:
         _test_wpas_ap_dfs(dev)
     finally:
@@ -316,6 +361,7 @@ def _test_wpas_ap_dfs(dev):
 
     dev[1].connect("wpas-ap-dfs", key_mgmt="NONE")
 
+@remote_compatible
 def test_wpas_ap_disable(dev):
     """wpa_supplicant AP mode - DISABLE_NETWORK"""
     id = dev[0].add_network()
@@ -334,3 +380,200 @@ def test_wpas_ap_disable(dev):
     if ev is None:
         raise Exception("AP-DISABLED event not seen")
     dev[0].wait_disconnected()
+
+def test_wpas_ap_acs(dev):
+    """wpa_supplicant AP mode - ACS"""
+    res = dev[0].get_capability("acs")
+    if res is None or "ACS" not in res:
+        raise HwsimSkip("ACS not supported")
+
+    id = dev[0].add_network()
+    dev[0].set_network(id, "mode", "2")
+    dev[0].set_network_quoted(id, "ssid", "wpas-ap-open")
+    dev[0].set_network(id, "key_mgmt", "NONE")
+    dev[0].set_network(id, "frequency", "2417")
+    dev[0].set_network(id, "scan_freq", "2417")
+    dev[0].set_network(id, "acs", "1")
+    dev[0].select_network(id)
+    wait_ap_ready(dev[0])
+
+    # ACS prefers channels 1, 6, 11
+    freq = dev[0].get_status_field('freq')
+    if freq == "2417":
+        raise Exception("Unexpected operating channel selected")
+
+    dev[1].connect("wpas-ap-open", key_mgmt="NONE", scan_freq=freq)
+
+@remote_compatible
+def test_wpas_ap_and_assoc_req_p2p_ie(dev):
+    """wpa_supplicant AP mode - unexpected P2P IE in Association Request"""
+    try:
+        _test_wpas_ap_and_assoc_req_p2p_ie(dev)
+    finally:
+        dev[1].request("VENDOR_ELEM_REMOVE 13 *")
+        dev[0].request("P2P_SET disabled 0")
+
+def _test_wpas_ap_and_assoc_req_p2p_ie(dev):
+    dev[0].request("P2P_SET disabled 1")
+    id = dev[0].add_network()
+    dev[0].set_network(id, "mode", "2")
+    dev[0].set_network_quoted(id, "ssid", "wpas-ap-open")
+    dev[0].set_network(id, "key_mgmt", "NONE")
+    dev[0].set_network(id, "frequency", "2412")
+    dev[0].set_network(id, "scan_freq", "2412")
+    dev[0].select_network(id)
+    wait_ap_ready(dev[0])
+
+    dev[1].request("VENDOR_ELEM_ADD 13 dd04506f9a09")
+    dev[1].connect("wpas-ap-open", key_mgmt="NONE", scan_freq="2412")
+    dev[1].request("DISCONNECT")
+    dev[1].wait_disconnected()
+
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+@remote_compatible
+def test_wpas_ap_open_ht_disabled(dev):
+    """wpa_supplicant AP mode - open network and HT disabled"""
+    id = dev[0].add_network()
+    dev[0].set_network(id, "mode", "2")
+    dev[0].set_network_quoted(id, "ssid", "wpas-ap-open")
+    dev[0].set_network(id, "key_mgmt", "NONE")
+    dev[0].set_network(id, "frequency", "2412")
+    dev[0].set_network(id, "scan_freq", "2412")
+    dev[0].set_network(id, "disable_ht", "1")
+    dev[0].select_network(id)
+    wait_ap_ready(dev[0])
+
+    dev[1].connect("wpas-ap-open", key_mgmt="NONE", scan_freq="2412")
+    hwsim_utils.test_connectivity(dev[0], dev[1])
+
+def test_wpas_ap_failures(dev):
+    """wpa_supplicant AP mode - failures"""
+    # No SSID configured for AP mode
+    id = dev[0].add_network()
+    dev[0].set_network(id, "mode", "2")
+    dev[0].set_network(id, "key_mgmt", "NONE")
+    dev[0].set_network(id, "frequency", "2412")
+    dev[0].set_network(id, "scan_freq", "2412")
+    dev[0].select_network(id)
+    ev = dev[0].wait_event([ "CTRL-EVENT-CONNECTED" ], timeout=0.1)
+    if ev is not None:
+        raise Exception("Unexpected connection event")
+    dev[0].request("REMOVE_NETWORK all")
+
+    # Invalid pbss value(2) for AP mode
+    dev[0].dump_monitor()
+    id = dev[0].add_network()
+    dev[0].set_network(id, "mode", "2")
+    dev[0].set_network_quoted(id, "ssid", "wpas-ap-open")
+    dev[0].set_network(id, "key_mgmt", "NONE")
+    dev[0].set_network(id, "frequency", "2412")
+    dev[0].set_network(id, "scan_freq", "2412")
+    dev[0].set_network(id, "pbss", "2")
+    dev[0].select_network(id)
+    ev = dev[0].wait_event([ "CTRL-EVENT-CONNECTED",
+                             "CTRL-EVENT-DISCONNECTED" ], timeout=0.1)
+    if ev is not None and "CTRL-EVENT-CONNECTED" in ev:
+        raise Exception("Unexpected connection event(2)")
+    dev[0].request("REMOVE_NETWORK all")
+
+def test_wpas_ap_oom(dev):
+    """wpa_supplicant AP mode - OOM"""
+    id = dev[0].add_network()
+    dev[0].set_network(id, "mode", "2")
+    dev[0].set_network_quoted(id, "ssid", "wpas-ap")
+    dev[0].set_network_quoted(id, "psk", "1234567890")
+    dev[0].set_network(id, "frequency", "2412")
+    dev[0].set_network(id, "scan_freq", "2412")
+    with alloc_fail(dev[0], 1, "=wpa_supplicant_conf_ap"):
+        dev[0].select_network(id)
+        dev[0].wait_disconnected()
+    dev[0].request("REMOVE_NETWORK all")
+
+    id = dev[0].add_network()
+    dev[0].set_network(id, "mode", "2")
+    dev[0].set_network_quoted(id, "ssid", "wpas-ap")
+    dev[0].set_network(id, "psk", "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef")
+    dev[0].set_network(id, "frequency", "2412")
+    dev[0].set_network(id, "scan_freq", "2412")
+    with alloc_fail(dev[0], 1, "=wpa_supplicant_conf_ap"):
+        dev[0].select_network(id)
+        dev[0].wait_disconnected()
+    dev[0].request("REMOVE_NETWORK all")
+
+    id = dev[0].add_network()
+    dev[0].set_network(id, "mode", "2")
+    dev[0].set_network_quoted(id, "ssid", "wpas-ap")
+    dev[0].set_network(id, "key_mgmt", "NONE")
+    dev[0].set_network_quoted(id, "wep_key0", "hello")
+    dev[0].set_network(id, "frequency", "2412")
+    dev[0].set_network(id, "scan_freq", "2412")
+    with alloc_fail(dev[0], 1, "=wpa_supplicant_conf_ap"):
+        dev[0].select_network(id)
+        dev[0].wait_disconnected()
+    dev[0].request("REMOVE_NETWORK all")
+
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    wpas.interface_add("wlan5")
+    wpas.request("SET manufacturer test")
+    wpas.request("SET model_name test")
+    wpas.request("SET model_number test")
+    wpas.request("SET serial_number test")
+    wpas.request("SET serial_number test")
+    wpas.request("SET serial_number test")
+    wpas.request("SET ap_vendor_elements dd0411223301")
+    id = wpas.add_network()
+    wpas.set_network(id, "mode", "2")
+    wpas.set_network_quoted(id, "ssid", "wpas-ap")
+    wpas.set_network(id, "key_mgmt", "NONE")
+    wpas.set_network(id, "frequency", "2412")
+    wpas.set_network(id, "scan_freq", "2412")
+
+    for i in range(5):
+        with alloc_fail(wpas, i, "=wpa_supplicant_conf_ap"):
+            wpas.select_network(id)
+            ev = dev[0].wait_event([ "CTRL-EVENT-CONNECTED",
+                                     "CTRL-EVENT-DISCONNECTED" ], timeout=1)
+        wpas.request("DISCONNECT")
+        wpas.wait_disconnected()
+
+def test_wpas_ap_params(dev):
+    """wpa_supplicant AP mode - parameters"""
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+    wpas.interface_add("wlan5")
+    wpas.request("SET manufacturer test")
+    wpas.request("SET model_name test")
+    wpas.request("SET model_number test")
+    wpas.request("SET serial_number test")
+    wpas.request("SET serial_number test")
+    wpas.request("SET serial_number test")
+    wpas.request("SET ap_vendor_elements dd0411223301")
+    id = wpas.add_network()
+    wpas.set_network(id, "mode", "2")
+    wpas.set_network_quoted(id, "ssid", "wpas-ap")
+    wpas.set_network(id, "key_mgmt", "NONE")
+    wpas.set_network(id, "frequency", "2412")
+    wpas.set_network(id, "scan_freq", "2412")
+    wpas.select_network(id)
+    wpas.wait_connected()
+    wpas.request("DISCONNECT")
+    wpas.wait_disconnected()
+
+    wpas.request("SET beacon_int 200 3")
+    wpas.request("SET dtim_period 3")
+    wpas.select_network(id)
+    wpas.wait_connected()
+    wpas.request("DISCONNECT")
+    wpas.wait_disconnected()
+
+    wpas.set_network(id, "beacon_int", "300")
+    wpas.set_network(id, "dtim_period", "2")
+    wpas.select_network(id)
+    wpas.wait_connected()
+    if "---- AP ----" not in wpas.request("PMKSA"):
+        raise Exception("AP section missing from PMKSA output")
+    if "OK" not in wpas.request("PMKSA_FLUSH"):
+        raise Exception("PMKSA_FLUSH failed")
+    wpas.request("DISCONNECT")
+    wpas.wait_disconnected()
index 0af31da..4110916 100644 (file)
@@ -9,6 +9,7 @@ logger = logging.getLogger()
 import os
 
 from wpasupplicant import WpaSupplicant
+import hostapd
 
 def check_config(config):
     with open(config, "r") as f:
@@ -29,6 +30,14 @@ def check_config(config):
         raise Exception("Missing network")
     if "wps_priority=5\n" not in data:
         raise Exception("Missing wps_priority")
+    if "ip_addr_go=192.168.1.1\n" not in data:
+        raise Exception("Missing ip_addr_go")
+    if "ip_addr_mask=255.255.255.0\n" not in data:
+        raise Exception("Missing ip_addr_mask")
+    if "ip_addr_start=192.168.1.10\n" not in data:
+        raise Exception("Missing ip_addr_start")
+    if "ip_addr_end=192.168.1.20\n" not in data:
+        raise Exception("Missing ip_addr_end")
     return data
 
 def test_wpas_config_file(dev):
@@ -92,6 +101,10 @@ def test_wpas_config_file(dev):
         ev = wpas.wait_event(["CRED-MODIFIED 0 password"])
 
         wpas.request("SET blob foo 12345678")
+        wpas.request("SET ip_addr_go 192.168.1.1")
+        wpas.request("SET ip_addr_mask 255.255.255.0")
+        wpas.request("SET ip_addr_start 192.168.1.10")
+        wpas.request("SET ip_addr_end 192.168.1.20")
 
         if "OK" not in wpas.request("SAVE_CONFIG"):
             raise Exception("Failed to save configuration file")
@@ -117,6 +130,7 @@ def test_wpas_config_file(dev):
             raise Exception("Unexpected configuration change")
 
         wpas.request("SET update_config 0")
+        wpas.global_request("SET update_config 0")
         if "OK" in wpas.request("SAVE_CONFIG"):
             raise Exception("SAVE_CONFIG succeeded unexpectedly")
         if "OK" in wpas.global_request("SAVE_CONFIG"):
@@ -126,6 +140,7 @@ def test_wpas_config_file(dev):
         os.remove(config)
         os.mkdir(config)
         wpas.request("SET update_config 1")
+        wpas.global_request("SET update_config 1")
         if "OK" in wpas.request("SAVE_CONFIG"):
             raise Exception("SAVE_CONFIG succeeded unexpectedly")
         if "OK" in wpas.global_request("SAVE_CONFIG"):
@@ -144,3 +159,243 @@ def test_wpas_config_file(dev):
             os.rmdir(config)
         except:
             pass
+
+def test_wpas_config_file_wps(dev, apdev):
+    """wpa_supplicant config file parsing/writing with WPS"""
+    config = "/tmp/test_wpas_config_file.conf"
+    if os.path.exists(config):
+        os.remove(config)
+
+    params = { "ssid": "test-wps", "eap_server": "1", "wps_state": "2",
+               "skip_cred_build": "1", "extra_cred": "wps-ctrl-cred" }
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+
+    try:
+        with open(config, "w") as f:
+            f.write("update_config=1\n")
+
+        wpas.interface_add("wlan5", config=config)
+
+        hapd.request("WPS_PIN any 12345670")
+        wpas.scan_for_bss(apdev[0]['bssid'], freq="2412")
+        wpas.request("WPS_PIN " + apdev[0]['bssid'] + " 12345670")
+        ev = wpas.wait_event(["WPS-FAIL"], timeout=10)
+        if ev is None:
+            raise Exception("WPS-FAIL event timed out")
+
+        with open(config, "r") as f:
+            data = f.read()
+            logger.info("Configuration file contents: " + data)
+            if "network=" in data:
+                raise Exception("Unexpected network block in configuration data")
+
+    finally:
+        try:
+            os.remove(config)
+        except:
+            pass
+        try:
+            os.remove(config + ".tmp")
+        except:
+            pass
+        try:
+            os.rmdir(config)
+        except:
+            pass
+
+def test_wpas_config_file_wps2(dev, apdev):
+    """wpa_supplicant config file parsing/writing with WPS (2)"""
+    config = "/tmp/test_wpas_config_file.conf"
+    if os.path.exists(config):
+        os.remove(config)
+
+    params = { "ssid": "test-wps", "eap_server": "1", "wps_state": "2",
+               "skip_cred_build": "1", "extra_cred": "wps-ctrl-cred2" }
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+
+    try:
+        with open(config, "w") as f:
+            f.write("update_config=1\n")
+
+        wpas.interface_add("wlan5", config=config)
+
+        hapd.request("WPS_PIN any 12345670")
+        wpas.scan_for_bss(apdev[0]['bssid'], freq="2412")
+        wpas.request("WPS_PIN " + apdev[0]['bssid'] + " 12345670")
+        ev = wpas.wait_event(["WPS-SUCCESS"], timeout=10)
+        if ev is None:
+            raise Exception("WPS-SUCCESS event timed out")
+
+        with open(config, "r") as f:
+            data = f.read()
+            logger.info("Configuration file contents: " + data)
+
+            with open(config, "r") as f:
+                data = f.read()
+                if "network=" not in data:
+                    raise Exception("Missing network block in configuration data")
+                if "ssid=410a420d430044" not in data:
+                    raise Exception("Unexpected ssid parameter value")
+
+    finally:
+        try:
+            os.remove(config)
+        except:
+            pass
+        try:
+            os.remove(config + ".tmp")
+        except:
+            pass
+        try:
+            os.rmdir(config)
+        except:
+            pass
+
+def test_wpas_config_file_set_psk(dev):
+    """wpa_supplicant config file parsing/writing with arbitrary PSK value"""
+    config = "/tmp/test_wpas_config_file.conf"
+    if os.path.exists(config):
+        os.remove(config)
+
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+
+    try:
+        with open(config, "w") as f:
+            f.write("update_config=1\n")
+
+        wpas.interface_add("wlan5", config=config)
+
+        id = wpas.add_network()
+        wpas.set_network_quoted(id, "ssid", "foo")
+        if "OK" in wpas.request('SET_NETWORK %d psk "12345678"\n}\nmodel_name=foobar\nnetwork={\n#\"' % id):
+            raise Exception("Invalid psk value accepted")
+
+        if "OK" not in wpas.request("SAVE_CONFIG"):
+            raise Exception("Failed to save configuration file")
+
+        with open(config, "r") as f:
+            data = f.read()
+            logger.info("Configuration file contents: " + data)
+            if "model_name" in data:
+                raise Exception("Unexpected parameter added to configuration")
+
+        wpas.interface_remove("wlan5")
+        wpas.interface_add("wlan5", config=config)
+
+    finally:
+        try:
+            os.remove(config)
+        except:
+            pass
+        try:
+            os.remove(config + ".tmp")
+        except:
+            pass
+        try:
+            os.rmdir(config)
+        except:
+            pass
+
+def test_wpas_config_file_set_cred(dev):
+    """wpa_supplicant config file parsing/writing with arbitrary cred values"""
+    config = "/tmp/test_wpas_config_file.conf"
+    if os.path.exists(config):
+        os.remove(config)
+
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+
+    try:
+        with open(config, "w") as f:
+            f.write("update_config=1\n")
+
+        wpas.interface_add("wlan5", config=config)
+
+        id = wpas.add_cred()
+        wpas.set_cred_quoted(id, "username", "hello")
+        fields = [ "username", "milenage", "imsi", "password", "realm",
+                   "phase1", "phase2", "provisioning_sp" ]
+        for field in fields:
+            if "FAIL" not in wpas.request('SET_CRED %d %s "hello"\n}\nmodel_name=foobar\ncred={\n#\"' % (id, field)):
+                raise Exception("Invalid %s value accepted" % field)
+
+        if "OK" not in wpas.request("SAVE_CONFIG"):
+            raise Exception("Failed to save configuration file")
+
+        with open(config, "r") as f:
+            data = f.read()
+            logger.info("Configuration file contents: " + data)
+            if "model_name" in data:
+                raise Exception("Unexpected parameter added to configuration")
+
+        wpas.interface_remove("wlan5")
+        wpas.interface_add("wlan5", config=config)
+
+    finally:
+        try:
+            os.remove(config)
+        except:
+            pass
+        try:
+            os.remove(config + ".tmp")
+        except:
+            pass
+        try:
+            os.rmdir(config)
+        except:
+            pass
+
+def test_wpas_config_file_set_global(dev):
+    """wpa_supplicant config file parsing/writing with arbitrary global values"""
+    config = "/tmp/test_wpas_config_file.conf"
+    if os.path.exists(config):
+        os.remove(config)
+
+    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+
+    try:
+        with open(config, "w") as f:
+            f.write("update_config=1\n")
+
+        wpas.interface_add("wlan5", config=config)
+
+        fields = [ "model_name", "device_name", "ctrl_interface_group",
+                   "opensc_engine_path", "pkcs11_engine_path",
+                   "pkcs11_module_path", "openssl_ciphers", "pcsc_reader",
+                   "pcsc_pin", "driver_param", "manufacturer", "model_name",
+                   "model_number", "serial_number", "config_methods",
+                  "p2p_ssid_postfix", "autoscan", "ext_password_backend",
+                  "osu_dir", "wowlan_triggers", "fst_group_id",
+                  "sched_scan_plans", "non_pref_chan" ]
+        for field in fields:
+            if "FAIL" not in wpas.request('SET %s hello\nmodel_name=foobar' % field):
+                raise Exception("Invalid %s value accepted" % field)
+
+        if "OK" not in wpas.request("SAVE_CONFIG"):
+            raise Exception("Failed to save configuration file")
+
+        with open(config, "r") as f:
+            data = f.read()
+            logger.info("Configuration file contents: " + data)
+            if "model_name" in data:
+                raise Exception("Unexpected parameter added to configuration")
+
+        wpas.interface_remove("wlan5")
+        wpas.interface_add("wlan5", config=config)
+
+    finally:
+        try:
+            os.remove(config)
+        except:
+            pass
+        try:
+            os.remove(config + ".tmp")
+        except:
+            pass
+        try:
+            os.rmdir(config)
+        except:
+            pass
index de7cde4..96ed551 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 import os
@@ -15,8 +16,10 @@ import hostapd
 import hwsim_utils
 from hwsim import HWSimRadio
 from wpasupplicant import WpaSupplicant
-from utils import alloc_fail
+from utils import alloc_fail, fail_test
+from test_wpas_ap import wait_ap_ready
 
+@remote_compatible
 def test_wpas_ctrl_network(dev):
     """wpa_supplicant ctrl_iface network set/get"""
     id = dev[0].add_network()
@@ -32,7 +35,36 @@ def test_wpas_ctrl_network(dev):
     if "FAIL" not in dev[0].request("GET_NETWORK " + str(id + 1) + " proto"):
         raise Exception("Unexpected success for invalid network id")
 
-    tests = (("key_mgmt", "WPA-PSK WPA-EAP IEEE8021X NONE WPA-NONE FT-PSK FT-EAP WPA-PSK-SHA256 WPA-EAP-SHA256"),
+    if "OK" not in dev[0].request("SET_NETWORK " + str(id) + " proto  \t WPA2 "):
+        raise Exception("Unexpected failure for SET_NETWORK proto")
+    res = dev[0].request("GET_NETWORK " + str(id) + " proto")
+    if res != "RSN":
+        raise Exception("Unexpected SET_NETWORK/GET_NETWORK conversion for proto: " + res)
+
+    if "OK" not in dev[0].request("SET_NETWORK " + str(id) + " key_mgmt  \t WPA-PSK "):
+        raise Exception("Unexpected success for SET_NETWORK key_mgmt")
+    res = dev[0].request("GET_NETWORK " + str(id) + " key_mgmt")
+    if res != "WPA-PSK":
+        raise Exception("Unexpected SET_NETWORK/GET_NETWORK conversion for key_mgmt: " + res)
+
+    if "OK" not in dev[0].request("SET_NETWORK " + str(id) + " auth_alg  \t OPEN "):
+        raise Exception("Unexpected failure for SET_NETWORK auth_alg")
+    res = dev[0].request("GET_NETWORK " + str(id) + " auth_alg")
+    if res != "OPEN":
+        raise Exception("Unexpected SET_NETWORK/GET_NETWORK conversion for auth_alg: " + res)
+
+    if "OK" not in dev[0].request("SET_NETWORK " + str(id) + " eap  \t TLS "):
+        raise Exception("Unexpected failure for SET_NETWORK eap")
+    res = dev[0].request("GET_NETWORK " + str(id) + " eap")
+    if res != "TLS":
+        raise Exception("Unexpected SET_NETWORK/GET_NETWORK conversion for eap: " + res)
+
+    tests = ("bssid foo", "key_mgmt foo", "key_mgmt ", "group NONE")
+    for t in tests:
+        if "FAIL" not in dev[0].request("SET_NETWORK " + str(id) + " " + t):
+            raise Exception("Unexpected success for invalid SET_NETWORK: " + t)
+
+    tests = [("key_mgmt", "WPA-PSK WPA-EAP IEEE8021X NONE WPA-NONE FT-PSK FT-EAP WPA-PSK-SHA256 WPA-EAP-SHA256"),
              ("pairwise", "CCMP-256 GCMP-256 CCMP GCMP TKIP"),
              ("group", "CCMP-256 GCMP-256 CCMP GCMP TKIP"),
              ("auth_alg", "OPEN SHARED LEAP"),
@@ -43,7 +75,11 @@ def test_wpas_ctrl_network(dev):
              ("proto", "WPA RSN OSEN"),
              ("eap", "TLS"),
              ("go_p2p_dev_addr", "22:33:44:55:66:aa"),
-             ("p2p_client_list", "22:33:44:55:66:bb 02:11:22:33:44:55"))
+             ("p2p_client_list", "22:33:44:55:66:bb 02:11:22:33:44:55")]
+    if "SAE" not in dev[0].get_capability("auth_alg"):
+        tests.append(("key_mgmt", "WPS OSEN"))
+    else:
+        tests.append(("key_mgmt", "WPS SAE FT-SAE OSEN"))
 
     dev[0].set_network_quoted(id, "ssid", "test")
     for field, value in tests:
@@ -52,6 +88,18 @@ def test_wpas_ctrl_network(dev):
         if res != value:
             raise Exception("Unexpected response for '" + field + "': '" + res + "'")
 
+    try:
+        value = "WPA-EAP-SUITE-B WPA-EAP-SUITE-B-192"
+        dev[0].set_network(id, "key_mgmt", value)
+        res = dev[0].get_network(id, "key_mgmt")
+        if res != value:
+            raise Exception("Unexpected response for key_mgmt")
+    except Exception, e:
+        if str(e).startswith("Unexpected"):
+            raise
+        else:
+            pass
+
     q_tests = (("identity", "hello"),
                ("anonymous_identity", "foo@nowhere.com"))
     for field, value in q_tests:
@@ -141,10 +189,10 @@ def test_wpas_ctrl_network(dev):
         raise Exception("Too short PSK accepted")
     if "FAIL" not in dev[0].request('SET_NETWORK ' + str(id) + ' psk "1234567890123456789012345678901234567890123456789012345678901234"'):
         raise Exception("Too long PSK accepted")
-    dev[0].set_network_quoted(id, "psk", "123456768");
-    dev[0].set_network_quoted(id, "psk", "123456789012345678901234567890123456789012345678901234567890123");
+    dev[0].set_network_quoted(id, "psk", "123456768")
+    dev[0].set_network_quoted(id, "psk", "123456789012345678901234567890123456789012345678901234567890123")
     if dev[0].get_network(id, "psk") != '*':
-        raise Exception("Unexpected psk read result");
+        raise Exception("Unexpected psk read result")
 
     if "FAIL" not in dev[0].request('SET_NETWORK ' + str(id) + ' eap UNKNOWN'):
         raise Exception("Unknown EAP method accepted")
@@ -232,6 +280,7 @@ def test_wpas_ctrl_network(dev):
         if "FAIL" not in dev[0].request("SET_NETWORK %d bssid_blacklist %s" % (id, val)):
             raise Exception("Invalid bssid_blacklist value accepted")
 
+@remote_compatible
 def test_wpas_ctrl_network_oom(dev):
     """wpa_supplicant ctrl_iface network OOM in string parsing"""
     id = dev[0].add_network()
@@ -245,6 +294,7 @@ def test_wpas_ctrl_network_oom(dev):
             if "FAIL" not in dev[0].request("SET_NETWORK " + str(id) + ' ssid ' + val):
                 raise Exception("Unexpected success for SET_NETWORK during OOM")
 
+@remote_compatible
 def test_wpas_ctrl_many_networks(dev, apdev):
     """wpa_supplicant ctrl_iface LIST_NETWORKS with huge number of networks"""
     for i in range(1000):
@@ -260,12 +310,13 @@ def test_wpas_ctrl_many_networks(dev, apdev):
     # with the test case failing and following reset operation timing out.
     dev[0].request("REMOVE_NETWORK all", timeout=60)
 
+@remote_compatible
 def test_wpas_ctrl_dup_network(dev, apdev):
     """wpa_supplicant ctrl_iface DUP_NETWORK"""
     ssid = "target"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     src = dev[0].connect("another", psk=passphrase, scan_freq="2412",
                          only_add_network=True)
@@ -293,12 +344,13 @@ def test_wpas_ctrl_dup_network(dev, apdev):
     if "OK" not in dev[0].request("DUP_NETWORK %d %d ssid" % (id, id)):
         raise Exception("Unexpected DUP_NETWORK failure")
 
+@remote_compatible
 def test_wpas_ctrl_dup_network_global(dev, apdev):
     """wpa_supplicant ctrl_iface DUP_NETWORK (global)"""
     ssid = "target"
     passphrase = 'qwertyuiop'
     params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     src = dev[0].connect("another", psk=passphrase, scan_freq="2412",
                          only_add_network=True)
@@ -361,6 +413,7 @@ def remove_cred(dev, id):
     if " " + str(id) not in ev:
         raise Exception("CRED-REMOVED event without matching id")
 
+@remote_compatible
 def test_wpas_ctrl_cred(dev):
     """wpa_supplicant ctrl_iface cred set"""
     id1 = add_cred(dev[0])
@@ -381,6 +434,7 @@ def test_wpas_ctrl_cred(dev):
     set_cred(dev[0], id, "temporary", "1")
     set_cred(dev[0], id, "priority", "1")
     set_cred(dev[0], id, "pcsc", "1")
+    set_cred(dev[0], id, "sim_num", "0")
     set_cred_quoted(dev[0], id, "private_key_passwd", "test")
     set_cred_quoted(dev[0], id, "domain_suffix_match", "test")
     set_cred_quoted(dev[0], id, "phase1", "test")
@@ -403,6 +457,16 @@ def test_wpas_ctrl_cred(dev):
     if "FAIL" not in dev[0].request("SET_CRED " + str(id) + " foo 4142"):
         raise Exception("Unexpected success on unknown field")
 
+    tests = ["sp_priority 256",
+             'roaming_partner "example.org"',
+             'roaming_partner "' + 200*'a' + '.example.org,"',
+             'roaming_partner "example.org,1"',
+             'roaming_partner "example.org,1,2"',
+             'roaming_partner "example.org,1,2,ABC"' ]
+    for t in tests:
+        if "FAIL" not in dev[0].request("SET_CRED " + str(id) + " " + t):
+            raise Exception("Unexpected success on invalid SET_CRED value: " + t)
+
     id3 = add_cred(dev[0])
     id4 = add_cred(dev[0])
     if len(dev[0].request("LIST_CREDS").splitlines()) != 6:
@@ -545,6 +609,7 @@ def test_wpas_ctrl_pno(dev):
     if "FAIL" in dev[0].request("SET pno 0"):
         raise Exception("Unexpected failure in disabling PNO")
 
+@remote_compatible
 def test_wpas_ctrl_get(dev):
     """wpa_supplicant ctrl_iface get"""
     if "FAIL" in dev[0].request("GET version"):
@@ -554,6 +619,7 @@ def test_wpas_ctrl_get(dev):
     if "FAIL" not in dev[0].request("GET foo"):
         raise Exception("Unexpected success on get command")
 
+@remote_compatible
 def test_wpas_ctrl_preauth(dev):
     """wpa_supplicant ctrl_iface preauth"""
     if "FAIL" not in dev[0].request("PREAUTH "):
@@ -561,6 +627,7 @@ def test_wpas_ctrl_preauth(dev):
     if "FAIL" in dev[0].request("PREAUTH 00:11:22:33:44:55"):
         raise Exception("Unexpected failure on PREAUTH")
 
+@remote_compatible
 def test_wpas_ctrl_stkstart(dev):
     """wpa_supplicant ctrl_iface strkstart"""
     if "FAIL" not in dev[0].request("STKSTART "):
@@ -568,6 +635,7 @@ def test_wpas_ctrl_stkstart(dev):
     if "FAIL" not in dev[0].request("STKSTART 00:11:22:33:44:55"):
         raise Exception("Unexpected success on STKSTART")
 
+@remote_compatible
 def test_wpas_ctrl_tdls_discover(dev):
     """wpa_supplicant ctrl_iface tdls_discover"""
     if "FAIL" not in dev[0].request("TDLS_DISCOVER "):
@@ -575,6 +643,7 @@ def test_wpas_ctrl_tdls_discover(dev):
     if "FAIL" not in dev[0].request("TDLS_DISCOVER 00:11:22:33:44:55"):
         raise Exception("Unexpected success on TDLS_DISCOVER")
 
+@remote_compatible
 def test_wpas_ctrl_tdls_chan_switch(dev):
     """wpa_supplicant ctrl_iface tdls_chan_switch error cases"""
     for args in [ '', '00:11:22:33:44:55' ]:
@@ -587,6 +656,7 @@ def test_wpas_ctrl_tdls_chan_switch(dev):
         if "FAIL" not in dev[0].request("TDLS_CHAN_SWITCH " + args):
             raise Exception("Unexpected success on invalid TDLS_CHAN_SWITCH: " + args)
 
+@remote_compatible
 def test_wpas_ctrl_addr(dev):
     """wpa_supplicant ctrl_iface invalid address"""
     if "FAIL" not in dev[0].request("TDLS_SETUP "):
@@ -608,6 +678,7 @@ def test_wpas_ctrl_addr(dev):
     if "FAIL" not in dev[0].request("BLACKLIST 00:11:22:33:44"):
         raise Exception("Unexpected success on invalid BLACKLIST")
 
+@remote_compatible
 def test_wpas_ctrl_wps_errors(dev):
     """wpa_supplicant ctrl_iface WPS error cases"""
     if "FAIL" not in dev[0].request("WPS_REG 00:11:22:33:44:55"):
@@ -656,6 +727,7 @@ def test_wpas_ctrl_wps_errors(dev):
     if "FAIL" not in dev[0].request("WPS_NFC_TOKEN FOO"):
         raise Exception("Unexpected success on invalid WPS_NFC_TOKEN")
 
+@remote_compatible
 def test_wpas_ctrl_config_parser(dev):
     """wpa_supplicant ctrl_iface SET config parser"""
     if "FAIL" not in dev[0].request("SET pbc_in_m1 qwerty"):
@@ -668,6 +740,7 @@ def test_wpas_ctrl_config_parser(dev):
     if "FAIL" not in dev[0].request("SET serial_number 0123456789abcdef0123456789abcdef0"):
         raise Exception("Too long string accepted")
 
+@remote_compatible
 def test_wpas_ctrl_mib(dev):
     """wpa_supplicant ctrl_iface MIB"""
     mib = dev[0].get_mib()
@@ -678,6 +751,12 @@ def test_wpas_ctrl_mib(dev):
 
 def test_wpas_ctrl_set_wps_params(dev):
     """wpa_supplicant ctrl_iface SET config_methods"""
+    try:
+        _test_wpas_ctrl_set_wps_params(dev)
+    finally:
+        dev[2].request("SET config_methods ")
+
+def _test_wpas_ctrl_set_wps_params(dev):
     ts = [ "config_methods label virtual_display virtual_push_button keypad",
            "device_type 1-0050F204-1",
            "os_version 01020300",
@@ -720,8 +799,8 @@ def test_wpas_ctrl_bssid_filter(dev, apdev):
         if "OK" not in dev[2].request("SET bssid_filter " + apdev[0]['bssid']):
             raise Exception("Failed to set bssid_filter")
         params = { "ssid": "test" }
-        hostapd.add_ap(apdev[0]['ifname'], params)
-        hostapd.add_ap(apdev[1]['ifname'], params)
+        hostapd.add_ap(apdev[0], params)
+        hostapd.add_ap(apdev[1], params)
         dev[2].scan_for_bss(apdev[0]['bssid'], freq="2412")
         dev[2].scan(freq="2412")
         bss = dev[2].get_bss(apdev[0]['bssid'])
@@ -751,10 +830,11 @@ def test_wpas_ctrl_bssid_filter(dev, apdev):
     finally:
         dev[2].request("SET bssid_filter ")
 
+@remote_compatible
 def test_wpas_ctrl_disallow_aps(dev, apdev):
     """wpa_supplicant ctrl_iface disallow_aps"""
     params = { "ssid": "test" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     if "FAIL" not in dev[0].request("SET disallow_aps bssid "):
         raise Exception("Unexpected success on invalid disallow_aps")
@@ -772,7 +852,7 @@ def test_wpas_ctrl_disallow_aps(dev, apdev):
         raise Exception("Unexpected success on invalid disallow_aps")
 
     dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
-    hostapd.add_ap(apdev[1]['ifname'], params)
+    hostapd.add_ap(apdev[1], params)
     dev[0].scan_for_bss(apdev[1]['bssid'], freq="2412")
     dev[0].dump_monitor()
     if "OK" not in dev[0].request("SET disallow_aps bssid 00:11:22:33:44:55 bssid 00:22:33:44:55:66"):
@@ -796,6 +876,7 @@ def test_wpas_ctrl_disallow_aps(dev, apdev):
     if "OK" not in dev[0].request("SET disallow_aps "):
         raise Exception("Failed to set disallow_aps")
 
+@remote_compatible
 def test_wpas_ctrl_blob(dev):
     """wpa_supplicant ctrl_iface SET blob"""
     if "FAIL" not in dev[0].request("SET blob foo"):
@@ -809,6 +890,7 @@ def test_wpas_ctrl_blob(dev):
     if "OK" not in dev[0].request("SET blob foo 0011"):
         raise Exception("Unexpected SET failure")
 
+@remote_compatible
 def test_wpas_ctrl_set_uapsd(dev):
     """wpa_supplicant ctrl_iface SET uapsd"""
     if "FAIL" not in dev[0].request("SET uapsd foo"):
@@ -837,7 +919,9 @@ def test_wpas_ctrl_set(dev):
              "dot11RSNAConfigPMKReauthThreshold 101",
              "dot11RSNAConfigSATimeout 0",
              "wps_version_number -1",
-             "wps_version_number 256" ]
+             "wps_version_number 256",
+             "fst_group_id ",
+             "fst_llt 0"]
     for val in vals:
         if "FAIL" not in dev[0].request("SET " + val):
             raise Exception("Unexpected SET success for " + val)
@@ -856,6 +940,12 @@ def test_wpas_ctrl_set(dev):
         if "OK" not in dev[0].request("SET " + val):
             raise Exception("Unexpected SET failure for " + val)
 
+    # This fails if wpa_supplicant is built with loadable EAP peer method
+    # support due to missing file and succeeds if no support for loadable
+    # methods is included, so don't check the return value for now.
+    dev[0].request("SET load_dynamic_eap /tmp/hwsim-eap-not-found.so")
+
+@remote_compatible
 def test_wpas_ctrl_get_capability(dev):
     """wpa_supplicant ctrl_iface GET_CAPABILITY"""
     if "FAIL" not in dev[0].request("GET_CAPABILITY 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"):
@@ -911,6 +1001,7 @@ def test_wpas_ctrl_get_capability(dev):
     if dev[0].get_capability("foo") is not None:
         raise Exception("Unexpected GET_CAPABILITY foo response: " + str(res))
 
+@remote_compatible
 def test_wpas_ctrl_nfc_report_handover(dev):
     """wpa_supplicant ctrl_iface NFC_REPORT_HANDOVER"""
     vals = [ "FOO",
@@ -926,6 +1017,7 @@ def test_wpas_ctrl_nfc_report_handover(dev):
         if "FAIL" not in dev[0].request("NFC_REPORT_HANDOVER " + v):
             raise Exception("Unexpected NFC_REPORT_HANDOVER success for " + v)
 
+@remote_compatible
 def test_wpas_ctrl_nfc_tag_read(dev):
     """wpa_supplicant ctrl_iface WPS_NFC_TAG_READ"""
     vals = [ "FOO", "0Q", "00", "000000", "10000001", "10000000", "00000000",
@@ -934,6 +1026,7 @@ def test_wpas_ctrl_nfc_tag_read(dev):
         if "FAIL" not in dev[0].request("WPS_NFC_TAG_READ " + v):
             raise Exception("Unexpected WPS_NFC_TAG_READ success for " + v)
 
+@remote_compatible
 def test_wpas_ctrl_nfc_get_handover(dev):
     """wpa_supplicant ctrl_iface NFC_GET_HANDOVER"""
     vals = [ "FOO", "FOO BAR", "WPS WPS", "WPS WPS-CR", "WPS FOO", "NDEF P2P" ]
@@ -961,6 +1054,7 @@ def test_wpas_ctrl_nfc_get_handover(dev):
 def get_blacklist(dev):
     return dev.request("BLACKLIST").splitlines()
 
+@remote_compatible
 def test_wpas_ctrl_blacklist(dev):
     """wpa_supplicant ctrl_iface BLACKLIST"""
     if "OK" not in dev[0].request("BLACKLIST clear"):
@@ -989,6 +1083,7 @@ def test_wpas_ctrl_blacklist(dev):
     if dev[0].request("BLACKLIST") != "":
         raise Exception("Unexpected blacklist contents")
 
+@remote_compatible
 def test_wpas_ctrl_blacklist_oom(dev):
     """wpa_supplicant ctrl_iface BLACKLIST and out-of-memory"""
     with alloc_fail(dev[0], 1, "wpa_blacklist_add"):
@@ -1037,10 +1132,11 @@ def test_wpas_ctrl_log_level(dev):
     if "Timestamp: 1" not in level:
         raise Exception("Unexpected timestamp(3): " + level)
 
+@remote_compatible
 def test_wpas_ctrl_enable_disable_network(dev, apdev):
     """wpa_supplicant ctrl_iface ENABLE/DISABLE_NETWORK"""
     params = { "ssid": "test" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
 
     id = dev[0].connect("test", key_mgmt="NONE", scan_freq="2412",
                         only_add_network=True)
@@ -1088,7 +1184,9 @@ def test_wpas_ctrl_country(dev, apdev):
         ev = dev[0].wait_global_event(["CTRL-EVENT-REGDOM-CHANGE"], 10)
         if ev is None:
             raise Exception("regdom change event not seen")
-        if "init=CORE type=WORLD" not in ev:
+        # init=CORE was previously used due to invalid db.txt data for 00. For
+        # now, allow both it and the new init=USER after fixed db.txt.
+        if "init=CORE type=WORLD" not in ev and "init=USER type=WORLD" not in ev:
             raise Exception("Unexpected event contents: " + ev)
     finally:
         subprocess.call(['iw', 'reg', 'set', '00'])
@@ -1169,7 +1267,10 @@ def test_wpas_ctrl_global(dev):
         raise Exception("INTERFACE_ADD succeeded unexpectedly")
     if "FAIL" not in wpas.global_request("INTERFACE_ADD FOO                                    "):
         raise Exception("INTERFACE_ADD succeeded unexpectedly")
+    if "FAIL" not in wpas.global_request("INTERFACE_ADD FOO    conf    driver  ctrliface       driverparam     bridge  create  abcd"):
+        raise Exception("INTERFACE_ADD succeeded unexpectedly")
 
+@remote_compatible
 def test_wpas_ctrl_roam(dev, apdev):
     """wpa_supplicant ctrl_iface ROAM error cases"""
     if "FAIL" not in dev[0].request("ROAM 00:11:22:33:44"):
@@ -1177,63 +1278,25 @@ def test_wpas_ctrl_roam(dev, apdev):
     if "FAIL" not in dev[0].request("ROAM 00:11:22:33:44:55"):
         raise Exception("Unexpected success")
     params = { "ssid": "test" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
+    hostapd.add_ap(apdev[0], params)
     id = dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
     if "FAIL" not in dev[0].request("ROAM 00:11:22:33:44:55"):
         raise Exception("Unexpected success")
 
+@remote_compatible
 def test_wpas_ctrl_ipaddr(dev, apdev):
     """wpa_supplicant IP address in STATUS"""
     try:
-        subprocess.call(['ip', 'addr', 'add', '10.174.65.207/32', 'dev',
-                         dev[0].ifname])
+        dev[0].cmd_execute(['ip', 'addr', 'add', '10.174.65.207/32', 'dev',
+                            dev[0].ifname])
         ipaddr = dev[0].get_status_field('ip_address')
         if ipaddr != '10.174.65.207':
             raise Exception("IP address not in STATUS output")
     finally:
-        subprocess.call(['ip', 'addr', 'del', '10.174.65.207/32', 'dev',
-                         dev[0].ifname])
-
-def test_wpas_ctrl_neighbor_rep_req(dev, apdev):
-    """wpa_supplicant ctrl_iface NEIGHBOR_REP_REQUEST"""
-    params = { "ssid": "test" }
-    hostapd.add_ap(apdev[0]['ifname'], params)
-    params = { "ssid": "test2", "radio_measurements": "1" }
-    hostapd.add_ap(apdev[1]['ifname'], params)
-
-    dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
-    if "FAIL" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
-        raise Exception("Request succeeded unexpectedly")
-    if "FAIL" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=abcdef"):
-        raise Exception("Request succeeded unexpectedly")
-    dev[0].request("DISCONNECT")
-
-    rrm = int(dev[0].get_driver_status_field("capa.rrm_flags"), 16)
-    if rrm & 0x5 != 0x5:
-        logger.info("Driver does not support required RRM capabilities - skip rest of the test case")
-        return
-
-    dev[0].connect("test2", key_mgmt="NONE", scan_freq="2412")
-
-    # These requests are expected to get sent properly, but since hostapd does
-    # not yet support processing of the request, these are expected to fail.
-    
-    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
-        raise Exception("Request failed")
-    ev = dev[0].wait_event([ "RRM-NEIGHBOR-REP-RECEIVED",
-                             "RRM-NEIGHBOR-REP-REQUEST-FAILED" ], timeout=10)
-    if ev is None:
-        raise Exception("RRM report result not indicated")
-    logger.info("RRM result: " + ev)
-
-    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=abcdef"):
-        raise Exception("Request failed")
-    ev = dev[0].wait_event([ "RRM-NEIGHBOR-REP-RECEIVED",
-                             "RRM-NEIGHBOR-REP-REQUEST-FAILED" ], timeout=10)
-    if ev is None:
-        raise Exception("RRM report result not indicated")
-    logger.info("RRM result: " + ev)
+        dev[0].cmd_execute(['ip', 'addr', 'del', '10.174.65.207/32', 'dev',
+                            dev[0].ifname])
 
+@remote_compatible
 def test_wpas_ctrl_rsp(dev, apdev):
     """wpa_supplicant ctrl_iface CTRL-RSP-"""
     if "FAIL" not in dev[0].request("CTRL-RSP-"):
@@ -1254,6 +1317,7 @@ def test_wpas_ctrl_rsp(dev, apdev):
         if "OK" not in dev[0].request("CTRL-RSP-%s-%d:" % (req, id)):
             raise Exception("Request failed unexpectedly")
 
+@remote_compatible
 def test_wpas_ctrl_vendor(dev, apdev):
     """wpa_supplicant ctrl_iface VENDOR"""
     cmds = [ "foo",
@@ -1265,6 +1329,7 @@ def test_wpas_ctrl_vendor(dev, apdev):
         if "FAIL" not in dev[0].request("VENDOR " + cmd):
             raise Exception("Invalid VENDOR command accepted: " + cmd)
 
+@remote_compatible
 def test_wpas_ctrl_mgmt_tx(dev, apdev):
     """wpa_supplicant ctrl_iface MGMT_TX"""
     cmds = [ "foo",
@@ -1279,11 +1344,13 @@ def test_wpas_ctrl_mgmt_tx(dev, apdev):
     if "OK" not in dev[0].request("MGMT_TX_DONE"):
         raise Exception("MGMT_TX_DONE failed")
 
+@remote_compatible
 def test_wpas_ctrl_driver_event(dev, apdev):
     """wpa_supplicant ctrl_iface DRIVER_EVENT"""
     if "FAIL" not in dev[0].request("DRIVER_EVENT foo"):
         raise Exception("Invalid DRIVER_EVENT accepted")
 
+@remote_compatible
 def test_wpas_ctrl_eapol_rx(dev, apdev):
     """wpa_supplicant ctrl_iface EAPOL_RX"""
     cmds = [ "foo",
@@ -1293,6 +1360,7 @@ def test_wpas_ctrl_eapol_rx(dev, apdev):
         if "FAIL" not in dev[0].request("EAPOL_RX " + cmd):
             raise Exception("Invalid EAPOL_RX command accepted: " + cmd)
 
+@remote_compatible
 def test_wpas_ctrl_data_test(dev, apdev):
     """wpa_supplicant ctrl_iface DATA_TEST"""
     dev[0].request("DATA_TEST_CONFIG 0")
@@ -1327,6 +1395,7 @@ def test_wpas_ctrl_data_test(dev, apdev):
     if "OK" not in dev[0].request("DATA_TEST_FRAME 00112233445566778899aabbccddee"):
         raise Exception("DATA_TEST_FRAME failed")
 
+@remote_compatible
 def test_wpas_ctrl_vendor_elem(dev, apdev):
     """wpa_supplicant ctrl_iface VENDOR_ELEM"""
     if "OK" not in dev[0].request("VENDOR_ELEM_ADD 1 "):
@@ -1395,6 +1464,7 @@ def test_wpas_ctrl_misc(dev, apdev):
     if "FAIL" not in dev[0].global_request("SET foo"):
         raise Exception("Invalid global SET accepted")
 
+@remote_compatible
 def test_wpas_ctrl_dump(dev, apdev):
     """wpa_supplicant ctrl_iface and DUMP/GET global parameters"""
     vals = dev[0].get_config()
@@ -1411,7 +1481,7 @@ def test_wpas_ctrl_dump(dev, apdev):
 
 def test_wpas_ctrl_interface_add(dev, apdev):
     """wpa_supplicant INTERFACE_ADD/REMOVE with vif creation/removal"""
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
@@ -1424,6 +1494,48 @@ def test_wpas_ctrl_interface_add(dev, apdev):
     dev[0].global_request("INTERFACE_REMOVE " + ifname)
     hwsim_utils.test_connectivity(dev[0], hapd)
 
+def test_wpas_ctrl_interface_add_sta(dev, apdev):
+    """wpa_supplicant INTERFACE_ADD/REMOVE with STA vif creation/removal"""
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
+    ifname = "test-" + dev[0].ifname
+    dev[0].interface_add(ifname, create=True, if_type='sta')
+    wpas = WpaSupplicant(ifname=ifname)
+    wpas.connect("open", key_mgmt="NONE", scan_freq="2412")
+    wpas.request("DISCONNECT")
+    wpas.wait_disconnected()
+    dev[0].global_request("INTERFACE_REMOVE " + ifname)
+
+def test_wpas_ctrl_interface_add_ap(dev, apdev):
+    """wpa_supplicant INTERFACE_ADD/REMOVE AP interface"""
+    with HWSimRadio() as (radio, iface):
+        wpas0 = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+        wpas0.interface_add(iface)
+
+        ifname = "test-wpas-ap"
+        wpas0.interface_add(ifname, create=True, if_type='ap')
+        wpas = WpaSupplicant(ifname=ifname)
+
+        id = wpas.add_network()
+        wpas.set_network(id, "mode", "2")
+        wpas.set_network_quoted(id, "ssid", "wpas-ap-open")
+        wpas.set_network(id, "key_mgmt", "NONE")
+        wpas.set_network(id, "frequency", "2412")
+        wpas.set_network(id, "scan_freq", "2412")
+        wpas.select_network(id)
+        wait_ap_ready(wpas)
+
+        dev[1].connect("wpas-ap-open", key_mgmt="NONE", scan_freq="2412")
+        dev[2].connect("wpas-ap-open", key_mgmt="NONE", scan_freq="2412")
+
+        hwsim_utils.test_connectivity(wpas, dev[1])
+        hwsim_utils.test_connectivity(dev[1], dev[2])
+
+        dev[1].request("DISCONNECT")
+        dev[2].request("DISCONNECT")
+        dev[1].wait_disconnected()
+        dev[2].wait_disconnected()
+        wpas0.global_request("INTERFACE_REMOVE " + ifname)
+
 def test_wpas_ctrl_interface_add_many(dev, apdev):
     """wpa_supplicant INTERFACE_ADD/REMOVE with vif creation/removal (many)"""
     try:
@@ -1434,9 +1546,10 @@ def test_wpas_ctrl_interface_add_many(dev, apdev):
             dev[0].global_request("INTERFACE_REMOVE " + ifname)
 
 def _test_wpas_ctrl_interface_add_many(dev, apdev):
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
+    dev[0].dump_monitor()
 
     l = []
     for i in range(10):
@@ -1444,9 +1557,14 @@ def _test_wpas_ctrl_interface_add_many(dev, apdev):
         dev[0].interface_add(ifname, create=True)
         wpas = WpaSupplicant(ifname=ifname)
         wpas.connect("open", key_mgmt="NONE", scan_freq="2412")
+        wpas.dump_monitor()
         l.append(wpas)
+        dev[0].dump_monitor()
     for wpas in l:
+        wpas.dump_monitor()
         hwsim_utils.test_connectivity(wpas, hapd)
+        wpas.dump_monitor()
+    dev[0].dump_monitor()
 
 def test_wpas_ctrl_interface_add2(dev, apdev):
     """wpa_supplicant INTERFACE_ADD/REMOVE with vif without creation/removal"""
@@ -1457,12 +1575,14 @@ def test_wpas_ctrl_interface_add2(dev, apdev):
         subprocess.call(['iw', 'dev', ifname, 'del'])
 
 def _test_wpas_ctrl_interface_add2(dev, apdev, ifname):
-    hapd = hostapd.add_ap(apdev[0]['ifname'], { "ssid": "open" })
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
     hwsim_utils.test_connectivity(dev[0], hapd)
 
     subprocess.call(['iw', 'dev', dev[0].ifname, 'interface', 'add', ifname,
                      'type', 'station'])
+    subprocess.call(['ip', 'link', 'set', 'dev', ifname, 'address',
+                     '02:01:00:00:02:01'])
     dev[0].interface_add(ifname, set_ifname=False, all_params=True)
     wpas = WpaSupplicant(ifname=ifname)
     wpas.connect("open", key_mgmt="NONE", scan_freq="2412")
@@ -1514,6 +1634,7 @@ def test_wpas_ctrl_wait(dev, apdev, test_params):
         if os.path.exists(pidfile):
             raise Exception("PID file not removed")
 
+@remote_compatible
 def test_wpas_ctrl_oom(dev):
     """Various wpa_supplicant ctrl_iface OOM cases"""
     try:
@@ -1571,8 +1692,6 @@ def _test_wpas_ctrl_oom(dev):
                3, 'wpa_supplicant_ctrl_iface_wps_nfc_token'),
               ('WPS_NFC_TOKEN NDEF', 'FAIL',
                4, 'wpa_supplicant_ctrl_iface_wps_nfc_token'),
-              ('WPS_NFC_TOKEN NDEF', 'FAIL',
-               5, 'wpa_supplicant_ctrl_iface_wps_nfc_token'),
               ('NFC_REPORT_HANDOVER ROLE TYPE 00 00', 'FAIL',
                1, 'wpas_ctrl_nfc_report_handover'),
               ('NFC_REPORT_HANDOVER ROLE TYPE 00 00', 'FAIL',
@@ -1583,8 +1702,6 @@ def _test_wpas_ctrl_oom(dev):
                1, 'ndef_build_record'),
               ('NFC_GET_HANDOVER_REQ NDEF P2P-CR', None,
                1, 'wpas_p2p_nfc_handover'),
-              ('NFC_GET_HANDOVER_REQ NDEF P2P-CR', 'FAIL',
-               2, 'wpas_p2p_nfc_handover'),
               ('NFC_GET_HANDOVER_REQ NDEF P2P-CR', None,
                1, 'wps_build_nfc_handover_req_p2p'),
               ('NFC_GET_HANDOVER_REQ NDEF P2P-CR', 'FAIL',
@@ -1593,18 +1710,6 @@ def _test_wpas_ctrl_oom(dev):
                1, 'wpas_ctrl_nfc_get_handover_sel_p2p'),
               ('NFC_GET_HANDOVER_SEL NDEF P2P-CR', None,
                1, 'wpas_ctrl_nfc_get_handover_sel_p2p'),
-              ('NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG', 'FAIL',
-               2, 'wpas_ctrl_nfc_get_handover_sel_p2p'),
-              ('NFC_GET_HANDOVER_SEL NDEF P2P-CR', 'FAIL',
-               2, 'wpas_ctrl_nfc_get_handover_sel_p2p'),
-              ('NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG', 'FAIL',
-               3, 'wpas_ctrl_nfc_get_handover_sel_p2p'),
-              ('NFC_GET_HANDOVER_SEL NDEF P2P-CR', 'FAIL',
-               3, 'wpas_ctrl_nfc_get_handover_sel_p2p'),
-              ('NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG', 'FAIL',
-               4, 'wpas_ctrl_nfc_get_handover_sel_p2p'),
-              ('NFC_GET_HANDOVER_SEL NDEF P2P-CR', 'FAIL',
-               4, 'wpas_ctrl_nfc_get_handover_sel_p2p'),
               ('P2P_ASP_PROVISION_RESP 00:11:22:33:44:55 id=1', 'FAIL',
                1, 'p2p_parse_asp_provision_cmd'),
               ('P2P_SERV_DISC_REQ 00:11:22:33:44:55 02000001', 'FAIL',
@@ -1657,11 +1762,15 @@ def _test_wpas_ctrl_oom(dev):
                1, 'wpa_supplicant_ctrl_iface_autoscan'),
               ('PING', None,
                1, 'wpa_supplicant_ctrl_iface_process') ]
+    tls = dev[0].request("GET tls_library")
+    if not tls.startswith("internal"):
+        tests.append(('NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG', 'FAIL',
+                      4, 'wpas_ctrl_nfc_get_handover_sel_p2p'))
     for cmd,exp,count,func in tests:
         with alloc_fail(dev[0], count, func):
             res = dev[0].request(cmd)
             if exp and exp not in res:
-                raise Exception("Unexpected success for '%s' during OOM" % cmd)
+                raise Exception("Unexpected success for '%s' during OOM (%d:%s)" % (cmd, count, func))
 
     tests = [ ('FOO', None,
                1, 'wpa_supplicant_global_ctrl_iface_process'),
@@ -1673,6 +1782,23 @@ def _test_wpas_ctrl_oom(dev):
             if exp and exp not in res:
                 raise Exception("Unexpected success for '%s' during OOM" % cmd)
 
+@remote_compatible
+def test_wpas_ctrl_error(dev):
+    """Various wpa_supplicant ctrl_iface error cases"""
+    tests = [ ('WPS_NFC_TOKEN NDEF', 'FAIL',
+               1, 'wpa_supplicant_ctrl_iface_wps_nfc_token'),
+              ('WPS_NFC_TOKEN NDEF', 'FAIL',
+               2, 'wpa_supplicant_ctrl_iface_wps_nfc_token'),
+              ('NFC_GET_HANDOVER_REQ NDEF P2P-CR', None,
+               1, 'wpas_p2p_nfc_handover'),
+              ('NFC_GET_HANDOVER_REQ NDEF P2P-CR', None,
+               1, 'wps_build_nfc_handover_req_p2p') ]
+    for cmd,exp,count,func in tests:
+        with fail_test(dev[0], count, func):
+            res = dev[0].request(cmd)
+            if exp and exp not in res:
+                raise Exception("Unexpected success for '%s' during failure testing (%d:%s)" % (cmd, count, func))
+
 def test_wpas_ctrl_socket_full(dev, apdev, test_params):
     """wpa_supplicant control socket and full send buffer"""
     if not dev[0].ping():
@@ -1757,3 +1883,93 @@ def test_wpas_ctrl_socket_full(dev, apdev, test_params):
     if not dev[0].ping():
         raise Exception("Could not ping wpa_supplicant at the end of the test")
     dev[0].get_status()
+
+def test_wpas_ctrl_event_burst(dev, apdev):
+    """wpa_supplicant control socket and event burst"""
+    if "OK" not in dev[0].request("EVENT_TEST 1000"):
+        raise Exception("Could not request event messages")
+
+    total_i = 0
+    total_g = 0
+    for i in range(100):
+        (i,g) = dev[0].dump_monitor()
+        total_i += i
+        total_g += g
+        logger.info("Received i=%d g=%d" % (i, g))
+        if total_i >= 1000 and total_g >= 1000:
+            break
+        time.sleep(0.05)
+
+    if total_i < 1000:
+        raise Exception("Some per-interface events not seen: %d" % total_i)
+    if total_g < 1000:
+        raise Exception("Some global events not seen: %d" % total_g)
+
+    if not dev[0].ping():
+        raise Exception("Could not ping wpa_supplicant at the end of the test")
+
+@remote_compatible
+def test_wpas_ctrl_sched_scan_plans(dev, apdev):
+    """wpa_supplicant sched_scan_plans parsing"""
+    dev[0].request("SET sched_scan_plans foo")
+    dev[0].request("SET sched_scan_plans 10:100 20:200 30")
+    with alloc_fail(dev[0], 1, "wpas_sched_scan_plans_set"):
+        dev[0].request("SET sched_scan_plans 10:100")
+    dev[0].request("SET sched_scan_plans 4294967295:0")
+    dev[0].request("SET sched_scan_plans 1 1")
+    dev[0].request("SET sched_scan_plans  ")
+    dev[0].request("SET sched_scan_plans ")
+
+def test_wpas_ctrl_signal_monitor(dev, apdev):
+    """wpa_supplicant SIGNAL_MONITOR command"""
+    hapd = hostapd.add_ap(apdev[0], { "ssid": "open" })
+    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
+    dev[1].connect("open", key_mgmt="NONE", scan_freq="2412",
+                   bgscan="simple:1:-45:2")
+    dev[2].connect("open", key_mgmt="NONE", scan_freq="2412")
+
+    tests = [ " THRESHOLD=-45", " THRESHOLD=-44 HYSTERESIS=5", "" ]
+    try:
+        if "FAIL" in dev[2].request("SIGNAL_MONITOR THRESHOLD=-1 HYSTERESIS=5"):
+            raise Exception("SIGNAL_MONITOR command failed")
+        for t in tests:
+            if "OK" not in dev[0].request("SIGNAL_MONITOR" + t):
+                raise Exception("SIGNAL_MONITOR command failed: " + t)
+        if "FAIL" not in dev[1].request("SIGNAL_MONITOR THRESHOLD=-44 HYSTERESIS=5"):
+            raise Exception("SIGNAL_MONITOR command accepted while using bgscan")
+        ev = dev[2].wait_event(["CTRL-EVENT-SIGNAL-CHANGE"], timeout=10)
+        if ev is None:
+            raise Exception("No signal change event seen")
+        if "above=0" not in ev:
+            raise Exception("Unexpected signal change event contents: " + ev)
+    finally:
+        dev[0].request("SIGNAL_MONITOR")
+        dev[1].request("SIGNAL_MONITOR")
+        dev[2].request("SIGNAL_MONITOR")
+
+    dev[0].request("REMOVE_NETWORK all")
+    dev[1].request("REMOVE_NETWORK all")
+    dev[1].wait_disconnected()
+
+def test_wpas_ctrl_p2p_listen_offload(dev, apdev):
+    """wpa_supplicant P2P_LO_START and P2P_LO_STOP commands"""
+    dev[0].request("P2P_LO_STOP")
+    dev[0].request("P2P_LO_START ")
+    dev[0].request("P2P_LO_START 2412")
+    dev[0].request("P2P_LO_START 2412 100 200 3")
+    dev[0].request("P2P_LO_STOP")
+
+def test_wpas_ctrl_driver_flags(dev, apdev):
+    """DRIVER_FLAGS command"""
+    params = hostapd.wpa2_params(ssid="test", passphrase="12345678")
+    hapd = hostapd.add_ap(apdev[0], params)
+    hapd_flags = hapd.request("DRIVER_FLAGS")
+    wpas_flags = dev[0].request("DRIVER_FLAGS")
+    if "FAIL" in hapd_flags:
+        raise Exception("DRIVER_FLAGS failed")
+    if hapd_flags != wpas_flags:
+        raise Exception("Unexpected difference in hostapd vs. wpa_supplicant DRIVER_FLAGS output")
+    logger.info("DRIVER_FLAGS: " + hapd_flags)
+    flags = hapd_flags.split('\n')
+    if 'AP' not in flags:
+        raise Exception("AP flag missing from DRIVER_FLAGS")
index b6188d1..2ef1861 100644 (file)
@@ -1,5 +1,3 @@
-#!/usr/bin/python
-#
 # wpa_supplicant mesh mode tests
 # Copyright (c) 2014, cozybit Inc.
 #
@@ -8,11 +6,16 @@
 
 import logging
 logger = logging.getLogger()
+import os
+import struct
 import subprocess
+import time
 
 import hwsim_utils
+import hostapd
 from wpasupplicant import WpaSupplicant
-from utils import HwsimSkip, alloc_fail
+from utils import HwsimSkip, alloc_fail, fail_test, wait_fail_trigger
+from tshark import run_tshark
 
 def check_mesh_support(dev, secure=False):
     if "MESH" not in dev.get_capability("modes"):
@@ -102,14 +105,20 @@ def test_wpas_add_set_remove_support(dev):
     dev[0].set_network(id, "mode", "5")
     dev[0].remove_network(id)
 
-def add_open_mesh_network(dev, freq="2412", start=True, beacon_int=0):
+def add_open_mesh_network(dev, freq="2412", start=True, beacon_int=0,
+                          basic_rates=None, chwidth=0):
     id = dev.add_network()
     dev.set_network(id, "mode", "5")
     dev.set_network_quoted(id, "ssid", "wpas-mesh-open")
     dev.set_network(id, "key_mgmt", "NONE")
-    dev.set_network(id, "frequency", freq)
+    if freq:
+        dev.set_network(id, "frequency", freq)
+    if chwidth > 0:
+        dev.set_network(id, "max_oper_chwidth", str(chwidth))
     if beacon_int:
         dev.set_network(id, "beacon_int", str(beacon_int))
+    if basic_rates:
+        dev.set_network(id, "mesh_basic_rates", basic_rates)
     if start:
         dev.mesh_group_add(id)
     return id
@@ -185,8 +194,8 @@ def test_wpas_mesh_mode_scan(dev):
 def test_wpas_mesh_open(dev, apdev):
     """wpa_supplicant open MESH network connectivity"""
     check_mesh_support(dev[0])
-    add_open_mesh_network(dev[0], freq="2462")
-    add_open_mesh_network(dev[1], freq="2462")
+    add_open_mesh_network(dev[0], freq="2462", basic_rates="60 120 240")
+    add_open_mesh_network(dev[1], freq="2462", basic_rates="60 120 240")
 
     # Check for mesh joined
     check_mesh_group_added(dev[0])
@@ -199,6 +208,17 @@ def test_wpas_mesh_open(dev, apdev):
     # Test connectivity 0->1 and 1->0
     hwsim_utils.test_connectivity(dev[0], dev[1])
 
+    state = dev[0].get_status_field("wpa_state")
+    if state != "COMPLETED":
+        raise Exception("Unexpected wpa_state on dev0: " + state)
+    state = dev[1].get_status_field("wpa_state")
+    if state != "COMPLETED":
+        raise Exception("Unexpected wpa_state on dev1: " + state)
+
+    mode = dev[0].get_status_field("mode")
+    if mode != "mesh":
+        raise Exception("Unexpected mode: " + mode)
+
 def test_wpas_mesh_open_no_auto(dev, apdev):
     """wpa_supplicant open MESH network connectivity"""
     check_mesh_support(dev[0])
@@ -222,7 +242,35 @@ def test_wpas_mesh_open_no_auto(dev, apdev):
     # Test connectivity 0->1 and 1->0
     hwsim_utils.test_connectivity(dev[0], dev[1])
 
-def add_mesh_secure_net(dev, psk=True):
+def test_mesh_open_no_auto2(dev, apdev):
+    """Open mesh network connectivity, no_auto on both peers"""
+    check_mesh_support(dev[0])
+    id = add_open_mesh_network(dev[0], start=False)
+    dev[0].set_network(id, "no_auto_peer", "1")
+    dev[0].mesh_group_add(id)
+
+    id = add_open_mesh_network(dev[1], start=False)
+    dev[1].set_network(id, "no_auto_peer", "1")
+    dev[1].mesh_group_add(id)
+
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+
+    ev = dev[0].wait_event(["will not initiate new peer link"], timeout=10)
+    if ev is None:
+        raise Exception("Missing no-initiate message")
+    addr1 = dev[1].own_addr()
+    if "OK" not in dev[0].request("MESH_PEER_ADD " + addr1):
+        raise Exception("MESH_PEER_ADD failed")
+    if "FAIL" not in dev[0].request("MESH_PEER_ADD ff:ff:ff:ff:ff:ff"):
+        raise Exception("MESH_PEER_ADD with unknown STA succeeded")
+    check_mesh_peer_connected(dev[0], timeout=30)
+    check_mesh_peer_connected(dev[1])
+    if "FAIL" not in dev[0].request("MESH_PEER_ADD " + addr1):
+        raise Exception("MESH_PEER_ADD succeeded for connected STA")
+    hwsim_utils.test_connectivity(dev[0], dev[1])
+
+def add_mesh_secure_net(dev, psk=True, pmf=False, pairwise=None, group=None):
     id = dev.add_network()
     dev.set_network(id, "mode", "5")
     dev.set_network_quoted(id, "ssid", "wpas-mesh-sec")
@@ -230,6 +278,12 @@ def add_mesh_secure_net(dev, psk=True):
     dev.set_network(id, "frequency", "2412")
     if psk:
         dev.set_network_quoted(id, "psk", "thisismypassphrase!")
+    if pmf:
+        dev.set_network(id, "ieee80211w", "2")
+    if pairwise:
+        dev.set_network(id, "pairwise", pairwise)
+    if group:
+        dev.set_network(id, "group", group)
     return id
 
 def test_wpas_mesh_secure(dev, apdev):
@@ -254,6 +308,96 @@ def test_wpas_mesh_secure(dev, apdev):
     # Test connectivity 0->1 and 1->0
     hwsim_utils.test_connectivity(dev[0], dev[1])
 
+    state = dev[0].get_status_field("wpa_state")
+    if state != "COMPLETED":
+        raise Exception("Unexpected wpa_state on dev0: " + state)
+    state = dev[1].get_status_field("wpa_state")
+    if state != "COMPLETED":
+        raise Exception("Unexpected wpa_state on dev1: " + state)
+
+def test_mesh_secure_pmf(dev, apdev):
+    """Secure mesh network connectivity with PMF enabled"""
+    check_mesh_support(dev[0], secure=True)
+    dev[0].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[0], pmf=True)
+    dev[0].mesh_group_add(id)
+
+    dev[1].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[1], pmf=True)
+    dev[1].mesh_group_add(id)
+
+    # Check for mesh joined
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+
+    # Check for peer connected
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[1])
+
+    # Test connectivity 0->1 and 1->0
+    hwsim_utils.test_connectivity(dev[0], dev[1])
+
+def run_mesh_secure(dev, cipher):
+    if cipher not in dev[0].get_capability("pairwise"):
+        raise HwsimSkip("Cipher %s not supported" % cipher)
+    check_mesh_support(dev[0], secure=True)
+    dev[0].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[0], pairwise=cipher, group=cipher)
+    dev[0].mesh_group_add(id)
+
+    dev[1].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[1], pairwise=cipher, group=cipher)
+    dev[1].mesh_group_add(id)
+
+    # Check for mesh joined
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+
+    # Check for peer connected
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[1])
+
+    # Test connectivity 0->1 and 1->0
+    hwsim_utils.test_connectivity(dev[0], dev[1])
+
+def test_mesh_secure_ccmp(dev, apdev):
+    """Secure mesh with CCMP"""
+    run_mesh_secure(dev, "CCMP")
+
+def test_mesh_secure_gcmp(dev, apdev):
+    """Secure mesh with GCMP"""
+    run_mesh_secure(dev, "GCMP")
+
+def test_mesh_secure_gcmp_256(dev, apdev):
+    """Secure mesh with GCMP-256"""
+    run_mesh_secure(dev, "GCMP-256")
+
+def test_mesh_secure_ccmp_256(dev, apdev):
+    """Secure mesh with CCMP-256"""
+    run_mesh_secure(dev, "CCMP-256")
+
+def test_mesh_secure_invalid_pairwise_cipher(dev, apdev):
+    """Secure mesh and invalid group cipher"""
+    check_mesh_support(dev[0], secure=True)
+    dev[0].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[0], pairwise="TKIP", group="CCMP")
+    if dev[0].mesh_group_add(id) != None:
+        raise Exception("Unexpected group add success")
+    ev = dev[0].wait_event(["mesh: Invalid pairwise cipher"], timeout=1)
+    if ev is None:
+        raise Exception("Invalid pairwise cipher not reported")
+
+def test_mesh_secure_invalid_group_cipher(dev, apdev):
+    """Secure mesh and invalid group cipher"""
+    check_mesh_support(dev[0], secure=True)
+    dev[0].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[0], pairwise="CCMP", group="TKIP")
+    if dev[0].mesh_group_add(id) != None:
+        raise Exception("Unexpected group add success")
+    ev = dev[0].wait_event(["mesh: Invalid group cipher"], timeout=1)
+    if ev is None:
+        raise Exception("Invalid group cipher not reported")
+
 def test_wpas_mesh_secure_sae_group_mismatch(dev, apdev):
     """wpa_supplicant secure MESH and SAE group mismatch"""
     check_mesh_support(dev[0], secure=True)
@@ -305,6 +449,30 @@ def test_wpas_mesh_secure_sae_group_mismatch(dev, apdev):
     dev[1].request("SET sae_groups ")
     dev[2].request("SET sae_groups ")
 
+def test_wpas_mesh_secure_sae_group_negotiation(dev, apdev):
+    """wpa_supplicant secure MESH and SAE group negotiation"""
+    check_mesh_support(dev[0], secure=True)
+    addr0 = dev[0].own_addr()
+    addr1 = dev[1].own_addr()
+
+    #dev[0].request("SET sae_groups 21 20 25 26")
+    dev[0].request("SET sae_groups 25")
+    id = add_mesh_secure_net(dev[0])
+    dev[0].mesh_group_add(id)
+
+    dev[1].request("SET sae_groups 19 25")
+    id = add_mesh_secure_net(dev[1])
+    dev[1].mesh_group_add(id)
+
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[1])
+
+    dev[0].request("SET sae_groups ")
+    dev[1].request("SET sae_groups ")
+
 def test_wpas_mesh_secure_sae_missing_password(dev, apdev):
     """wpa_supplicant secure MESH and missing SAE password"""
     check_mesh_support(dev[0], secure=True)
@@ -347,6 +515,67 @@ def test_wpas_mesh_secure_no_auto(dev, apdev):
     dev[0].request("SET sae_groups ")
     dev[1].request("SET sae_groups ")
 
+def test_wpas_mesh_secure_dropped_frame(dev, apdev):
+    """Secure mesh network connectivity when the first plink Open is dropped"""
+    check_mesh_support(dev[0], secure=True)
+
+    dev[0].request("SET ext_mgmt_frame_handling 1")
+    dev[0].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[0])
+    dev[0].mesh_group_add(id)
+
+    dev[1].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[1])
+    dev[1].mesh_group_add(id)
+
+    # Check for mesh joined
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+
+    # Drop the first Action frame (plink Open) to test unexpected order of
+    # Confirm/Open messages.
+    count = 0
+    while True:
+        count += 1
+        if count > 10:
+            raise Exception("Did not see Action frames")
+        rx_msg = dev[0].mgmt_rx()
+        if rx_msg is None:
+            raise Exception("MGMT-RX timeout")
+        if rx_msg['subtype'] == 13:
+            logger.info("Drop the first Action frame")
+            break
+        if "OK" not in dev[0].request("MGMT_RX_PROCESS freq={} datarate={} ssi_signal={} frame={}".format(rx_msg['freq'], rx_msg['datarate'], rx_msg['ssi_signal'], rx_msg['frame'].encode('hex'))):
+            raise Exception("MGMT_RX_PROCESS failed")
+
+    dev[0].request("SET ext_mgmt_frame_handling 0")
+
+    # Check for peer connected
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[1])
+
+    # Test connectivity 0->1 and 1->0
+    hwsim_utils.test_connectivity(dev[0], dev[1])
+
+def test_mesh_secure_fail(dev, apdev):
+    """Secure mesh network connectivity failure"""
+    check_mesh_support(dev[0], secure=True)
+    dev[0].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[0], pmf=True)
+    dev[0].mesh_group_add(id)
+
+    dev[1].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[1], pmf=True)
+
+    with fail_test(dev[0], 1, "wpa_driver_nl80211_sta_add;mesh_mpm_auth_peer"):
+        dev[1].mesh_group_add(id)
+
+        check_mesh_group_added(dev[0])
+        check_mesh_group_added(dev[1])
+
+        check_mesh_peer_connected(dev[0])
+        check_mesh_peer_connected(dev[1])
+
 def test_wpas_mesh_ctrl(dev):
     """wpa_supplicant ctrl_iface mesh command error cases"""
     check_mesh_support(dev[0])
@@ -440,7 +669,7 @@ def test_wpas_mesh_dynamic_interface(dev):
         if mesh1:
             dev[1].request("MESH_GROUP_REMOVE " + mesh1)
 
-def test_wpas_mesh_max_peering(dev, apdev):
+def test_wpas_mesh_max_peering(dev, apdev, params):
     """Mesh max peering limit"""
     check_mesh_support(dev[0])
     try:
@@ -476,6 +705,40 @@ def test_wpas_mesh_max_peering(dev, apdev):
     finally:
         dev[0].request("SET max_peer_links 99")
 
+    addr0 = dev[0].own_addr()
+    addr1 = dev[1].own_addr()
+    addr2 = dev[2].own_addr()
+
+    capfile = os.path.join(params['logdir'], "hwsim0.pcapng")
+    filt = "wlan.fc.type_subtype == 8"
+    out = run_tshark(capfile, filt, [ "wlan.sa", "wlan.mesh.config.cap" ])
+    pkts = out.splitlines()
+    one = [ 0, 0, 0 ]
+    zero = [ 0, 0, 0 ]
+    for pkt in pkts:
+        addr, cap = pkt.split('\t')
+        cap = int(cap, 16)
+        if addr == addr0:
+            idx = 0
+        elif addr == addr1:
+            idx = 1
+        elif addr == addr2:
+            idx = 2
+        else:
+            continue
+        if cap & 0x01:
+            one[idx] += 1
+        else:
+            zero[idx] += 1
+    logger.info("one: " + str(one))
+    logger.info("zero: " + str(zero))
+    if zero[0] == 0:
+        raise Exception("Accepting Additional Mesh Peerings not cleared")
+    if one[0] == 0:
+        raise Exception("Accepting Additional Mesh Peerings was not set in the first Beacon frame")
+    if zero[1] > 0 or zero[2] > 0 or one[1] == 0 or one[2] == 0:
+        raise Exception("Unexpected value in Accepting Additional Mesh Peerings from other STAs")
+
 def test_wpas_mesh_open_5ghz(dev, apdev):
     """wpa_supplicant open MESH network on 5 GHz band"""
     try:
@@ -508,6 +771,104 @@ def _test_wpas_mesh_open_5ghz(dev, apdev):
     # Test connectivity 0->1 and 1->0
     hwsim_utils.test_connectivity(dev[0], dev[1])
 
+def test_wpas_mesh_open_vht_80p80(dev, apdev):
+    """wpa_supplicant open MESH network on VHT 80+80 MHz channel"""
+    try:
+        _test_wpas_mesh_open_vht_80p80(dev, apdev)
+    finally:
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        dev[0].flush_scan_cache()
+        dev[1].flush_scan_cache()
+
+def _test_wpas_mesh_open_vht_80p80(dev, apdev):
+    check_mesh_support(dev[0])
+    subprocess.call(['iw', 'reg', 'set', 'US'])
+    for i in range(2):
+        for j in range(5):
+            ev = dev[i].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=5)
+            if ev is None:
+                raise Exception("No regdom change event")
+            if "alpha2=US" in ev:
+                break
+        add_open_mesh_network(dev[i], freq="5180", chwidth=3)
+
+    # Check for mesh joined
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+
+    # Check for peer connected
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[1])
+
+    # Test connectivity 0->1 and 1->0
+    hwsim_utils.test_connectivity(dev[0], dev[1])
+
+    sig = dev[0].request("SIGNAL_POLL").splitlines()
+    if "WIDTH=80+80 MHz" not in sig:
+        raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
+    if "CENTER_FRQ1=5210" not in sig:
+        raise Exception("Unexpected SIGNAL_POLL value(3): " + str(sig))
+    if "CENTER_FRQ2=5775" not in sig:
+        raise Exception("Unexpected SIGNAL_POLL value(4): " + str(sig))
+
+    sig = dev[1].request("SIGNAL_POLL").splitlines()
+    if "WIDTH=80+80 MHz" not in sig:
+        raise Exception("Unexpected SIGNAL_POLL value(2b): " + str(sig))
+    if "CENTER_FRQ1=5210" not in sig:
+        raise Exception("Unexpected SIGNAL_POLL value(3b): " + str(sig))
+    if "CENTER_FRQ2=5775" not in sig:
+        raise Exception("Unexpected SIGNAL_POLL value(4b): " + str(sig))
+
+def test_mesh_open_vht_160(dev, apdev):
+    """Open mesh network on VHT 160 MHz channel"""
+    try:
+        _test_mesh_open_vht_160(dev, apdev)
+    finally:
+        subprocess.call(['iw', 'reg', 'set', '00'])
+        dev[0].flush_scan_cache()
+        dev[1].flush_scan_cache()
+
+def _test_mesh_open_vht_160(dev, apdev):
+    check_mesh_support(dev[0])
+    subprocess.call(['iw', 'reg', 'set', 'ZA'])
+    for i in range(2):
+        for j in range(5):
+            ev = dev[i].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=5)
+            if ev is None:
+                raise Exception("No regdom change event")
+            if "alpha2=ZA" in ev:
+                break
+
+        cmd = subprocess.Popen(["iw", "reg", "get"], stdout=subprocess.PIPE)
+        reg = cmd.stdout.read()
+        if "@ 160)" not in reg:
+            raise HwsimSkip("160 MHz channel not supported in regulatory information")
+
+        add_open_mesh_network(dev[i], freq="5520", chwidth=2)
+
+    # Check for mesh joined
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+
+    # Check for peer connected
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[1])
+
+    # Test connectivity 0->1 and 1->0
+    hwsim_utils.test_connectivity(dev[0], dev[1])
+
+    sig = dev[0].request("SIGNAL_POLL").splitlines()
+    if "WIDTH=160 MHz" not in sig:
+        raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
+    if "FREQUENCY=5520" not in sig:
+        raise Exception("Unexpected SIGNAL_POLL value(3): " + str(sig))
+
+    sig = dev[1].request("SIGNAL_POLL").splitlines()
+    if "WIDTH=160 MHz" not in sig:
+        raise Exception("Unexpected SIGNAL_POLL value(2b): " + str(sig))
+    if "FREQUENCY=5520" not in sig:
+        raise Exception("Unexpected SIGNAL_POLL value(3b): " + str(sig))
+
 def test_wpas_mesh_password_mismatch(dev, apdev):
     """Mesh network and one device with mismatching password"""
     check_mesh_support(dev[0], secure=True)
@@ -610,3 +971,996 @@ def test_mesh_wpa_auth_init_oom(dev, apdev):
         ev = dev[0].wait_event(["MESH-GROUP-STARTED"], timeout=0.2)
         if ev is not None:
             raise Exception("Unexpected mesh group start during OOM")
+
+def test_mesh_wpa_init_fail(dev, apdev):
+    """Secure mesh network setup local failure"""
+    check_mesh_support(dev[0], secure=True)
+    dev[0].request("SET sae_groups ")
+
+    with fail_test(dev[0], 1, "os_get_random;=__mesh_rsn_auth_init"):
+        id = add_mesh_secure_net(dev[0])
+        dev[0].mesh_group_add(id)
+        wait_fail_trigger(dev[0], "GET_FAIL")
+
+    dev[0].dump_monitor()
+    with alloc_fail(dev[0], 1, "mesh_rsn_auth_init"):
+        id = add_mesh_secure_net(dev[0])
+        dev[0].mesh_group_add(id)
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+    dev[0].dump_monitor()
+    with fail_test(dev[0], 1, "os_get_random;mesh_rsn_init_ampe_sta"):
+        id = add_mesh_secure_net(dev[0])
+        dev[0].mesh_group_add(id)
+        dev[1].request("SET sae_groups ")
+        id = add_mesh_secure_net(dev[1])
+        dev[1].mesh_group_add(id)
+        wait_fail_trigger(dev[0], "GET_FAIL")
+
+def test_wpas_mesh_reconnect(dev, apdev):
+    """Secure mesh network plink counting during reconnection"""
+    check_mesh_support(dev[0])
+    try:
+        _test_wpas_mesh_reconnect(dev)
+    finally:
+        dev[0].request("SET max_peer_links 99")
+
+def _test_wpas_mesh_reconnect(dev):
+    dev[0].request("SET max_peer_links 2")
+    dev[0].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[0])
+    dev[0].set_network(id, "beacon_int", "100")
+    dev[0].mesh_group_add(id)
+    dev[1].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[1])
+    dev[1].mesh_group_add(id)
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[1])
+
+    for i in range(3):
+        # Drop incoming management frames to avoid handling link close
+        dev[0].request("SET ext_mgmt_frame_handling 1")
+        dev[1].mesh_group_remove()
+        check_mesh_group_removed(dev[1])
+        dev[1].request("FLUSH")
+        dev[0].request("SET ext_mgmt_frame_handling 0")
+        id = add_mesh_secure_net(dev[1])
+        dev[1].mesh_group_add(id)
+        check_mesh_group_added(dev[1])
+        check_mesh_peer_connected(dev[1])
+        dev[0].dump_monitor()
+        dev[1].dump_monitor()
+
+def test_wpas_mesh_gate_forwarding(dev, apdev, p):
+    """Mesh forwards traffic to unknown sta to mesh gates"""
+    addr0 = dev[0].own_addr()
+    addr1 = dev[1].own_addr()
+    addr2 = dev[2].own_addr()
+    external_sta = '02:11:22:33:44:55'
+
+    # start 3 node connected mesh
+    check_mesh_support(dev[0])
+    for i in range(3):
+        add_open_mesh_network(dev[i])
+        check_mesh_group_added(dev[i])
+    for i in range(3):
+        check_mesh_peer_connected(dev[i])
+
+    hwsim_utils.test_connectivity(dev[0], dev[1])
+    hwsim_utils.test_connectivity(dev[1], dev[2])
+    hwsim_utils.test_connectivity(dev[0], dev[2])
+
+    # dev0 and dev1 are mesh gates
+    subprocess.call(['iw', 'dev', dev[0].ifname, 'set', 'mesh_param',
+                     'mesh_gate_announcements=1'])
+    subprocess.call(['iw', 'dev', dev[1].ifname, 'set', 'mesh_param',
+                     'mesh_gate_announcements=1'])
+
+    # wait for gate announcement frames
+    time.sleep(1)
+
+    # data frame from dev2 -> external sta should be sent to both gates
+    dev[2].request("DATA_TEST_CONFIG 1")
+    dev[2].request("DATA_TEST_TX {} {} 0".format(external_sta, addr2))
+    dev[2].request("DATA_TEST_CONFIG 0")
+
+    capfile = os.path.join(p['logdir'], "hwsim0.pcapng")
+    filt = "wlan.sa==%s && wlan_mgt.fixed.mesh_addr5==%s" % (addr2,
+                                                             external_sta)
+    for i in range(15):
+        da = run_tshark(capfile, filt, [ "wlan.da" ])
+        if addr0 in da and addr1 in da:
+            logger.debug("Frames seen in tshark iteration %d" % i)
+            break
+        time.sleep(0.3)
+
+    if addr0 not in da:
+        raise Exception("Frame to gate %s not observed" % addr0)
+    if addr1 not in da:
+        raise Exception("Frame to gate %s not observed" % addr1)
+
+def test_wpas_mesh_pmksa_caching(dev, apdev):
+    """Secure mesh network and PMKSA caching"""
+    check_mesh_support(dev[0], secure=True)
+    dev[0].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[0])
+    dev[0].mesh_group_add(id)
+
+    dev[1].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[1])
+    dev[1].mesh_group_add(id)
+
+    # Check for mesh joined
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+
+    # Check for peer connected
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[1])
+
+    addr0 = dev[0].own_addr()
+    addr1 = dev[1].own_addr()
+    pmksa0 = dev[0].get_pmksa(addr1)
+    pmksa1 = dev[1].get_pmksa(addr0)
+    if pmksa0 is None or pmksa1 is None:
+        raise Exception("No PMKSA cache entry created")
+    if pmksa0['pmkid'] != pmksa1['pmkid']:
+        raise Exception("PMKID mismatch in PMKSA cache entries")
+
+    if "OK" not in dev[0].request("MESH_PEER_REMOVE " + addr1):
+        raise Exception("Failed to remove peer")
+    pmksa0b = dev[0].get_pmksa(addr1)
+    if pmksa0b is None:
+        raise Exception("PMKSA cache entry not maintained")
+    time.sleep(0.1)
+
+    if "FAIL" not in dev[0].request("MESH_PEER_ADD " + addr1):
+        raise Exception("MESH_PEER_ADD unexpectedly succeeded in no_auto_peer=0 case")
+
+def test_wpas_mesh_pmksa_caching2(dev, apdev):
+    """Secure mesh network and PMKSA caching with no_auto_peer=1"""
+    check_mesh_support(dev[0], secure=True)
+    addr0 = dev[0].own_addr()
+    addr1 = dev[1].own_addr()
+    dev[0].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[0])
+    dev[0].set_network(id, "no_auto_peer", "1")
+    dev[0].mesh_group_add(id)
+
+    dev[1].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[1])
+    dev[1].set_network(id, "no_auto_peer", "1")
+    dev[1].mesh_group_add(id)
+
+    # Check for mesh joined
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+
+    # Check for peer connected
+    ev = dev[0].wait_event(["will not initiate new peer link"], timeout=10)
+    if ev is None:
+        raise Exception("Missing no-initiate message")
+    if "OK" not in dev[0].request("MESH_PEER_ADD " + addr1):
+        raise Exception("MESH_PEER_ADD failed")
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[1])
+
+    pmksa0 = dev[0].get_pmksa(addr1)
+    pmksa1 = dev[1].get_pmksa(addr0)
+    if pmksa0 is None or pmksa1 is None:
+        raise Exception("No PMKSA cache entry created")
+    if pmksa0['pmkid'] != pmksa1['pmkid']:
+        raise Exception("PMKID mismatch in PMKSA cache entries")
+
+    if "OK" not in dev[0].request("MESH_PEER_REMOVE " + addr1):
+        raise Exception("Failed to remove peer")
+    pmksa0b = dev[0].get_pmksa(addr1)
+    if pmksa0b is None:
+        raise Exception("PMKSA cache entry not maintained")
+
+    ev = dev[0].wait_event(["will not initiate new peer link"], timeout=10)
+    if ev is None:
+        raise Exception("Missing no-initiate message (2)")
+    if "OK" not in dev[0].request("MESH_PEER_ADD " + addr1):
+        raise Exception("MESH_PEER_ADD failed (2)")
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[1])
+
+    pmksa0c = dev[0].get_pmksa(addr1)
+    pmksa1c = dev[1].get_pmksa(addr0)
+    if pmksa0c is None or pmksa1c is None:
+        raise Exception("No PMKSA cache entry created (2)")
+    if pmksa0c['pmkid'] != pmksa1c['pmkid']:
+        raise Exception("PMKID mismatch in PMKSA cache entries")
+    if pmksa0['pmkid'] != pmksa0c['pmkid']:
+        raise Exception("PMKID changed")
+
+    hwsim_utils.test_connectivity(dev[0], dev[1])
+
+def test_wpas_mesh_pmksa_caching_no_match(dev, apdev):
+    """Secure mesh network and PMKSA caching with no PMKID match"""
+    check_mesh_support(dev[0], secure=True)
+    addr0 = dev[0].own_addr()
+    addr1 = dev[1].own_addr()
+    dev[0].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[0])
+    dev[0].set_network(id, "no_auto_peer", "1")
+    dev[0].mesh_group_add(id)
+
+    dev[1].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[1])
+    dev[1].set_network(id, "no_auto_peer", "1")
+    dev[1].mesh_group_add(id)
+
+    # Check for mesh joined
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+
+    # Check for peer connected
+    ev = dev[0].wait_event(["will not initiate new peer link"], timeout=10)
+    if ev is None:
+        raise Exception("Missing no-initiate message")
+    if "OK" not in dev[0].request("MESH_PEER_ADD " + addr1):
+        raise Exception("MESH_PEER_ADD failed")
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[1])
+
+    pmksa0 = dev[0].get_pmksa(addr1)
+    pmksa1 = dev[1].get_pmksa(addr0)
+    if pmksa0 is None or pmksa1 is None:
+        raise Exception("No PMKSA cache entry created")
+    if pmksa0['pmkid'] != pmksa1['pmkid']:
+        raise Exception("PMKID mismatch in PMKSA cache entries")
+
+    if "OK" not in dev[0].request("MESH_PEER_REMOVE " + addr1):
+        raise Exception("Failed to remove peer")
+
+    if "OK" not in dev[1].request("PMKSA_FLUSH"):
+        raise Exception("Failed to flush PMKSA cache")
+
+    ev = dev[0].wait_event(["will not initiate new peer link"], timeout=10)
+    if ev is None:
+        raise Exception("Missing no-initiate message (2)")
+    if "OK" not in dev[0].request("MESH_PEER_ADD " + addr1):
+        raise Exception("MESH_PEER_ADD failed (2)")
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[1])
+
+    pmksa0c = dev[0].get_pmksa(addr1)
+    pmksa1c = dev[1].get_pmksa(addr0)
+    if pmksa0c is None or pmksa1c is None:
+        raise Exception("No PMKSA cache entry created (2)")
+    if pmksa0c['pmkid'] != pmksa1c['pmkid']:
+        raise Exception("PMKID mismatch in PMKSA cache entries")
+    if pmksa0['pmkid'] == pmksa0c['pmkid']:
+        raise Exception("PMKID did not change")
+
+    hwsim_utils.test_connectivity(dev[0], dev[1])
+
+def test_mesh_pmksa_caching_oom(dev, apdev):
+    """Secure mesh network and PMKSA caching failing due to OOM"""
+    check_mesh_support(dev[0], secure=True)
+    addr0 = dev[0].own_addr()
+    addr1 = dev[1].own_addr()
+    dev[0].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[0])
+    dev[0].set_network(id, "no_auto_peer", "1")
+    dev[0].mesh_group_add(id)
+
+    dev[1].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[1])
+    dev[1].set_network(id, "no_auto_peer", "1")
+    dev[1].mesh_group_add(id)
+
+    # Check for mesh joined
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+
+    # Check for peer connected
+    ev = dev[0].wait_event(["will not initiate new peer link"], timeout=10)
+    if ev is None:
+        raise Exception("Missing no-initiate message")
+    if "OK" not in dev[0].request("MESH_PEER_ADD " + addr1):
+        raise Exception("MESH_PEER_ADD failed")
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[1])
+
+    if "OK" not in dev[0].request("MESH_PEER_REMOVE " + addr1):
+        raise Exception("Failed to remove peer")
+    pmksa0b = dev[0].get_pmksa(addr1)
+    if pmksa0b is None:
+        raise Exception("PMKSA cache entry not maintained")
+
+    ev = dev[0].wait_event(["will not initiate new peer link"], timeout=10)
+    if ev is None:
+        raise Exception("Missing no-initiate message (2)")
+
+    with alloc_fail(dev[0], 1, "wpa_auth_sta_init;mesh_rsn_auth_sae_sta"):
+        if "OK" not in dev[0].request("MESH_PEER_ADD " + addr1):
+            raise Exception("MESH_PEER_ADD failed (2)")
+        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+
+def test_mesh_oom(dev, apdev):
+    """Mesh network setup failing due to OOM"""
+    check_mesh_support(dev[0], secure=True)
+    dev[0].request("SET sae_groups ")
+
+    with alloc_fail(dev[0], 1, "mesh_config_create"):
+        add_open_mesh_network(dev[0])
+        ev = dev[0].wait_event(["Failed to init mesh"])
+        if ev is None:
+            raise Exception("Init failure not reported")
+
+    with alloc_fail(dev[0], 4, "=wpa_supplicant_mesh_init"):
+        add_open_mesh_network(dev[0], basic_rates="60 120 240")
+        ev = dev[0].wait_event(["Failed to init mesh"])
+        if ev is None:
+            raise Exception("Init failure not reported")
+
+    for i in range(1, 66):
+        dev[0].dump_monitor()
+        logger.info("Test instance %d" % i)
+        try:
+            with alloc_fail(dev[0], i, "wpa_supplicant_mesh_init"):
+                add_open_mesh_network(dev[0])
+                wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
+                ev = dev[0].wait_event(["Failed to init mesh",
+                                        "MESH-GROUP-STARTED"])
+                if ev is None:
+                    raise Exception("Init failure not reported")
+        except Exception, e:
+            if i < 15:
+                raise
+            logger.info("Ignore no-oom for i=%d" % i)
+
+    with alloc_fail(dev[0], 5, "=wpa_supplicant_mesh_init"):
+        id = add_mesh_secure_net(dev[0])
+        dev[0].mesh_group_add(id)
+        ev = dev[0].wait_event(["Failed to init mesh"])
+        if ev is None:
+            raise Exception("Init failure not reported")
+
+def test_mesh_add_interface_oom(dev):
+    """wpa_supplicant mesh with dynamic interface addition failing"""
+    check_mesh_support(dev[0])
+    for i in range(1, 3):
+        mesh = None
+        try:
+            with alloc_fail(dev[0], i, "wpas_mesh_add_interface"):
+                mesh = dev[0].request("MESH_INTERFACE_ADD").strip()
+        finally:
+            if mesh and mesh != "FAIL":
+                dev[0].request("MESH_GROUP_REMOVE " + mesh)
+
+def test_mesh_scan_oom(dev):
+    """wpa_supplicant mesh scan results and OOM"""
+    check_mesh_support(dev[0])
+    add_open_mesh_network(dev[0])
+    check_mesh_group_added(dev[0])
+    for i in range(5):
+        dev[1].scan(freq="2412")
+        res = dev[1].request("SCAN_RESULTS")
+        if "[MESH]" in res:
+            break
+    for r in res.splitlines():
+        if "[MESH]" in r:
+            break
+    bssid = r.split('\t')[0]
+
+    bss = dev[1].get_bss(bssid)
+    if bss is None:
+        raise Exception("Could not get BSS entry for mesh")
+
+    for i in range(1, 3):
+        with alloc_fail(dev[1], i, "mesh_attr_text"):
+            bss = dev[1].get_bss(bssid)
+            if bss and "mesh_id" in bss:
+                raise Exception("Unexpected BSS result during OOM")
+
+def test_mesh_drv_fail(dev, apdev):
+    """Mesh network setup failing due to driver command failure"""
+    check_mesh_support(dev[0], secure=True)
+    dev[0].request("SET sae_groups ")
+
+    with fail_test(dev[0], 1, "nl80211_join_mesh"):
+        add_open_mesh_network(dev[0])
+        ev = dev[0].wait_event(["mesh join error"])
+        if ev is None:
+            raise Exception("Join failure not reported")
+
+    dev[0].dump_monitor()
+    with fail_test(dev[0], 1, "wpa_driver_nl80211_if_add"):
+        if "FAIL" not in dev[0].request("MESH_INTERFACE_ADD").strip():
+            raise Exception("Interface added unexpectedly")
+
+    dev[0].dump_monitor()
+    with fail_test(dev[0], 1, "wpa_driver_nl80211_init_mesh"):
+        add_open_mesh_network(dev[0])
+        ev = dev[0].wait_event(["Could not join mesh"])
+        if ev is None:
+            raise Exception("Join failure not reported")
+
+def test_mesh_sae_groups_invalid(dev, apdev):
+    """Mesh with invalid SAE group configuration"""
+    check_mesh_support(dev[0], secure=True)
+
+    dev[0].request("SET sae_groups 25")
+    id = add_mesh_secure_net(dev[0])
+    dev[0].mesh_group_add(id)
+
+    dev[1].request("SET sae_groups 123 122 121")
+    id = add_mesh_secure_net(dev[1])
+    dev[1].mesh_group_add(id)
+
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+
+    ev = dev[0].wait_event(["new peer notification"], timeout=10)
+    if ev is None:
+        raise Exception("dev[0] did not see peer")
+    ev = dev[1].wait_event(["new peer notification"], timeout=10)
+    if ev is None:
+        raise Exception("dev[1] did not see peer")
+
+    ev = dev[0].wait_event(["MESH-PEER-CONNECTED"], timeout=0.1)
+    if ev is not None:
+        raise Exception("Unexpected connection(0)")
+
+    ev = dev[1].wait_event(["MESH-PEER-CONNECTED"], timeout=0.01)
+    if ev is not None:
+        raise Exception("Unexpected connection(1)")
+
+    # Additional coverage in mesh_rsn_sae_group() with non-zero
+    # wpa_s->mesh_rsn->sae_group_index.
+    dev[0].dump_monitor()
+    dev[1].dump_monitor()
+    id = add_mesh_secure_net(dev[2])
+    dev[2].mesh_group_add(id)
+    check_mesh_group_added(dev[2])
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[2])
+    ev = dev[1].wait_event(["new peer notification"], timeout=10)
+    if ev is None:
+        raise Exception("dev[1] did not see peer(2)")
+    dev[0].dump_monitor()
+    dev[1].dump_monitor()
+    dev[2].dump_monitor()
+
+    dev[0].request("SET sae_groups ")
+    dev[1].request("SET sae_groups ")
+
+def test_mesh_sae_failure(dev, apdev):
+    """Mesh and local SAE failures"""
+    check_mesh_support(dev[0], secure=True)
+
+    dev[0].request("SET sae_groups ")
+    dev[1].request("SET sae_groups ")
+
+    funcs = [ (1, "=mesh_rsn_auth_sae_sta", True),
+              (1, "mesh_rsn_build_sae_commit;mesh_rsn_auth_sae_sta", False),
+              (1, "auth_sae_init_committed;mesh_rsn_auth_sae_sta", True),
+              (1, "=mesh_rsn_protect_frame", True),
+              (2, "=mesh_rsn_protect_frame", True),
+              (1, "aes_siv_encrypt;mesh_rsn_protect_frame", True),
+              (1, "=mesh_rsn_process_ampe", True),
+              (1, "aes_siv_decrypt;mesh_rsn_process_ampe", True) ]
+    for count, func, success in funcs:
+        id = add_mesh_secure_net(dev[0])
+        dev[0].mesh_group_add(id)
+
+        with alloc_fail(dev[1], count, func):
+            id = add_mesh_secure_net(dev[1])
+            dev[1].mesh_group_add(id)
+            check_mesh_group_added(dev[0])
+            check_mesh_group_added(dev[1])
+            if success:
+                # retry is expected to work
+                check_mesh_peer_connected(dev[0])
+                check_mesh_peer_connected(dev[1])
+            else:
+                wait_fail_trigger(dev[1], "GET_ALLOC_FAIL")
+        dev[0].mesh_group_remove()
+        dev[1].mesh_group_remove()
+        check_mesh_group_removed(dev[0])
+        check_mesh_group_removed(dev[1])
+
+def test_mesh_failure(dev, apdev):
+    """Mesh and local failures"""
+    check_mesh_support(dev[0])
+
+    funcs = [ (1, "ap_sta_add;mesh_mpm_add_peer", True),
+              (1, "wpabuf_alloc;mesh_mpm_send_plink_action", True) ]
+    for count, func, success in funcs:
+        add_open_mesh_network(dev[0])
+
+        with alloc_fail(dev[1], count, func):
+            add_open_mesh_network(dev[1])
+            check_mesh_group_added(dev[0])
+            check_mesh_group_added(dev[1])
+            if success:
+                # retry is expected to work
+                check_mesh_peer_connected(dev[0])
+                check_mesh_peer_connected(dev[1])
+            else:
+                wait_fail_trigger(dev[1], "GET_ALLOC_FAIL")
+        dev[0].mesh_group_remove()
+        dev[1].mesh_group_remove()
+        check_mesh_group_removed(dev[0])
+        check_mesh_group_removed(dev[1])
+
+    funcs = [ (1, "mesh_mpm_init_link", True) ]
+    for count, func, success in funcs:
+        add_open_mesh_network(dev[0])
+
+        with fail_test(dev[1], count, func):
+            add_open_mesh_network(dev[1])
+            check_mesh_group_added(dev[0])
+            check_mesh_group_added(dev[1])
+            if success:
+                # retry is expected to work
+                check_mesh_peer_connected(dev[0])
+                check_mesh_peer_connected(dev[1])
+            else:
+                wait_fail_trigger(dev[1], "GET_FAIL")
+        dev[0].mesh_group_remove()
+        dev[1].mesh_group_remove()
+        check_mesh_group_removed(dev[0])
+        check_mesh_group_removed(dev[1])
+
+def test_mesh_invalid_frequency(dev, apdev):
+    """Mesh and invalid frequency configuration"""
+    check_mesh_support(dev[0])
+    add_open_mesh_network(dev[0], freq=None)
+    ev = dev[0].wait_event(["MESH-GROUP-STARTED",
+                            "Could not join mesh"])
+    if ev is None or "Could not join mesh" not in ev:
+        raise Exception("Mesh join failure not reported")
+    dev[0].request("REMOVE_NETWORK all")
+
+    add_open_mesh_network(dev[0], freq="2413")
+    ev = dev[0].wait_event(["MESH-GROUP-STARTED",
+                            "Could not join mesh"])
+    if ev is None or "Could not join mesh" not in ev:
+        raise Exception("Mesh join failure not reported")
+
+def test_mesh_default_beacon_int(dev, apdev):
+    """Mesh and default beacon interval"""
+    check_mesh_support(dev[0])
+    try:
+        dev[0].request("SET beacon_int 200")
+        add_open_mesh_network(dev[0])
+        check_mesh_group_added(dev[0])
+    finally:
+        dev[0].request("SET beacon_int 0")
+
+def test_mesh_scan_parse_error(dev, apdev):
+    """Mesh scan element parse error"""
+    check_mesh_support(dev[0])
+    params = { "ssid": "open",
+               "beacon_int": "2000" }
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+    hapd.set('vendor_elements', 'dd0201')
+    for i in range(10):
+        dev[0].scan(freq=2412)
+        if bssid in dev[0].request("SCAN_RESULTS"):
+            break
+    # This will fail in IE parsing due to the truncated IE in the Probe
+    # Response frame.
+    bss = dev[0].request("BSS " + bssid)
+
+def test_mesh_missing_mic(dev, apdev):
+    """Secure mesh network and missing MIC"""
+    check_mesh_support(dev[0], secure=True)
+
+    dev[0].request("SET ext_mgmt_frame_handling 1")
+    dev[0].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[0])
+    dev[0].mesh_group_add(id)
+
+    dev[1].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[1])
+    dev[1].mesh_group_add(id)
+
+    # Check for mesh joined
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+
+    count = 0
+    remove_mic = True
+    while True:
+        count += 1
+        if count > 15:
+            raise Exception("Did not see Action frames")
+        rx_msg = dev[0].mgmt_rx()
+        if rx_msg is None:
+            ev = dev[1].wait_event(["MESH-PEER-CONNECTED"], timeout=0.01)
+            if ev:
+                break
+            raise Exception("MGMT-RX timeout")
+        if rx_msg['subtype'] == 13:
+            payload = rx_msg['payload']
+            frame = rx_msg['frame']
+            (categ, action) = struct.unpack('BB', payload[0:2])
+            if categ == 15 and action == 1 and remove_mic:
+                # Mesh Peering Open
+                pos = frame.find('\x8c\x10')
+                if not pos:
+                    raise Exception("Could not find MIC element")
+                logger.info("Found MIC at %d" % pos)
+                # Remove MIC
+                rx_msg['frame'] = frame[0:pos]
+                remove_mic = False
+        if "OK" not in dev[0].request("MGMT_RX_PROCESS freq={} datarate={} ssi_signal={} frame={}".format(rx_msg['freq'], rx_msg['datarate'], rx_msg['ssi_signal'], rx_msg['frame'].encode('hex'))):
+            raise Exception("MGMT_RX_PROCESS failed")
+        ev = dev[1].wait_event(["MESH-PEER-CONNECTED"], timeout=0.01)
+        if ev:
+            break
+
+def test_mesh_pmkid_mismatch(dev, apdev):
+    """Secure mesh network and PMKID mismatch"""
+    check_mesh_support(dev[0], secure=True)
+    addr0 = dev[0].own_addr()
+    addr1 = dev[1].own_addr()
+    dev[0].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[0])
+    dev[0].set_network(id, "no_auto_peer", "1")
+    dev[0].mesh_group_add(id)
+
+    dev[1].request("SET sae_groups ")
+    id = add_mesh_secure_net(dev[1])
+    dev[1].set_network(id, "no_auto_peer", "1")
+    dev[1].mesh_group_add(id)
+
+    # Check for mesh joined
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+
+    # Check for peer connected
+    ev = dev[0].wait_event(["will not initiate new peer link"], timeout=10)
+    if ev is None:
+        raise Exception("Missing no-initiate message")
+    if "OK" not in dev[0].request("MESH_PEER_ADD " + addr1):
+        raise Exception("MESH_PEER_ADD failed")
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[1])
+
+    if "OK" not in dev[0].request("MESH_PEER_REMOVE " + addr1):
+        raise Exception("Failed to remove peer")
+
+    ev = dev[0].wait_event(["will not initiate new peer link"], timeout=10)
+    if ev is None:
+        raise Exception("Missing no-initiate message (2)")
+    dev[0].dump_monitor()
+    dev[1].dump_monitor()
+    dev[0].request("SET ext_mgmt_frame_handling 1")
+    if "OK" not in dev[0].request("MESH_PEER_ADD " + addr1):
+        raise Exception("MESH_PEER_ADD failed (2)")
+
+    count = 0
+    break_pmkid = True
+    while True:
+        count += 1
+        if count > 50:
+            raise Exception("Did not see Action frames")
+        rx_msg = dev[0].mgmt_rx()
+        if rx_msg is None:
+            ev = dev[1].wait_event(["MESH-PEER-CONNECTED"], timeout=0.1)
+            if ev:
+                break
+            raise Exception("MGMT-RX timeout")
+        if rx_msg['subtype'] == 13:
+            payload = rx_msg['payload']
+            frame = rx_msg['frame']
+            (categ, action) = struct.unpack('BB', payload[0:2])
+            if categ == 15 and action == 1 and break_pmkid:
+                # Mesh Peering Open
+                pos = frame.find('\x75\x14')
+                if not pos:
+                    raise Exception("Could not find Mesh Peering Management element")
+                logger.info("Found Mesh Peering Management element at %d" % pos)
+                # Break PMKID to hit "Mesh RSN: Invalid PMKID (Chosen PMK did
+                # not match calculated PMKID)"
+                rx_msg['frame'] = frame[0:pos + 6] + '\x00\x00\x00\x00' + frame[pos + 10:]
+                break_pmkid = False
+        if "OK" not in dev[0].request("MGMT_RX_PROCESS freq={} datarate={} ssi_signal={} frame={}".format(rx_msg['freq'], rx_msg['datarate'], rx_msg['ssi_signal'], rx_msg['frame'].encode('hex'))):
+            raise Exception("MGMT_RX_PROCESS failed")
+        ev = dev[1].wait_event(["MESH-PEER-CONNECTED"], timeout=0.01)
+        if ev:
+            break
+
+def test_mesh_peering_proto(dev, apdev):
+    """Mesh peering management protocol testing"""
+    check_mesh_support(dev[0])
+
+    dev[0].request("SET ext_mgmt_frame_handling 1")
+    add_open_mesh_network(dev[0], beacon_int=160)
+    add_open_mesh_network(dev[1], beacon_int=160)
+
+    count = 0
+    test = 1
+    while True:
+        count += 1
+        if count > 50:
+            raise Exception("Did not see Action frames")
+        rx_msg = dev[0].mgmt_rx()
+        if rx_msg is None:
+            ev = dev[1].wait_event(["MESH-PEER-CONNECTED"], timeout=0.01)
+            if ev:
+                break
+            raise Exception("MGMT-RX timeout")
+        if rx_msg['subtype'] == 13:
+            payload = rx_msg['payload']
+            frame = rx_msg['frame']
+            (categ, action) = struct.unpack('BB', payload[0:2])
+            if categ == 15 and action == 1 and test == 1:
+                # Mesh Peering Open
+                pos = frame.find('\x75\x04')
+                if not pos:
+                    raise Exception("Could not find Mesh Peering Management element")
+                logger.info("Found Mesh Peering Management element at %d" % pos)
+                # Remove the element to hit
+                # "MPM: No Mesh Peering Management element"
+                rx_msg['frame'] = frame[0:pos]
+                test += 1
+            elif categ == 15 and action == 1 and test == 2:
+                # Mesh Peering Open
+                pos = frame.find('\x72\x0e')
+                if not pos:
+                    raise Exception("Could not find Mesh ID element")
+                logger.info("Found Mesh ID element at %d" % pos)
+                # Remove the element to hit
+                # "MPM: No Mesh ID or Mesh Configuration element"
+                rx_msg['frame'] = frame[0:pos] + frame[pos + 16:]
+                test += 1
+            elif categ == 15 and action == 1 and test == 3:
+                # Mesh Peering Open
+                pos = frame.find('\x72\x0e')
+                if not pos:
+                    raise Exception("Could not find Mesh ID element")
+                logger.info("Found Mesh ID element at %d" % pos)
+                # Replace Mesh ID to hit "MPM: Mesh ID or Mesh Configuration
+                # element do not match local MBSS"
+                rx_msg['frame'] = frame[0:pos] + '\x72\x0etest-test-test' + frame[pos + 16:]
+                test += 1
+            elif categ == 15 and action == 1 and test == 4:
+                # Mesh Peering Open
+                # Remove IEs to hit
+                # "MPM: Ignore too short action frame 1 ie_len 0"
+                rx_msg['frame'] = frame[0:26]
+                test += 1
+            elif categ == 15 and action == 1 and test == 5:
+                # Mesh Peering Open
+                # Truncate IEs to hit
+                # "MPM: Failed to parse PLINK IEs"
+                rx_msg['frame'] = frame[0:30]
+                test += 1
+            elif categ == 15 and action == 1 and test == 6:
+                # Mesh Peering Open
+                pos = frame.find('\x75\x04')
+                if not pos:
+                    raise Exception("Could not find Mesh Peering Management element")
+                logger.info("Found Mesh Peering Management element at %d" % pos)
+                # Truncate the element to hit
+                # "MPM: Invalid peer mgmt ie" and
+                # "MPM: Mesh parsing rejected frame"
+                rx_msg['frame'] = frame[0:pos] + '\x75\x00\x00\x00' + frame[pos + 6:]
+                test += 1
+        if "OK" not in dev[0].request("MGMT_RX_PROCESS freq={} datarate={} ssi_signal={} frame={}".format(rx_msg['freq'], rx_msg['datarate'], rx_msg['ssi_signal'], rx_msg['frame'].encode('hex'))):
+            raise Exception("MGMT_RX_PROCESS failed")
+        ev = dev[1].wait_event(["MESH-PEER-CONNECTED"], timeout=0.01)
+        if ev:
+            break
+
+    if test != 7:
+        raise Exception("Not all test frames completed")
+
+def test_mesh_mpm_init_proto(dev, apdev):
+    """Mesh peering management protocol testing for peer addition"""
+    check_mesh_support(dev[0])
+    add_open_mesh_network(dev[0])
+    check_mesh_group_added(dev[0])
+    dev[0].dump_monitor()
+
+    dev[0].request("SET ext_mgmt_frame_handling 1")
+
+    addr = "020000000100"
+    hdr = "d000ac00020000000000" + addr + addr + "1000"
+    fixed = "0f010000"
+    supp_rates = "010802040b168c129824"
+    ext_supp_rates = "3204b048606c"
+    mesh_id = "720e777061732d6d6573682d6f70656e"
+    mesh_conf = "710701010001000009"
+    mpm = "75040000079d"
+    ht_capab = "2d1a7c001bffff000000000000000000000100000000000000000000"
+    ht_oper = "3d160b000000000000000000000000000000000000000000"
+
+    dev[0].request("NOTE no supported rates")
+    frame = hdr + fixed + ext_supp_rates + mesh_id + mesh_conf + mpm + ht_capab + ht_oper
+    if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=%s" % frame):
+        raise Exception("MGMT_RX_PROCESS failed")
+
+    dev[0].request("NOTE Invalid supported rates element length 33+0")
+    long_supp_rates = "012100112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00"
+    frame = hdr + fixed + long_supp_rates + mesh_id + mesh_conf + mpm + ht_capab + ht_oper
+    if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=%s" % frame):
+        raise Exception("MGMT_RX_PROCESS failed")
+
+    dev[0].request("NOTE Too short mesh config")
+    short_mesh_conf = "710401010001"
+    frame = hdr + fixed + supp_rates + mesh_id + short_mesh_conf + mpm + ht_capab + ht_oper
+    if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=%s" % frame):
+        raise Exception("MGMT_RX_PROCESS failed")
+
+    dev[0].request("NOTE Add STA failure")
+    frame = hdr + fixed + supp_rates + ext_supp_rates + mesh_id + mesh_conf + mpm + ht_capab + ht_oper
+    with fail_test(dev[0], 1, "wpa_driver_nl80211_sta_add"):
+        if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=%s" % frame):
+            raise Exception("MGMT_RX_PROCESS failed")
+
+    dev[0].request("NOTE Send Action failure")
+    with fail_test(dev[0], 1, "driver_nl80211_send_action"):
+        if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=%s" % frame):
+            raise Exception("MGMT_RX_PROCESS failed")
+
+    dev[0].request("NOTE Set STA failure")
+    addr = "020000000101"
+    hdr = "d000ac00020000000000" + addr + addr + "1000"
+    frame = hdr + fixed + supp_rates + ext_supp_rates + mesh_id + mesh_conf + mpm + ht_capab + ht_oper
+    with fail_test(dev[0], 2, "wpa_driver_nl80211_sta_add"):
+        if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=%s" % frame):
+            raise Exception("MGMT_RX_PROCESS failed")
+
+    dev[0].request("NOTE ap_sta_add OOM")
+    addr = "020000000102"
+    hdr = "d000ac00020000000000" + addr + addr + "1000"
+    frame = hdr + fixed + supp_rates + ext_supp_rates + mesh_id + mesh_conf + mpm + ht_capab + ht_oper
+    with alloc_fail(dev[0], 1, "ap_sta_add"):
+        if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=%s" % frame):
+            raise Exception("MGMT_RX_PROCESS failed")
+
+    dev[0].request("NOTE hostapd_get_aid() failure")
+    addr = "020000000103"
+    hdr = "d000ac00020000000000" + addr + addr + "1000"
+    frame = hdr + fixed + supp_rates + ext_supp_rates + mesh_id + mesh_conf + mpm + ht_capab + ht_oper
+    with fail_test(dev[0], 1, "hostapd_get_aid"):
+        if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=%s" % frame):
+            raise Exception("MGMT_RX_PROCESS failed")
+
+    if "OK" not in dev[0].request("MESH_PEER_REMOVE 02:00:00:00:01:00"):
+        raise Exception("Failed to remove peer")
+    if "FAIL" not in dev[0].request("MESH_PEER_REMOVE 02:00:00:00:01:02"):
+        raise Exception("Unexpected MESH_PEER_REMOVE success")
+    if "FAIL" not in dev[1].request("MESH_PEER_REMOVE 02:00:00:00:01:02"):
+        raise Exception("Unexpected MESH_PEER_REMOVE success(2)")
+    if "FAIL" not in dev[1].request("MESH_PEER_ADD 02:00:00:00:01:02"):
+        raise Exception("Unexpected MESH_PEER_ADD success")
+
+def test_mesh_holding(dev, apdev):
+    """Mesh MPM FSM and HOLDING state event OPN_ACPT"""
+    check_mesh_support(dev[0])
+    add_open_mesh_network(dev[0])
+    add_open_mesh_network(dev[1])
+    check_mesh_group_added(dev[0])
+    check_mesh_group_added(dev[1])
+    check_mesh_peer_connected(dev[0])
+    check_mesh_peer_connected(dev[1])
+
+    addr0 = dev[0].own_addr()
+    addr1 = dev[1].own_addr()
+
+    dev[0].request("SET ext_mgmt_frame_handling 1")
+    if "OK" not in dev[0].request("MESH_PEER_REMOVE " + addr1):
+        raise Exception("Failed to remove peer")
+
+    rx_msg = dev[0].mgmt_rx()
+    if rx_msg is None:
+        raise Exception("MGMT-RX timeout")
+    if rx_msg['subtype'] != 13:
+        raise Exception("Unexpected management frame")
+    payload = rx_msg['payload']
+    (categ, action) = struct.unpack('BB', payload[0:2])
+    if categ != 0x0f or action != 0x03:
+        raise Exception("Did not see Mesh Peering Close")
+
+    peer_lid = payload[-6:-4].encode("hex")
+    my_lid = payload[-4:-2].encode("hex")
+
+    # Drop Mesh Peering Close and instead, process an unexpected Mesh Peering
+    # Open to trigger transmission of another Mesh Peering Close in the HOLDING
+    # state based on an OPN_ACPT event.
+
+    dst = addr0.replace(':', '')
+    src = addr1.replace(':', '')
+    hdr = "d000ac00" + dst + src + src + "1000"
+    fixed = "0f010000"
+    supp_rates = "010802040b168c129824"
+    ext_supp_rates = "3204b048606c"
+    mesh_id = "720e777061732d6d6573682d6f70656e"
+    mesh_conf = "710701010001000009"
+    mpm = "7504" + my_lid + peer_lid
+    ht_capab = "2d1a7c001bffff000000000000000000000100000000000000000000"
+    ht_oper = "3d160b000000000000000000000000000000000000000000"
+
+    frame = hdr + fixed + supp_rates + ext_supp_rates + mesh_id + mesh_conf + mpm + ht_capab + ht_oper
+    if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=%s" % frame):
+        raise Exception("MGMT_RX_PROCESS failed")
+    time.sleep(0.1)
+
+def test_mesh_cnf_rcvd_event_cls_acpt(dev, apdev):
+    """Mesh peering management protocol testing - CLS_ACPT event in CNF_RCVD"""
+    check_mesh_support(dev[0])
+    add_open_mesh_network(dev[0])
+    check_mesh_group_added(dev[0])
+    dev[0].dump_monitor()
+
+    dev[0].request("SET ext_mgmt_frame_handling 1")
+    add_open_mesh_network(dev[1])
+    check_mesh_group_added(dev[1])
+
+    addr0 = dev[0].own_addr()
+    addr1 = dev[1].own_addr()
+
+    rx_msg = dev[0].mgmt_rx()
+    # Drop Mesh Peering Open
+
+    rx_msg = dev[0].mgmt_rx()
+    # Allow Mesh Peering Confirm to go through
+    if "OK" not in dev[0].request("MGMT_RX_PROCESS freq={} datarate={} ssi_signal={} frame={}".format(rx_msg['freq'], rx_msg['datarate'], rx_msg['ssi_signal'], rx_msg['frame'].encode('hex'))):
+        raise Exception("MGMT_RX_PROCESS failed")
+
+    payload = rx_msg['payload']
+    peer_lid = payload[51:53].encode("hex")
+    my_lid = payload[53:55].encode("hex")
+
+    dst = addr0.replace(':', '')
+    src = addr1.replace(':', '')
+    hdr = "d000ac00" + dst + src + src + "1000"
+    fixed = "0f03"
+    mesh_id = "720e777061732d6d6573682d6f70656e"
+    mpm = "75080000" + peer_lid + my_lid + "3700"
+    frame = hdr + fixed + mesh_id + mpm
+
+    # Inject Mesh Peering Close to hit "state CNF_RCVD event CLS_ACPT" to
+    # HOLDING transition.
+    if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + frame):
+        raise Exception("MGMT_RX_PROCESS failed")
+
+def test_mesh_opn_snt_event_cls_acpt(dev, apdev):
+    """Mesh peering management protocol testing - CLS_ACPT event in OPN_SNT"""
+    check_mesh_support(dev[0])
+    add_open_mesh_network(dev[0])
+    check_mesh_group_added(dev[0])
+    dev[0].dump_monitor()
+
+    dev[0].request("SET ext_mgmt_frame_handling 1")
+    add_open_mesh_network(dev[1])
+    check_mesh_group_added(dev[1])
+
+    addr0 = dev[0].own_addr()
+    addr1 = dev[1].own_addr()
+
+    rx_msg = dev[0].mgmt_rx()
+    # Drop Mesh Peering Open
+
+    rx_msg = dev[0].mgmt_rx()
+    # Drop Mesh Peering Confirm
+
+    payload = rx_msg['payload']
+    peer_lid = "0000"
+    my_lid = payload[53:55].encode("hex")
+
+    dst = addr0.replace(':', '')
+    src = addr1.replace(':', '')
+    hdr = "d000ac00" + dst + src + src + "1000"
+    fixed = "0f03"
+    mesh_id = "720e777061732d6d6573682d6f70656e"
+    mpm = "75080000" + peer_lid + my_lid + "3700"
+    frame = hdr + fixed + mesh_id + mpm
+
+    # Inject Mesh Peering Close to hit "state OPN_SNTevent CLS_ACPT" to
+    # HOLDING transition.
+    if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + frame):
+        raise Exception("MGMT_RX_PROCESS failed")
index d2d5596..38ed9c5 100644 (file)
@@ -4,6 +4,7 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+from remotehost import remote_compatible
 import logging
 logger = logging.getLogger()
 import struct
@@ -20,7 +21,7 @@ def add_wmm_ap(apdev, acm_list):
     for ac in acm_list:
         params["wmm_ac_%s_acm" % (ac.lower())] = "1"
 
-    return hostapd.add_ap(apdev['ifname'], params)
+    return hostapd.add_ap(apdev, params)
 
 def test_tspec(dev, apdev):
     """Basic addts/delts tests"""
@@ -209,13 +210,14 @@ def test_tspec_protocol(dev, apdev):
 
     hapd.set("ext_mgmt_frame_handling", "0")
 
+@remote_compatible
 def test_tspec_not_enabled(dev, apdev):
     """addts failing if AP does not support WMM"""
     params = { "ssid": "wmm_no_ac",
                "hw_mode": "g",
                "channel": "11",
                "wmm_enabled" : "0" }
-    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+    hapd = hostapd.add_ap(apdev[0], params)
     dev[0].connect("wmm_no_ac", key_mgmt="NONE", scan_freq="2462")
     status = dev[0].request("WMM_AC_STATUS")
     if "Not associated to a WMM AP, WMM AC is Disabled" not in status:
@@ -246,6 +248,7 @@ def test_tspec_not_enabled(dev, apdev):
     msg['payload'] = struct.pack('BBBB', 17, 2, 0, 0)
     hapd.mgmt_tx(msg)
 
+@remote_compatible
 def test_tspec_ap_roam_open(dev, apdev):
     """Roam between two open APs while having tspecs"""
     hapd0 = add_wmm_ap(apdev[0], ["VO", "VI"])
@@ -264,6 +267,7 @@ def test_tspec_ap_roam_open(dev, apdev):
     dev[0].roam(apdev[0]['bssid'])
     hwsim_utils.test_connectivity(dev[0], hapd0)
 
+@remote_compatible
 def test_tspec_reassoc(dev, apdev):
     """Reassociation to same BSS while having tspecs"""
     hapd0 = add_wmm_ap(apdev[0], ["VO", "VI"])
index ee70cfd..5faed5e 100644 (file)
@@ -21,7 +21,7 @@ def run_tshark(filename, filter, display=None, wait=True):
     if wait:
         # wait a bit to make it more likely for wlantest sniffer to have
         # captured and written the results into a file that we can process here
-        time.sleep(1)
+        time.sleep(0.1)
 
     try:
         arg = [ "tshark", "-r", filename,
index daed84f..479923c 100644 (file)
@@ -5,6 +5,8 @@
 # See README for more details.
 
 import os
+import time
+import remotehost
 
 def get_ifnames():
     ifnames = []
@@ -50,6 +52,14 @@ class fail_test(object):
             if self._dev.request("GET_FAIL") != "0:%s" % self._funcs:
                 raise Exception("Test failure did not trigger")
 
+def wait_fail_trigger(dev, cmd, note="Failure not triggered"):
+    for i in range(0, 40):
+        if dev.request(cmd).startswith("0:"):
+            break
+        if i == 39:
+            raise Exception(note)
+        time.sleep(0.05)
+
 def require_under_vm():
     with open('/proc/1/cmdline', 'r') as f:
         cmd = f.read()
@@ -71,3 +81,24 @@ def skip_with_fips(dev, reason="Not supported in FIPS mode"):
     res = dev.get_capability("fips")
     if res and 'FIPS' in res:
         raise HwsimSkip(reason)
+
+def get_phy(ap, ifname=None):
+    phy = "phy3"
+    try:
+        hostname = ap['hostname']
+    except:
+        hostname = None
+    host = remotehost.Host(hostname)
+
+    if ifname == None:
+        ifname = ap['ifname']
+    status, buf = host.execute(["iw", "dev", ifname, "info"])
+    if status != 0:
+        raise Exception("iw " + ifname + " info failed")
+    lines = buf.split("\n")
+    for line in lines:
+        if "wiphy" in line:
+            words = line.split()
+            phy = "phy" + words[1]
+            break
+    return phy
index ffab4ee..3cbfe10 100755 (executable)
@@ -12,6 +12,8 @@ mount sysfs -t sysfs /sys
 # needed for tracing
 mount debugfs -t debugfs /sys/kernel/debug
 
+export PATH=/usr/sbin:$PATH
+
 # reboot on any sort of crash
 sysctl kernel.panic_on_oops=1
 sysctl kernel.panic=1
@@ -20,13 +22,14 @@ sysctl kernel.panic=1
 TESTDIR=$(sed 's/.*testdir=\([^ ]*\) .*/\1/' /proc/cmdline)
 TIMEWARP=$(sed 's/.*timewarp=\([^ ]*\) .*/\1/' /proc/cmdline)
 EPATH=$(sed 's/.*EPATH=\([^ ]*\) .*/\1/' /proc/cmdline)
-ARGS=$(sed 's/.*ARGS=//' /proc/cmdline)
+ARGS=$(sed 's/.*ARGS=\([^ ]*\)\( \|$\).*/\1/' /proc/cmdline)
 
 # create /dev entries we need
 mknod -m 660 /dev/ttyS0 c 4 64
 mknod -m 660 /dev/random c 1 8
 mknod -m 660 /dev/urandom c 1 9
 mknod -m 666 /dev/null c 1 3
+mknod -m 666 /dev/kmsg c 1 11
 test -f /sys/class/misc/rfkill/dev && \
        mknod -m 660 /dev/rfkill c $(cat /sys/class/misc/rfkill/dev | tr ':' ' ')
 ln -s /proc/self/fd/0 /dev/stdin
@@ -75,6 +78,10 @@ ip link set lo up
 mkdir /tmp/logs
 mount -t 9p -o trans=virtio,rw logshare /tmp/logs
 
+# allow access to any outside directory (e.g. /tmp) we also have
+mkdir /tmp/host
+mount --bind / /tmp/host
+
 if [ "$TIMEWARP" = "1" ] ; then
     (
         while sleep 1 ; do
@@ -104,7 +111,7 @@ else
        dbus-daemon --config-file=$TESTDIR/vm/dbus.conf --fork
 
        cd $TESTDIR
-       ./run-all.sh $ARGS </dev/ttyS0 >/dev/ttyS0 2>&1
+       ./run-all.sh $(cat /tmp/host$ARGS) </dev/ttyS0 >/dev/ttyS0 2>&1
        if test -d /sys/kernel/debug/gcov ; then
                cp -ar /sys/kernel/debug/gcov /tmp/logs/
                # these are broken as they're updated while being read ...
index 40ab5e3..40bbb76 100755 (executable)
@@ -50,6 +50,7 @@ long_tests = [ "ap_roam_open",
                "ap_vht160",
                "dfs_radar",
                "dfs",
+               "dfs_ht40_minus",
                "grpform_cred_ready_timeout",
                "hostapd_oom_wpa2_eap_connect",
                "wpas_ap_dfs",
@@ -352,6 +353,13 @@ def main():
                    help="run tests under valgrind")
     p.add_argument('params', nargs='*')
     args = p.parse_args()
+
+    dir = os.environ.get('HWSIM_TEST_LOG_DIR', '/tmp/hwsim-test-logs')
+    try:
+        os.makedirs(dir)
+    except:
+        pass
+
     num_servers = args.num_servers
     rerun_failures = not args.no_retry
     if args.debug:
@@ -363,7 +371,7 @@ def main():
         extra_args += [ '--long' ]
     if args.codecov:
         print "Code coverage - build separate binaries"
-        logdir = "/tmp/hwsim-test-logs/" + str(timestamp)
+        logdir = os.path.join(dir, str(timestamp))
         os.makedirs(logdir)
         subprocess.check_call([os.path.join(scriptsdir, 'build-codecov.sh'),
                                logdir])
@@ -390,12 +398,6 @@ def main():
     if len(tests) == 0:
         sys.exit("No test cases selected")
 
-    dir = '/tmp/hwsim-test-logs'
-    try:
-        os.mkdir(dir)
-    except:
-        pass
-
     if args.shuffle:
         from random import shuffle
         shuffle(tests)
@@ -457,7 +459,9 @@ def main():
         for i in range(0, num_servers):
             if len(vm[i]['failed']) == 0:
                 continue
-            print "./parallel-vm.py -1 1",
+            print "./vm-run.sh",
+            if args.long:
+                print "--long",
             skip = len(vm[i]['fail_seq'])
             skip -= min(skip, 30)
             for t in vm[i]['fail_seq']:
index b2fd078..f9e22d9 100755 (executable)
@@ -9,7 +9,11 @@ if [ -z "$NUM" ]; then
 fi
 shift
 
-LOGS=/tmp/hwsim-test-logs
+if [ -n "$HWSIM_TEST_LOG_DIR" ] ; then
+       LOGS="$HWSIM_TEST_LOG_DIR"
+else
+       LOGS=/tmp/hwsim-test-logs
+fi
 mkdir -p $LOGS
 DATE=$(date +%s)
 
index d52f7fc..76e31e7 100755 (executable)
@@ -1,5 +1,8 @@
 #!/bin/sh
 
+EPATH=$(sed 's/.*EPATH=\([^ ]*\) .*/\1/' /proc/cmdline)
+PATH=/tmp/bin:$EPATH:$PATH
+
 # assume this was a call for CRDA,
 # if not then it won't find a COUNTRY
 # environment variable and exit
index 9993043..c0ef5b0 100755 (executable)
@@ -6,7 +6,11 @@ if [ -z "$TESTDIR" ] ; then
        TESTDIR=$(pwd)/../
 fi
 
-LOGS=/tmp/hwsim-test-logs
+if [ -n "$HWSIM_TEST_LOG_DIR" ] ; then
+       LOGS="$HWSIM_TEST_LOG_DIR"
+else
+       LOGS=/tmp/hwsim-test-logs
+fi
 
 # increase the memory size if you want to run with valgrind, 512 MB works
 MEMORY=192
@@ -101,7 +105,26 @@ fi
 
 echo "Starting test run in a virtual machine"
 
-kvm \
+KVM=kvm
+for kvmprog in kvm qemu-kvm; do
+    if $kvmprog --version &> /dev/null; then
+       KVM=$kvmprog
+       break
+    fi
+done
+
+argsfile=$(mktemp)
+if [ $? -ne 0 ] ; then
+       exit 2
+fi
+function finish {
+       rm -f $argsfile
+}
+trap finish EXIT
+
+echo "$RUN_TEST_ARGS" > $argsfile
+
+$KVM \
        -kernel $KERNEL -smp 4 \
        $KVMARGS -m $MEMORY -nographic \
        -fsdev local,security_model=none,id=fsdev-root,path=/$ROTAG \
@@ -109,7 +132,7 @@ kvm \
        -fsdev local,security_model=none,id=fsdev-logs,path="$LOGDIR",writeout=immediate \
        -device virtio-9p-pci,id=fs-logs,fsdev=fsdev-logs,mount_tag=logshare \
        -monitor null -serial stdio -serial file:$LOGDIR/console \
-       -append "mac80211_hwsim.support_p2p_device=0 mac80211_hwsim.channels=$CHANNELS mac80211_hwsim.radios=7 init=$CMD testdir=$TESTDIR timewarp=$TIMEWARP console=$KVMOUT root=/dev/root rootflags=trans=virtio,version=9p2000.u ro rootfstype=9p EPATH=$EPATH ARGS=$RUN_TEST_ARGS"
+       -append "mac80211_hwsim.support_p2p_device=0 mac80211_hwsim.channels=$CHANNELS mac80211_hwsim.radios=7 init=$CMD testdir=$TESTDIR timewarp=$TIMEWARP console=$KVMOUT root=/dev/root rootflags=trans=virtio,version=9p2000.u ro rootfstype=9p EPATH=$EPATH ARGS=$argsfile"
 
 if [ $CODECOV = "yes" ]; then
     echo "Preparing code coverage reports"
index 5f6b4ac..10bb45f 100644 (file)
@@ -4,7 +4,9 @@
 # This software may be distributed under the terms of the BSD license.
 # See README for more details.
 
+import re
 import os
+import posixpath
 import time
 import subprocess
 import logging
@@ -13,44 +15,133 @@ import wpaspy
 logger = logging.getLogger()
 
 class Wlantest:
+    remote_host = None
+    setup_params = None
+    exe_thread = None
+    exe_res = []
+    monitor_mod = None
+    setup_done = False
+
+    @classmethod
+    def stop_remote_wlantest(cls):
+        if cls.exe_thread is None:
+            # Local flow - no need for remote operations
+            return
+
+        cls.remote_host.execute(["killall", "-9", "wlantest"])
+        cls.remote_host.wait_execute_complete(cls.exe_thread, 5)
+        cls.exe_thread = None
+        cls.exe_res = []
+
+    @classmethod
+    def reset_remote_wlantest(cls):
+        cls.stop_remote_wlantest()
+        cls.remote_host = None
+        cls.setup_params = None
+        cls.exe_thread = None
+        cls.exe_res = []
+        cls.monitor_mod = None
+        cls.setup_done = False
+
+    @classmethod
+    def start_remote_wlantest(cls):
+        if cls.remote_host is None:
+            # Local flow - no need for remote operations
+            return
+        if cls.exe_thread is not None:
+            raise Exception("Cannot start wlantest twice")
+
+        log_dir = cls.setup_params['log_dir']
+        ifaces = re.split('; | |, ', cls.remote_host.ifname)
+        ifname = ifaces[0]
+        exe = cls.setup_params["wlantest"]
+        tc_name = cls.setup_params["tc_name"]
+        base_log_name = tc_name + "_wlantest_" + \
+                        cls.remote_host.name + "_" + ifname
+        log_file = posixpath.join(log_dir, base_log_name + ".log")
+        pcap_file = posixpath.join(log_dir, base_log_name + ".pcapng")
+        cmd = "{} -i {} -n {} -c -dtN -L {}".format(exe, ifname,
+                                                    pcap_file, log_file)
+        cls.remote_host.add_log(log_file)
+        cls.remote_host.add_log(pcap_file)
+        cls.exe_thread = cls.remote_host.execute_run(cmd.split(), cls.exe_res)
+        # Give wlantest a chance to start working
+        time.sleep(1)
+
+    @classmethod
+    def register_remote_wlantest(cls, host, setup_params, monitor_mod):
+        if cls.remote_host is not None:
+            raise Exception("Cannot register remote wlantest twice")
+        cls.remote_host = host
+        cls.setup_params = setup_params
+        cls.monitor_mod = monitor_mod
+        status, buf = host.execute(["which", setup_params['wlantest']])
+        if status != 0:
+            raise Exception(host.name + " - wlantest: " + buf)
+        status, buf = host.execute(["which", setup_params['wlantest_cli']])
+        if status != 0:
+            raise Exception(host.name + " - wlantest_cli: " + buf)
+
+    @classmethod
+    def chan_from_wpa(cls, wpa, is_p2p=False):
+        if cls.monitor_mod is None:
+            return
+        m = cls.monitor_mod
+        return m.setup(cls.remote_host, [m.get_monitor_params(wpa, is_p2p)])
+
+    @classmethod
+    def setup(cls, wpa, is_p2p=False):
+        cls.chan_from_wpa(wpa, is_p2p)
+        cls.start_remote_wlantest()
+        cls.setup_done = True
+
     def __init__(self):
+        if not self.setup_done:
+            raise Exception("Cannot create Wlantest instance before setup()")
         if os.path.isfile('../../wlantest/wlantest_cli'):
             self.wlantest_cli = '../../wlantest/wlantest_cli'
         else:
             self.wlantest_cli = 'wlantest_cli'
 
+    def cli_cmd(self, params):
+        if self.remote_host is not None:
+            exe = self.setup_params["wlantest_cli"]
+            ret = self.remote_host.execute([exe] + params)
+            if ret[0] != 0:
+                raise Exception("wlantest_cli failed")
+            return ret[1]
+        else:
+            return subprocess.check_output([self.wlantest_cli] + params)
+
     def flush(self):
-        res = subprocess.check_output([self.wlantest_cli, "flush"])
+        res = self.cli_cmd(["flush"])
         if "FAIL" in res:
             raise Exception("wlantest_cli flush failed")
 
     def relog(self):
-        res = subprocess.check_output([self.wlantest_cli, "relog"])
+        res = self.cli_cmd(["relog"])
         if "FAIL" in res:
             raise Exception("wlantest_cli relog failed")
 
     def add_passphrase(self, passphrase):
-        res = subprocess.check_output([self.wlantest_cli, "add_passphrase",
-                                       passphrase])
+        res = self.cli_cmd(["add_passphrase", passphrase])
         if "FAIL" in res:
             raise Exception("wlantest_cli add_passphrase failed")
 
     def add_wepkey(self, key):
-        res = subprocess.check_output([self.wlantest_cli, "add_wepkey", key])
+        res = self.cli_cmd(["add_wepkey", key])
         if "FAIL" in res:
             raise Exception("wlantest_cli add_key failed")
 
     def info_bss(self, field, bssid):
-        res = subprocess.check_output([self.wlantest_cli, "info_bss",
-                                       field, bssid])
+        res = self.cli_cmd(["info_bss", field, bssid])
         if "FAIL" in res:
             raise Exception("Could not get BSS info from wlantest for " + bssid)
         return res
 
     def get_bss_counter(self, field, bssid):
         try:
-            res = subprocess.check_output([self.wlantest_cli, "get_bss_counter",
-                                           field, bssid]);
+            res = self.cli_cmd(["get_bss_counter", field, bssid])
         except Exception, e:
             return 0
         if "FAIL" in res:
@@ -58,36 +149,30 @@ class Wlantest:
         return int(res)
 
     def clear_bss_counters(self, bssid):
-        subprocess.call([self.wlantest_cli, "clear_bss_counters", bssid],
-                        stdout=open('/dev/null', 'w'));
+        self.cli_cmd(["clear_bss_counters", bssid])
 
     def info_sta(self, field, bssid, addr):
-        res = subprocess.check_output([self.wlantest_cli, "info_sta",
-                                       field, bssid, addr])
+        res = self.cli_cmd(["info_sta", field, bssid, addr])
         if "FAIL" in res:
             raise Exception("Could not get STA info from wlantest for " + addr)
         return res
 
     def get_sta_counter(self, field, bssid, addr):
-        res = subprocess.check_output([self.wlantest_cli, "get_sta_counter",
-                                       field, bssid, addr]);
+        res = self.cli_cmd(["get_sta_counter", field, bssid, addr])
         if "FAIL" in res:
             raise Exception("wlantest_cli command failed")
         return int(res)
 
     def clear_sta_counters(self, bssid, addr):
-        res = subprocess.check_output([self.wlantest_cli, "clear_sta_counters",
-                                       bssid, addr]);
+        res = self.cli_cmd(["clear_sta_counters", bssid, addr])
         if "FAIL" in res:
             raise Exception("wlantest_cli command failed")
 
     def tdls_clear(self, bssid, addr1, addr2):
-        res = subprocess.check_output([self.wlantest_cli, "clear_tdls_counters",
-                                       bssid, addr1, addr2]);
+        self.cli_cmd(["clear_tdls_counters", bssid, addr1, addr2])
 
     def get_tdls_counter(self, field, bssid, addr1, addr2):
-        res = subprocess.check_output([self.wlantest_cli, "get_tdls_counter",
-                                       field, bssid, addr1, addr2]);
+        res = self.cli_cmd(["get_tdls_counter", field, bssid, addr1, addr2])
         if "FAIL" in res:
             raise Exception("wlantest_cli command failed")
         return int(res)
@@ -139,15 +224,13 @@ class Wlantest:
             raise Exception("Unexpected STA key_mgmt")
 
     def get_tx_tid(self, bssid, addr, tid):
-        res = subprocess.check_output([self.wlantest_cli, "get_tx_tid",
-                                       bssid, addr, str(tid)]);
+        res = self.cli_cmd(["get_tx_tid", bssid, addr, str(tid)])
         if "FAIL" in res:
             raise Exception("wlantest_cli command failed")
         return int(res)
 
     def get_rx_tid(self, bssid, addr, tid):
-        res = subprocess.check_output([self.wlantest_cli, "get_rx_tid",
-                                       bssid, addr, str(tid)]);
+        res = self.cli_cmd(["get_rx_tid", bssid, addr, str(tid)])
         if "FAIL" in res:
             raise Exception("wlantest_cli command failed")
         return int(res)
index 8e79c8b..ba2552c 100644 (file)
@@ -10,29 +10,66 @@ import logging
 import binascii
 import re
 import struct
-import subprocess
 import wpaspy
+import remotehost
+import subprocess
 
 logger = logging.getLogger()
 wpas_ctrl = '/var/run/wpa_supplicant'
 
 class WpaSupplicant:
-    def __init__(self, ifname=None, global_iface=None):
+    def __init__(self, ifname=None, global_iface=None, hostname=None,
+                 port=9877, global_port=9878):
+        self.hostname = hostname
         self.group_ifname = None
         self.gctrl_mon = None
+        self.host = remotehost.Host(hostname, ifname)
+        self._group_dbg = None
         if ifname:
-            self.set_ifname(ifname)
+            self.set_ifname(ifname, hostname, port)
+            res = self.get_driver_status()
+            if 'capa.flags' in res and int(res['capa.flags'], 0) & 0x20000000:
+                self.p2p_dev_ifname = 'p2p-dev-' + self.ifname
+            else:
+                self.p2p_dev_ifname = ifname
         else:
             self.ifname = None
 
         self.global_iface = global_iface
         if global_iface:
-            self.global_ctrl = wpaspy.Ctrl(global_iface)
-            self.global_mon = wpaspy.Ctrl(global_iface)
+            if hostname != None:
+                self.global_ctrl = wpaspy.Ctrl(hostname, global_port)
+                self.global_mon = wpaspy.Ctrl(hostname, global_port)
+                self.global_dbg = hostname + "/" + str(global_port) + "/"
+            else:
+                self.global_ctrl = wpaspy.Ctrl(global_iface)
+                self.global_mon = wpaspy.Ctrl(global_iface)
+                self.global_dbg = ""
             self.global_mon.attach()
         else:
             self.global_mon = None
 
+    def cmd_execute(self, cmd_array, shell=False):
+        if self.hostname is None:
+            if shell:
+                cmd = ' '.join(cmd_array)
+            else:
+                cmd = cmd_array
+            proc = subprocess.Popen(cmd, stderr=subprocess.STDOUT,
+                                    stdout=subprocess.PIPE, shell=shell)
+            out = proc.communicate()[0]
+            ret = proc.returncode
+            return ret, out
+        else:
+            return self.host.execute(cmd_array)
+
+    def terminate(self):
+        if self.global_mon:
+            self.global_mon.detach()
+            self.global_mon = None
+            self.global_ctrl.terminate()
+            self.global_ctrl = None
+
     def close_ctrl(self):
         if self.global_mon:
             self.global_mon.detach()
@@ -40,10 +77,17 @@ class WpaSupplicant:
             self.global_ctrl = None
         self.remove_ifname()
 
-    def set_ifname(self, ifname):
+    def set_ifname(self, ifname, hostname=None, port=9877):
         self.ifname = ifname
-        self.ctrl = wpaspy.Ctrl(os.path.join(wpas_ctrl, ifname))
-        self.mon = wpaspy.Ctrl(os.path.join(wpas_ctrl, ifname))
+        if hostname != None:
+            self.ctrl = wpaspy.Ctrl(hostname, port)
+            self.mon = wpaspy.Ctrl(hostname, port)
+            self.host = remotehost.Host(hostname, ifname)
+            self.dbg = hostname + "/" + ifname
+        else:
+            self.ctrl = wpaspy.Ctrl(os.path.join(wpas_ctrl, ifname))
+            self.mon = wpaspy.Ctrl(os.path.join(wpas_ctrl, ifname))
+            self.dbg = ifname
         self.mon.attach()
 
     def remove_ifname(self):
@@ -53,14 +97,33 @@ class WpaSupplicant:
             self.ctrl = None
             self.ifname = None
 
+    def get_ctrl_iface_port(self, ifname):
+        if self.hostname is None:
+            return None
+
+        res = self.global_request("INTERFACES ctrl")
+        lines = res.splitlines()
+        found = False
+        for line in lines:
+            words = line.split()
+            if words[0] == ifname:
+                found = True
+                break
+        if not found:
+            raise Exception("Could not find UDP port for " + ifname)
+        res = line.find("ctrl_iface=udp:")
+        if res == -1:
+            raise Exception("Wrong ctrl_interface format")
+        words = line.split(":")
+        return int(words[1])
+
     def interface_add(self, ifname, config="", driver="nl80211",
                       drv_params=None, br_ifname=None, create=False,
-                      set_ifname=True, all_params=False):
-        try:
-            groups = subprocess.check_output(["id"])
-            group = "admin" if "(admin)" in groups else "adm"
-        except Exception, e:
+                      set_ifname=True, all_params=False, if_type=None):
+        status, groups = self.host.execute(["id"])
+        if status != 0:
             group = "admin"
+        group = "admin" if "(admin)" in groups else "adm"
         cmd = "INTERFACE_ADD " + ifname + "\t" + config + "\t" + driver + "\tDIR=/var/run/wpa_supplicant GROUP=" + group
         if drv_params:
             cmd = cmd + '\t' + drv_params
@@ -74,6 +137,8 @@ class WpaSupplicant:
                 if not drv_params:
                     cmd += '\t'
             cmd += '\tcreate'
+            if if_type:
+                cmd += '\t' + if_type
         if all_params and not create:
             if not br_ifname:
                 cmd += '\t'
@@ -83,28 +148,50 @@ class WpaSupplicant:
         if "FAIL" in self.global_request(cmd):
             raise Exception("Failed to add a dynamic wpa_supplicant interface")
         if not create and set_ifname:
-            self.set_ifname(ifname)
+            port = self.get_ctrl_iface_port(ifname)
+            self.set_ifname(ifname, self.hostname, port)
+            res = self.get_driver_status()
+            if 'capa.flags' in res and int(res['capa.flags'], 0) & 0x20000000:
+                self.p2p_dev_ifname = 'p2p-dev-' + self.ifname
+            else:
+                self.p2p_dev_ifname = ifname
 
     def interface_remove(self, ifname):
         self.remove_ifname()
         self.global_request("INTERFACE_REMOVE " + ifname)
 
     def request(self, cmd, timeout=10):
-        logger.debug(self.ifname + ": CTRL: " + cmd)
+        logger.debug(self.dbg + ": CTRL: " + cmd)
         return self.ctrl.request(cmd, timeout=timeout)
 
     def global_request(self, cmd):
         if self.global_iface is None:
-            self.request(cmd)
+            return self.request(cmd)
         else:
             ifname = self.ifname or self.global_iface
-            logger.debug(ifname + ": CTRL(global): " + cmd)
+            logger.debug(self.global_dbg + ifname + ": CTRL(global): " + cmd)
             return self.global_ctrl.request(cmd)
 
+    @property
+    def group_dbg(self):
+        if self._group_dbg is not None:
+            return self._group_dbg
+        if self.group_ifname is None:
+            raise Exception("Cannot have group_dbg without group_ifname")
+        if self.hostname is None:
+            self._group_dbg = self.group_ifname
+        else:
+            self._group_dbg = self.hostname + "/" + self.group_ifname
+        return self._group_dbg
+
     def group_request(self, cmd):
         if self.group_ifname and self.group_ifname != self.ifname:
-            logger.debug(self.group_ifname + ": CTRL: " + cmd)
-            gctrl = wpaspy.Ctrl(os.path.join(wpas_ctrl, self.group_ifname))
+            if self.hostname is None:
+                gctrl = wpaspy.Ctrl(os.path.join(wpas_ctrl, self.group_ifname))
+            else:
+                port = self.get_ctrl_iface_port(self.group_ifname)
+                gctrl = wpaspy.Ctrl(self.hostname, port)
+            logger.debug(self.group_dbg + ": CTRL(group): " + cmd)
             return gctrl.request(cmd)
         return self.request(cmd)
 
@@ -120,13 +207,8 @@ class WpaSupplicant:
         if not "OK" in res:
             logger.info("FLUSH to " + self.ifname + " failed: " + res)
         self.global_request("REMOVE_NETWORK all")
-        self.global_request("SET p2p_add_cli_chan 0")
-        self.global_request("SET p2p_no_go_freq ")
-        self.global_request("SET p2p_pref_chan ")
         self.global_request("SET p2p_no_group_iface 1")
-        self.global_request("SET p2p_go_intent 7")
         self.global_request("P2P_FLUSH")
-        self.request("SET ignore_old_scan_res 0")
         if self.gctrl_mon:
             try:
                 self.gctrl_mon.detach()
@@ -151,18 +233,14 @@ class WpaSupplicant:
         if iter == 60:
             logger.error(self.ifname + ": Driver scan state did not clear")
             print "Trying to clear cfg80211/mac80211 scan state"
-            try:
-                cmd = ["ifconfig", self.ifname, "down"]
-                subprocess.call(cmd)
-            except subprocess.CalledProcessError, e:
-                logger.info("ifconfig failed: " + str(e.returncode))
-                logger.info(e.output)
-            try:
-                cmd = ["ifconfig", self.ifname, "up"]
-                subprocess.call(cmd)
-            except subprocess.CalledProcessError, e:
-                logger.info("ifconfig failed: " + str(e.returncode))
-                logger.info(e.output)
+            status, buf = self.host.execute(["ifconfig", self.ifname, "down"])
+            if status != 0:
+                logger.info("ifconfig failed: " + buf)
+                logger.info(status)
+            status, buf = self.host.execute(["ifconfig", self.ifname, "up"])
+            if status != 0:
+                logger.info("ifconfig failed: " + buf)
+                logger.info(status)
         if iter > 0:
             # The ongoing scan could have discovered BSSes or P2P peers
             logger.info("Run FLUSH again since scan was in progress")
@@ -202,6 +280,27 @@ class WpaSupplicant:
             raise Exception("SET_NETWORK failed")
         return None
 
+    def p2pdev_request(self, cmd):
+        return self.global_request("IFNAME=" + self.p2p_dev_ifname + " " + cmd)
+
+    def p2pdev_add_network(self):
+        id = self.p2pdev_request("ADD_NETWORK")
+        if "FAIL" in id:
+            raise Exception("p2pdev ADD_NETWORK failed")
+        return int(id)
+
+    def p2pdev_set_network(self, id, field, value):
+        res = self.p2pdev_request("SET_NETWORK " + str(id) + " " + field + " " + value)
+        if "FAIL" in res:
+            raise Exception("p2pdev SET_NETWORK failed")
+        return None
+
+    def p2pdev_set_network_quoted(self, id, field, value):
+        res = self.p2pdev_request("SET_NETWORK " + str(id) + " " + field + ' "' + value + '"')
+        if "FAIL" in res:
+            raise Exception("p2pdev SET_NETWORK failed")
+        return None
+
     def list_networks(self, p2p=False):
         if p2p:
             res = self.global_request("LIST_NETWORKS")
@@ -268,7 +367,7 @@ class WpaSupplicant:
         quoted = [ "realm", "username", "password", "domain", "imsi",
                    "excluded_ssid", "milenage", "ca_cert", "client_cert",
                    "private_key", "domain_suffix_match", "provisioning_sp",
-                   "roaming_partner", "phase1", "phase2" ]
+                   "roaming_partner", "phase1", "phase2", "private_key_passwd" ]
         for field in quoted:
             if field in params:
                 self.set_cred_quoted(id, field, params[field])
@@ -282,7 +381,7 @@ class WpaSupplicant:
             if field in params:
                 self.set_cred(id, field, params[field])
 
-        return id;
+        return id
 
     def select_network(self, id, freq=None):
         if freq:
@@ -306,7 +405,9 @@ class WpaSupplicant:
             raise Exception("MESH_GROUP_REMOVE failed")
         return None
 
-    def connect_network(self, id, timeout=10):
+    def connect_network(self, id, timeout=None):
+        if timeout is None:
+            timeout = 10 if self.hostname is None else 60
         self.dump_monitor()
         self.select_network(id)
         self.wait_connected(timeout=timeout)
@@ -382,8 +483,8 @@ class WpaSupplicant:
         return None
 
     def get_mcc(self):
-       mcc = int(self.get_driver_status_field('capa.num_multichan_concurrent'))
-       return 1 if mcc < 2 else mcc
+        mcc = int(self.get_driver_status_field('capa.num_multichan_concurrent'))
+        return 1 if mcc < 2 else mcc
 
     def get_mib(self):
         res = self.request("MIB")
@@ -413,6 +514,12 @@ class WpaSupplicant:
     def p2p_listen(self):
         return self.global_request("P2P_LISTEN")
 
+    def p2p_ext_listen(self, period, interval):
+        return self.global_request("P2P_EXT_LISTEN %d %d" % (period, interval))
+
+    def p2p_cancel_ext_listen(self):
+        return self.global_request("P2P_EXT_LISTEN")
+
     def p2p_find(self, social=False, progressive=False, dev_id=None,
                  dev_type=None, delay=None, freq=None):
         cmd = "P2P_FIND"
@@ -447,11 +554,12 @@ class WpaSupplicant:
             return True
         return "[PROBE_REQ_ONLY]" not in res
 
-    def discover_peer(self, peer, full=True, timeout=15, social=True, force_find=False):
+    def discover_peer(self, peer, full=True, timeout=15, social=True,
+                      force_find=False, freq=None):
         logger.info(self.ifname + ": Trying to discover peer " + peer)
         if not force_find and self.peer_known(peer, full):
             return True
-        self.p2p_find(social)
+        self.p2p_find(social, freq=freq)
         count = 0
         while count < timeout * 4:
             time.sleep(0.25)
@@ -500,7 +608,12 @@ class WpaSupplicant:
         res['ifname'] = s[2]
         self.group_ifname = s[2]
         try:
-            self.gctrl_mon = wpaspy.Ctrl(os.path.join(wpas_ctrl, self.group_ifname))
+            if self.hostname is None:
+                self.gctrl_mon = wpaspy.Ctrl(os.path.join(wpas_ctrl,
+                                                          self.group_ifname))
+            else:
+                port = self.get_ctrl_iface_port(self.group_ifname)
+                self.gctrl_mon = wpaspy.Ctrl(self.hostname, port)
             self.gctrl_mon.attach()
         except:
             logger.debug("Could not open monitor socket for group interface")
@@ -537,7 +650,9 @@ class WpaSupplicant:
 
         return res
 
-    def p2p_go_neg_auth(self, peer, pin, method, go_intent=None, persistent=False, freq=None):
+    def p2p_go_neg_auth(self, peer, pin, method, go_intent=None,
+                        persistent=False, freq=None, freq2=None,
+                        max_oper_chwidth=None, ht40=False, vht=False):
         if not self.discover_peer(peer):
             raise Exception("Peer " + peer + " not found")
         self.dump_monitor()
@@ -549,6 +664,14 @@ class WpaSupplicant:
             cmd = cmd + ' go_intent=' + str(go_intent)
         if freq:
             cmd = cmd + ' freq=' + str(freq)
+        if freq2:
+            cmd = cmd + ' freq2=' + str(freq2)
+        if max_oper_chwidth:
+            cmd = cmd + ' max_oper_chwidth=' + str(max_oper_chwidth)
+        if ht40:
+            cmd = cmd + ' ht40'
+        if vht:
+            cmd = cmd + ' vht'
         if persistent:
             cmd = cmd + " persistent"
         if "OK" in self.global_request(cmd):
@@ -558,14 +681,14 @@ class WpaSupplicant:
     def p2p_go_neg_auth_result(self, timeout=1, expect_failure=False):
         go_neg_res = None
         ev = self.wait_global_event(["P2P-GO-NEG-SUCCESS",
-                                     "P2P-GO-NEG-FAILURE"], timeout);
+                                     "P2P-GO-NEG-FAILURE"], timeout)
         if ev is None:
             if expect_failure:
                 return None
             raise Exception("Group formation timed out")
         if "P2P-GO-NEG-SUCCESS" in ev:
             go_neg_res = ev
-            ev = self.wait_global_event(["P2P-GROUP-STARTED"], timeout);
+            ev = self.wait_global_event(["P2P-GROUP-STARTED"], timeout)
             if ev is None:
                 if expect_failure:
                     return None
@@ -573,7 +696,11 @@ class WpaSupplicant:
         self.dump_monitor()
         return self.group_form_result(ev, expect_failure, go_neg_res)
 
-    def p2p_go_neg_init(self, peer, pin, method, timeout=0, go_intent=None, expect_failure=False, persistent=False, persistent_id=None, freq=None, provdisc=False, wait_group=True):
+    def p2p_go_neg_init(self, peer, pin, method, timeout=0, go_intent=None,
+                        expect_failure=False, persistent=False,
+                        persistent_id=None, freq=None, provdisc=False,
+                        wait_group=True, freq2=None, max_oper_chwidth=None,
+                        ht40=False, vht=False):
         if not self.discover_peer(peer):
             raise Exception("Peer " + peer + " not found")
         self.dump_monitor()
@@ -581,10 +708,18 @@ class WpaSupplicant:
             cmd = "P2P_CONNECT " + peer + " " + pin + " " + method
         else:
             cmd = "P2P_CONNECT " + peer + " " + method
-        if go_intent:
+        if go_intent is not None:
             cmd = cmd + ' go_intent=' + str(go_intent)
         if freq:
             cmd = cmd + ' freq=' + str(freq)
+        if freq2:
+            cmd = cmd + ' freq2=' + str(freq2)
+        if max_oper_chwidth:
+            cmd = cmd + ' max_oper_chwidth=' + str(max_oper_chwidth)
+        if ht40:
+            cmd = cmd + ' ht40'
+        if vht:
+            cmd = cmd + ' vht'
         if persistent:
             cmd = cmd + " persistent"
         elif persistent_id:
@@ -593,7 +728,6 @@ class WpaSupplicant:
             cmd = cmd + " provdisc"
         if "OK" in self.global_request(cmd):
             if timeout == 0:
-                self.dump_monitor()
                 return None
             go_neg_res = None
             ev = self.wait_global_event(["P2P-GO-NEG-SUCCESS",
@@ -620,7 +754,7 @@ class WpaSupplicant:
         while True:
             while self.mon.pending():
                 ev = self.mon.recv()
-                logger.debug(self.ifname + ": " + ev)
+                logger.debug(self.dbg + ": " + ev)
                 for event in events:
                     if event in ev:
                         return ev
@@ -640,7 +774,7 @@ class WpaSupplicant:
             while True:
                 while self.global_mon.pending():
                     ev = self.global_mon.recv()
-                    logger.debug(self.ifname + "(global): " + ev)
+                    logger.debug(self.global_dbg + self.ifname + "(global): " + ev)
                     for event in events:
                         if event in ev:
                             return ev
@@ -660,7 +794,7 @@ class WpaSupplicant:
             while True:
                 while self.gctrl_mon.pending():
                     ev = self.gctrl_mon.recv()
-                    logger.debug(self.group_ifname + ": " + ev)
+                    logger.debug(self.group_dbg + "(group): " + ev)
                     for event in events:
                         if event in ev:
                             return ev
@@ -681,19 +815,25 @@ class WpaSupplicant:
             except:
                 pass
             self.gctrl_mon = None
-        ev = self.wait_global_event(["P2P-GROUP-REMOVED"], timeout=3)
+        timeout = 3 if self.hostname is None else 10
+        ev = self.wait_global_event(["P2P-GROUP-REMOVED"], timeout=timeout)
         if ev is None:
             raise Exception("Group removal event timed out")
         if "reason=GO_ENDING_SESSION" not in ev:
             raise Exception("Unexpected group removal reason")
 
     def dump_monitor(self):
+        count_iface = 0
+        count_global = 0
         while self.mon.pending():
             ev = self.mon.recv()
-            logger.debug(self.ifname + ": " + ev)
+            logger.debug(self.dbg + ": " + ev)
+            count_iface += 1
         while self.global_mon and self.global_mon.pending():
             ev = self.global_mon.recv()
-            logger.debug(self.ifname + "(global): " + ev)
+            logger.debug(self.global_dbg + self.ifname + "(global): " + ev)
+            count_global += 1
+        return (count_iface, count_global)
 
     def remove_group(self, ifname=None):
         if self.gctrl_mon:
@@ -743,9 +883,10 @@ class WpaSupplicant:
     def p2p_connect_group(self, go_addr, pin, timeout=0, social=False,
                           freq=None):
         self.dump_monitor()
-        if not self.discover_peer(go_addr, social=social):
+        if not self.discover_peer(go_addr, social=social, freq=freq):
             if social or not self.discover_peer(go_addr, social=social):
                 raise Exception("GO " + go_addr + " not found")
+        self.p2p_stop_find()
         self.dump_monitor()
         cmd = "P2P_CONNECT " + go_addr + " " + pin + " join"
         if freq:
@@ -754,9 +895,13 @@ class WpaSupplicant:
             if timeout == 0:
                 self.dump_monitor()
                 return None
-            ev = self.wait_global_event(["P2P-GROUP-STARTED"], timeout)
+            ev = self.wait_global_event(["P2P-GROUP-STARTED",
+                                         "P2P-GROUP-FORMATION-FAILURE"],
+                                        timeout)
             if ev is None:
                 raise Exception("Joining the group timed out")
+            if "P2P-GROUP-STARTED" not in ev:
+                raise Exception("Failed to join the group")
             self.dump_monitor()
             return self.group_form_result(ev)
         raise Exception("P2P_CONNECT(join) failed")
@@ -865,7 +1010,8 @@ class WpaSupplicant:
                        "disable_ht40", "disable_sgi", "disable_ldpc",
                        "ht40_intolerant", "update_identifier", "mac_addr",
                        "erp", "bg_scan_period", "bssid_blacklist",
-                       "bssid_whitelist", "mem_only_psk", "eap_workaround" ]
+                       "bssid_whitelist", "mem_only_psk", "eap_workaround",
+                       "engine" ]
         for field in not_quoted:
             if field in kwargs and kwargs[field]:
                 self.set_network(id, field, kwargs[field])
@@ -996,7 +1142,7 @@ class WpaSupplicant:
         return res.split(' ')
 
     def get_bss(self, bssid, ifname=None):
-       if not ifname or ifname == self.ifname:
+        if not ifname or ifname == self.ifname:
             res = self.request("BSS " + bssid)
         elif ifname == self.group_ifname:
             res = self.group_request("BSS " + bssid)
@@ -1059,6 +1205,17 @@ class WpaSupplicant:
         if field != "freq":
             raise Exception("Unexpected MGMT-RX event format: " + ev)
         msg['freq'] = val
+
+        field,val = items[2].split('=')
+        if field != "datarate":
+            raise Exception("Unexpected MGMT-RX event format: " + ev)
+        msg['datarate'] = val
+
+        field,val = items[3].split('=')
+        if field != "ssi_signal":
+            raise Exception("Unexpected MGMT-RX event format: " + ev)
+        msg['ssi_signal'] = val
+
         frame = binascii.unhexlify(items[4])
         msg['frame'] = frame
 
@@ -1085,7 +1242,9 @@ class WpaSupplicant:
             raise Exception(error)
         return ev
 
-    def wait_disconnected(self, timeout=10, error="Disconnection timed out"):
+    def wait_disconnected(self, timeout=None, error="Disconnection timed out"):
+        if timeout is None:
+            timeout = 10 if self.hostname is None else 30
         ev = self.wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=timeout)
         if ev is None:
             raise Exception(error)
@@ -1106,7 +1265,7 @@ class WpaSupplicant:
         return vals
 
     def asp_provision(self, peer, adv_id, adv_mac, session_id, session_mac,
-                      method="1000", info="", status=None, cpt=None):
+                      method="1000", info="", status=None, cpt=None, role=None):
         if status is None:
             cmd = "P2P_ASP_PROVISION"
             params = "info='%s' method=%s" % (info, method)
@@ -1114,6 +1273,8 @@ class WpaSupplicant:
             cmd = "P2P_ASP_PROVISION_RESP"
             params = "status=%d" % status
 
+        if role is not None:
+            params += " role=" + role
         if cpt is not None:
             params += " cpt=" + cpt
 
index bda8036..c73a15c 100644 (file)
@@ -23,7 +23,7 @@ u8 * bip_protect(const u8 *igtk, size_t igtk_len, u8 *frame, size_t len,
        struct ieee80211_hdr *hdr;
        size_t plen;
 
-       plen = len + igtk_len == 32 ? 26 : 18;
+       plen = len + (igtk_len == 32 ? 26 : 18);
        prot = os_malloc(plen);
        if (prot == NULL)
                return NULL;
index ee1f1a6..2a1ad83 100644 (file)
@@ -77,6 +77,64 @@ static void ccmp_aad_nonce(const struct ieee80211_hdr *hdr, const u8 *data,
 }
 
 
+static void ccmp_aad_nonce_pv1(const u8 *hdr, const u8 *a1, const u8 *a2,
+                              const u8 *a3, const u8 *pn,
+                              u8 *aad, size_t *aad_len, u8 *nonce)
+{
+       u16 fc, type;
+       u8 *pos;
+
+       nonce[0] = BIT(5); /* PV1 */
+       /* TODO: Priority for QMF; 0 is used for Data frames */
+
+       fc = WPA_GET_LE16(hdr);
+       type = (fc & (BIT(2) | BIT(3) | BIT(4))) >> 2;
+
+       if (type == 1)
+               nonce[0] |= 0x10; /* Management */
+
+       fc &= ~(BIT(10) | BIT(11) | BIT(13) | BIT(14) | BIT(15));
+       fc |= BIT(12);
+       WPA_PUT_LE16(aad, fc);
+       pos = aad + 2;
+       if (type == 0 || type == 3) {
+               const u8 *sc;
+
+               os_memcpy(pos, a1, ETH_ALEN);
+               pos += ETH_ALEN;
+               os_memcpy(pos, a2, ETH_ALEN);
+               pos += ETH_ALEN;
+
+               if (type == 0) {
+                       /* Either A1 or A2 contains SID */
+                       sc = hdr + 2 + 2 + ETH_ALEN;
+               } else {
+                       /* Both A1 and A2 contain full addresses */
+                       sc = hdr + 2 + 2 * ETH_ALEN;
+               }
+               /* SC with Sequence Number subfield (bits 4-15 of the Sequence
+                * Control field) masked to 0. */
+               *pos++ = *sc & 0x0f;
+               *pos++ = 0;
+
+               if (a3) {
+                       os_memcpy(pos, a3, ETH_ALEN);
+                       pos += ETH_ALEN;
+               }
+       }
+
+       *aad_len = pos - aad;
+
+       os_memcpy(nonce + 1, a2, ETH_ALEN);
+       nonce[7] = pn[5]; /* PN5 */
+       nonce[8] = pn[4]; /* PN4 */
+       nonce[9] = pn[3]; /* PN3 */
+       nonce[10] = pn[2]; /* PN2 */
+       nonce[11] = pn[1]; /* PN1 */
+       nonce[12] = pn[0]; /* PN0 */
+}
+
+
 u8 * ccmp_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
                  const u8 *data, size_t data_len, size_t *decrypted_len)
 {
@@ -177,6 +235,48 @@ u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos,
 }
 
 
+u8 * ccmp_encrypt_pv1(const u8 *tk, const u8 *a1, const u8 *a2, const u8 *a3,
+                     const u8 *frame, size_t len,
+                     size_t hdrlen, const u8 *pn, int keyid,
+                     size_t *encrypted_len)
+{
+       u8 aad[24], nonce[13];
+       size_t aad_len, plen;
+       u8 *crypt, *pos;
+       struct ieee80211_hdr *hdr;
+
+       if (len < hdrlen || hdrlen < 12)
+               return NULL;
+       plen = len - hdrlen;
+
+       crypt = os_malloc(hdrlen + plen + 8 + AES_BLOCK_SIZE);
+       if (crypt == NULL)
+               return NULL;
+
+       os_memcpy(crypt, frame, hdrlen);
+       hdr = (struct ieee80211_hdr *) crypt;
+       hdr->frame_control |= host_to_le16(BIT(12)); /* Protected Frame */
+       pos = crypt + hdrlen;
+
+       os_memset(aad, 0, sizeof(aad));
+       ccmp_aad_nonce_pv1(crypt, a1, a2, a3, pn, aad, &aad_len, nonce);
+       wpa_hexdump(MSG_EXCESSIVE, "CCMP AAD", aad, aad_len);
+       wpa_hexdump(MSG_EXCESSIVE, "CCMP nonce", nonce, sizeof(nonce));
+
+       if (aes_ccm_ae(tk, 16, nonce, 8, frame + hdrlen, plen, aad, aad_len,
+                      pos, pos + plen) < 0) {
+               os_free(crypt);
+               return NULL;
+       }
+
+       wpa_hexdump(MSG_EXCESSIVE, "CCMP encrypted", crypt + hdrlen, plen);
+
+       *encrypted_len = hdrlen + plen + 8;
+
+       return crypt;
+}
+
+
 u8 * ccmp_256_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
                      const u8 *data, size_t data_len, size_t *decrypted_len)
 {
index 7c3ce18..6c3853b 100644 (file)
@@ -102,6 +102,8 @@ int read_cap_file(struct wlantest *wt, const char *fname)
                                write_pcap_with_radiotap(wt, data, hdr->caplen);
                        else
                                pcap_dump(wt->write_pcap_dumper, hdr, data);
+                       if (wt->pcap_no_buffer)
+                               pcap_dump_flush(wt->write_pcap_dumper);
                }
                if (hdr->caplen < hdr->len) {
                        add_note(wt, MSG_DEBUG, "pcap: Dropped incomplete "
index 4c55e7d..b53542f 100644 (file)
@@ -7,7 +7,6 @@
  */
 
 #include "utils/includes.h"
-#include <linux/if_ether.h>
 
 #include "utils/common.h"
 #include "common/defs.h"
index 36f2f5d..b15e5b3 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "utils/common.h"
 #include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
 #include "wlantest.h"
 
 
@@ -136,6 +137,212 @@ static void test_vector_ccmp(void)
 }
 
 
+static void test_vector_ccmp_pv1(void)
+{
+       u8 tk[] = { 0xc9, 0x7c, 0x1f, 0x67, 0xce, 0x37, 0x11, 0x85,
+                   0x51, 0x4a, 0x8a, 0x19, 0xf2, 0xbd, 0xd5, 0x2f };
+       u8 pn[8];
+       u8 frame1[] = {
+               0x61, 0x00, 0xa2, 0xae, 0xa5, 0xb8, 0xfc, 0xba,
+               0x07, 0x00, 0x80, 0x33,
+               0xf8, 0xba, 0x1a, 0x55, 0xd0, 0x2f, 0x85, 0xae,
+               0x96, 0x7b, 0xb6, 0x2f, 0xb6, 0xcd, 0xa8, 0xeb,
+               0x7e, 0x78, 0xa0, 0x50
+       };
+       u8 frame2[] = {
+               0x61, 0x00, 0xa2, 0xae, 0xa5, 0xb8, 0xfc, 0xba,
+               0x07, 0x20, 0x80, 0x33, 0x02, 0xd2, 0xe1, 0x28,
+               0xa5, 0x7c,
+               0xf8, 0xba, 0x1a, 0x55, 0xd0, 0x2f, 0x85, 0xae,
+               0x96, 0x7b, 0xb6, 0x2f, 0xb6, 0xcd, 0xa8, 0xeb,
+               0x7e, 0x78, 0xa0, 0x50
+       };
+       u8 frame3[] = {
+               0x6d, 0x00, 0xa2, 0xae, 0xa5, 0xb8, 0xfc, 0xba,
+               0x52, 0x30, 0xf1, 0x84, 0x44, 0x08, 0x80, 0x33,
+               0xf8, 0xba, 0x1a, 0x55, 0xd0, 0x2f, 0x85, 0xae,
+               0x96, 0x7b, 0xb6, 0x2f, 0xb6, 0xcd, 0xa8, 0xeb,
+               0x7e, 0x78, 0xa0, 0x50
+       };
+       u8 *enc;
+       size_t enc_len;
+       u8 fcs[4];
+       u8 bssid[ETH_ALEN] = { 0xa2, 0xae, 0xa5, 0xb8, 0xfc, 0xba };
+       u8 da[ETH_ALEN] = { 0x02, 0xd2, 0xe1, 0x28, 0xa5, 0x7c };
+       u8 sa[ETH_ALEN] = { 0x52, 0x30, 0xf1, 0x84, 0x44, 0x08 };
+       u16 aid = 7;
+       u32 bpn = 123;
+       u16 sc = 0x3380;
+       int key_id = 0;
+       u16 fc;
+       int tid = 3;
+       u16 sid;
+
+       wpa_printf(MSG_INFO,
+                  "\nIEEE P802.11ah/D10.0, J.6.4 CCMP PV1 test vectors\n");
+
+       wpa_printf(MSG_INFO, "BSSID: " MACSTR, MAC2STR(bssid));
+       wpa_printf(MSG_INFO, "DA: " MACSTR, MAC2STR(da));
+       wpa_printf(MSG_INFO, "SA: " MACSTR, MAC2STR(sa));
+       wpa_printf(MSG_INFO, "Association ID: %u", aid);
+       wpa_printf(MSG_INFO, "Base PN: %u (0x%08x)", bpn, bpn);
+       wpa_printf(MSG_INFO, "SC = 0x%04x (FragNum=%u SeqNum=%u)",
+                  sc, WLAN_GET_SEQ_FRAG(sc), WLAN_GET_SEQ_SEQ(sc));
+       wpa_printf(MSG_INFO, "TID = %u", tid);
+       wpa_printf(MSG_INFO, "Key ID: %u", key_id);
+       wpa_hexdump(MSG_INFO, "TK", tk, sizeof(tk));
+       wpa_printf(MSG_INFO, "PN = SC||BPN");
+       WPA_PUT_LE16(&pn[0], sc);
+       WPA_PUT_LE32(&pn[2], bpn);
+       wpa_hexdump(MSG_INFO, "PN (PN0..PN5)", pn, sizeof(pn));
+
+       wpa_printf(MSG_INFO,
+                  "\nPV1 test vector #1:\nHeader compression used and A3 was previously stored at the receiver\n");
+       fc = WPA_GET_LE16(frame1);
+       wpa_printf(MSG_INFO,
+                  "FC=0x%04x (PV=%u Type=%u PTID/Subtype=%u From_DS=%u More_Fragments=%u Power_Management=%u More_Data=%u Protected_Frame=%u End_of_SP=%u Relayed_Frame=%u Ack_Policy=%u)",
+                  fc,
+                  fc & WLAN_FC_PVER,
+                  (fc & (BIT(2) | BIT(3) | BIT(4))) >> 2,
+                  (fc & (BIT(5) | BIT(6) | BIT(7))) >> 5,
+                  !!(fc & BIT(8)),
+                  !!(fc & BIT(9)),
+                  !!(fc & BIT(10)),
+                  !!(fc & BIT(11)),
+                  !!(fc & BIT(12)),
+                  !!(fc & BIT(13)),
+                  !!(fc & BIT(14)),
+                  !!(fc & BIT(15)));
+       wpa_printf(MSG_INFO, "A1=" MACSTR, MAC2STR(&frame1[2]));
+       sid = WPA_GET_LE16(&frame1[8]);
+       wpa_printf(MSG_INFO,
+                  "A2=%02x %02x (SID: AID=%u A3_Present=%u A4_Present=%u A-MSDU=%u); corresponds to 52:30:f1:84:44:08 in uncompressed header",
+                  frame1[8], frame1[9],
+                  sid & ~(BIT(13) | BIT(14) | BIT(15)),
+                  !!(sid & BIT(13)),
+                  !!(sid & BIT(14)),
+                  !!(sid & BIT(15)));
+       sc = WPA_GET_LE16(&frame1[10]);
+       wpa_printf(MSG_INFO, "Sequence Control: %02x %02x (FN=%u SN=%u)",
+                  frame1[10], frame1[11],
+                  WLAN_GET_SEQ_FRAG(sc), WLAN_GET_SEQ_SEQ(sc));
+       wpa_printf(MSG_INFO, "A3 not present; corresponds to 02:d2:e1:28:a5:7c in uncompressed header");
+       wpa_printf(MSG_INFO, "A4 not present");
+       wpa_hexdump(MSG_INFO, "Plaintext Frame Header", frame1, 12);
+       wpa_hexdump(MSG_INFO, "Plaintext Frame Body",
+                   frame1 + 12, sizeof(frame1) - 12);
+
+       enc = ccmp_encrypt_pv1(tk, &frame1[2], sa, da, frame1, sizeof(frame1),
+                              12, pn, key_id, &enc_len);
+       if (enc == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to encrypt CCMP frame");
+               return;
+       }
+
+       wpa_hexdump(MSG_INFO, "Encrypted Frame Header", enc, 12);
+       wpa_hexdump(MSG_INFO, "Encrypted Frame Frame Body",
+                   enc + 12, enc_len - 12);
+       WPA_PUT_LE32(fcs, crc32(enc, enc_len));
+       wpa_hexdump(MSG_INFO, "Encrypted Frame FCS", fcs, sizeof(fcs));
+
+       wpa_printf(MSG_INFO,
+                  "\nPV1 test vector #2:\nHeader compression used and A3 was not previously stored at the receiver\n");
+       fc = WPA_GET_LE16(frame2);
+       wpa_printf(MSG_INFO,
+                  "FC=0x%04x (PV=%u Type=%u PTID/Subtype=%u From_DS=%u More_Fragments=%u Power_Management=%u More_Data=%u Protected_Frame=%u End_of_SP=%u Relayed_Frame=%u Ack_Policy=%u)",
+                  fc,
+                  fc & WLAN_FC_PVER,
+                  (fc & (BIT(2) | BIT(3) | BIT(4))) >> 2,
+                  (fc & (BIT(5) | BIT(6) | BIT(7))) >> 5,
+                  !!(fc & BIT(8)),
+                  !!(fc & BIT(9)),
+                  !!(fc & BIT(10)),
+                  !!(fc & BIT(11)),
+                  !!(fc & BIT(12)),
+                  !!(fc & BIT(13)),
+                  !!(fc & BIT(14)),
+                  !!(fc & BIT(15)));
+       wpa_printf(MSG_INFO, "A1=" MACSTR, MAC2STR(&frame2[2]));
+       sid = WPA_GET_LE16(&frame2[8]);
+       wpa_printf(MSG_INFO,
+                  "A2=%02x %02x (SID: AID=%u A3_Present=%u A4_Present=%u A-MSDU=%u); corresponds to 52:30:f1:84:44:08 in uncompressed header",
+                  frame2[8], frame2[9],
+                  sid & ~(BIT(13) | BIT(14) | BIT(15)),
+                  !!(sid & BIT(13)),
+                  !!(sid & BIT(14)),
+                  !!(sid & BIT(15)));
+       sc = WPA_GET_LE16(&frame2[10]);
+       wpa_printf(MSG_INFO, "Sequence Control: %02x %02x (FN=%u SN=%u)",
+                  frame2[10], frame2[11],
+                  WLAN_GET_SEQ_FRAG(sc), WLAN_GET_SEQ_SEQ(sc));
+       wpa_printf(MSG_INFO, "A3=" MACSTR, MAC2STR(&frame2[12]));
+       wpa_printf(MSG_INFO, "A4 not present");
+       wpa_hexdump(MSG_INFO, "Plaintext Frame Header", frame2, 18);
+       wpa_hexdump(MSG_INFO, "Plaintext Frame Body",
+                   frame2 + 18, sizeof(frame2) - 18);
+
+       enc = ccmp_encrypt_pv1(tk, &frame2[2], sa, &frame2[12],
+                              frame2, sizeof(frame2), 18, pn, key_id,
+                              &enc_len);
+       if (enc == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to encrypt CCMP frame");
+               return;
+       }
+
+       wpa_hexdump(MSG_INFO, "Encrypted Frame Header", enc, 18);
+       wpa_hexdump(MSG_INFO, "Encrypted Frame Frame Body",
+                   enc + 18, enc_len - 18);
+       WPA_PUT_LE32(fcs, crc32(enc, enc_len));
+       wpa_hexdump(MSG_INFO, "Encrypted Frame FCS", fcs, sizeof(fcs));
+
+       wpa_printf(MSG_INFO,
+                  "\nPV1 test vector #3:\nType 3 frame from SA to DA(=BSSID) (i.e., no separate DA in this example)\n");
+       fc = WPA_GET_LE16(frame3);
+       wpa_printf(MSG_INFO,
+                  "FC=0x%04x (PV=%u Type=%u PTID/Subtype=%u From_DS=%u More_Fragments=%u Power_Management=%u More_Data=%u Protected_Frame=%u End_of_SP=%u Relayed_Frame=%u Ack_Policy=%u)",
+                  fc,
+                  fc & WLAN_FC_PVER,
+                  (fc & (BIT(2) | BIT(3) | BIT(4))) >> 2,
+                  (fc & (BIT(5) | BIT(6) | BIT(7))) >> 5,
+                  !!(fc & BIT(8)),
+                  !!(fc & BIT(9)),
+                  !!(fc & BIT(10)),
+                  !!(fc & BIT(11)),
+                  !!(fc & BIT(12)),
+                  !!(fc & BIT(13)),
+                  !!(fc & BIT(14)),
+                  !!(fc & BIT(15)));
+       wpa_printf(MSG_INFO, "A1=" MACSTR, MAC2STR(&frame3[2]));
+       wpa_printf(MSG_INFO, "A2=" MACSTR, MAC2STR(&frame3[8]));
+       sc = WPA_GET_LE16(&frame3[14]);
+       wpa_printf(MSG_INFO, "Sequence Control: %02x %02x (FN=%u SN=%u)",
+                  frame3[14], frame3[15],
+                  WLAN_GET_SEQ_FRAG(sc), WLAN_GET_SEQ_SEQ(sc));
+       wpa_printf(MSG_INFO,
+                  "A3 not present; corresponds to 02:d2:e1:28:a5:7c in uncompressed header");
+       wpa_printf(MSG_INFO, "A4 not present");
+       wpa_hexdump(MSG_INFO, "Plaintext Frame Header", frame3, 16);
+       wpa_hexdump(MSG_INFO, "Plaintext Frame Body",
+                   frame3 + 16, sizeof(frame3) - 16);
+
+       enc = ccmp_encrypt_pv1(tk, &frame3[2], &frame3[8], da,
+                              frame3, sizeof(frame3), 16, pn, key_id,
+                              &enc_len);
+       if (enc == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to encrypt CCMP frame");
+               return;
+       }
+
+       wpa_hexdump(MSG_INFO, "Encrypted Frame Header", enc, 16);
+       wpa_hexdump(MSG_INFO, "Encrypted Frame Frame Body",
+                   enc + 16, enc_len - 16);
+       WPA_PUT_LE32(fcs, crc32(enc, enc_len));
+       wpa_hexdump(MSG_INFO, "Encrypted Frame FCS", fcs, sizeof(fcs));
+
+       wpa_debug_level = MSG_INFO;
+}
+
+
 static void test_vector_bip(void)
 {
        u8 igtk[] = {
@@ -712,6 +919,7 @@ int main(int argc, char *argv[])
 
        test_vector_tkip();
        test_vector_ccmp();
+       test_vector_ccmp_pv1();
        test_vector_bip();
        test_vector_ccmp_mgmt();
        errors += test_vector_gcmp();
index ab3b2fc..abe97d1 100644 (file)
@@ -21,7 +21,7 @@ static void wlantest_terminate(int sig, void *signal_ctx)
 
 static void usage(void)
 {
-       printf("wlantest [-cddhqqFt] [-i<ifname>] [-r<pcap file>] "
+       printf("wlantest [-cddhqqFNt] [-i<ifname>] [-r<pcap file>] "
               "[-p<passphrase>]\n"
               "         [-I<wired ifname>] [-R<wired pcap file>] "
               "[-P<RADIUS shared secret>]\n"
@@ -350,7 +350,7 @@ int main(int argc, char *argv[])
        wlantest_init(&wt);
 
        for (;;) {
-               c = getopt(argc, argv, "cdf:Fhi:I:L:n:p:P:qr:R:tT:w:W:");
+               c = getopt(argc, argv, "cdf:Fhi:I:L:n:Np:P:qr:R:tT:w:W:");
                if (c < 0)
                        break;
                switch (c) {
@@ -383,6 +383,9 @@ int main(int argc, char *argv[])
                case 'n':
                        wt.pcapng_file = optarg;
                        break;
+               case 'N':
+                       wt.pcap_no_buffer = 1;
+                       break;
                case 'p':
                        add_passphrase(&wt, optarg);
                        break;
index ced9baa..1ff579f 100644 (file)
@@ -202,6 +202,7 @@ struct wlantest {
        int last_mgmt_valid;
 
        unsigned int assume_fcs:1;
+       unsigned int pcap_no_buffer:1;
 
        char *notes[MAX_NOTES];
        size_t num_notes;
@@ -273,6 +274,10 @@ u8 * ccmp_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
                  const u8 *data, size_t data_len, size_t *decrypted_len);
 u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos,
                  u8 *pn, int keyid, size_t *encrypted_len);
+u8 * ccmp_encrypt_pv1(const u8 *tk, const u8 *a1, const u8 *a2, const u8 *a3,
+                     const u8 *frame, size_t len,
+                     size_t hdrlen, const u8 *pn, int keyid,
+                     size_t *encrypted_len);
 void ccmp_get_pn(u8 *pn, const u8 *data);
 u8 * ccmp_256_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
                      const u8 *data, size_t data_len, size_t *decrypted_len);
index 28b306b..abd889f 100644 (file)
@@ -59,6 +59,8 @@ void write_pcap_captured(struct wlantest *wt, const u8 *buf, size_t len)
        h.caplen = len;
        h.len = len;
        pcap_dump(wt->write_pcap_dumper, &h, buf);
+       if (wt->pcap_no_buffer)
+               pcap_dump_flush(wt->write_pcap_dumper);
 }
 
 
@@ -102,6 +104,8 @@ void write_pcap_decrypted(struct wlantest *wt, const u8 *buf1, size_t len1,
        h.caplen = len;
        h.len = len;
        pcap_dump(wt->write_pcap_dumper, &h, buf);
+       if (wt->pcap_no_buffer)
+               pcap_dump_flush(wt->write_pcap_dumper);
 }
 
 
@@ -181,6 +185,8 @@ int write_pcapng_init(struct wlantest *wt, const char *fname)
        desc.link_type = LINKTYPE_IEEE802_11_RADIO;
        desc.snap_len = 65535;
        fwrite(&desc, sizeof(desc), 1, wt->pcapng);
+       if (wt->pcap_no_buffer)
+               fflush(wt->pcapng);
 
        return 0;
 }
@@ -263,6 +269,8 @@ static void write_pcapng_decrypted(struct wlantest *wt)
        *block_len = pkt->block_total_len = pos - (u8 *) pkt;
 
        fwrite(pkt, pos - (u8 *) pkt, 1, wt->pcapng);
+       if (wt->pcap_no_buffer)
+               fflush(wt->pcapng);
 
        os_free(pkt);
 }
@@ -337,6 +345,8 @@ void write_pcapng_write_read(struct wlantest *wt, int dlt,
        *block_len = pkt->block_total_len = pos - (u8 *) pkt;
 
        fwrite(pkt, pos - (u8 *) pkt, 1, wt->pcapng);
+       if (wt->pcap_no_buffer)
+               fflush(wt->pcapng);
 
        os_free(pkt);
 
index 0d818ed..a8d6a7f 100644 (file)
@@ -49,6 +49,12 @@ ifeq ($(TARGET_ARCH),arm)
 L_CFLAGS += -mabi=aapcs-linux
 endif
 
+# C++ flags for binder interface
+L_CPPFLAGS := -std=c++11 -Wall -Werror
+# TODO: Remove these allowed warnings later.
+L_CPPFLAGS += -Wno-unused-variable -Wno-unused-parameter
+L_CPPFLAGS += -Wno-unused-private-field
+
 INCLUDES = $(LOCAL_PATH)
 INCLUDES += $(LOCAL_PATH)/src
 INCLUDES += $(LOCAL_PATH)/src/common
@@ -65,7 +71,6 @@ INCLUDES += $(LOCAL_PATH)/src/rsn_supp
 INCLUDES += $(LOCAL_PATH)/src/tls
 INCLUDES += $(LOCAL_PATH)/src/utils
 INCLUDES += $(LOCAL_PATH)/src/wps
-INCLUDES += external/openssl/include
 INCLUDES += system/security/keystore/include
 ifdef CONFIG_DRIVER_NL80211
 ifneq ($(wildcard external/libnl),)
@@ -95,6 +100,7 @@ OBJS_p += src/utils/wpabuf.c
 OBJS_c = wpa_cli.c src/common/wpa_ctrl.c
 OBJS_c += src/utils/wpa_debug.c
 OBJS_c += src/utils/common.c
+OBJS_c += src/common/cli.c
 OBJS_d =
 OBJS_priv =
 
@@ -270,6 +276,7 @@ endif
 ifdef CONFIG_IBSS_RSN
 NEED_RSN_AUTHENTICATOR=y
 L_CFLAGS += -DCONFIG_IBSS_RSN
+L_CFLAGS += -DCONFIG_NO_VLAN
 OBJS += ibss_rsn.c
 endif
 
@@ -386,7 +393,6 @@ EAPDYN += src/eap_peer/eap_tls.so
 else
 L_CFLAGS += -DEAP_TLS
 OBJS += src/eap_peer/eap_tls.c
-OBJS_h += src/eap_server/eap_server_tls.c
 endif
 TLS_FUNCS=y
 CONFIG_IEEE8021X_EAPOL=y
@@ -397,7 +403,6 @@ ifdef CONFIG_EAP_UNAUTH_TLS
 L_CFLAGS += -DEAP_UNAUTH_TLS
 ifndef CONFIG_EAP_TLS
 OBJS += src/eap_peer/eap_tls.c
-OBJS_h += src/eap_server/eap_server_tls.c
 TLS_FUNCS=y
 endif
 CONFIG_IEEE8021X_EAPOL=y
@@ -412,7 +417,6 @@ else
 L_CFLAGS += -DEAP_PEAP
 OBJS += src/eap_peer/eap_peap.c
 OBJS += src/eap_common/eap_peap_common.c
-OBJS_h += src/eap_server/eap_server_peap.c
 endif
 TLS_FUNCS=y
 CONFIG_IEEE8021X_EAPOL=y
@@ -426,7 +430,6 @@ EAPDYN += src/eap_peer/eap_ttls.so
 else
 L_CFLAGS += -DEAP_TTLS
 OBJS += src/eap_peer/eap_ttls.c
-OBJS_h += src/eap_server/eap_server_ttls.c
 endif
 TLS_FUNCS=y
 ifndef CONFIG_FIPS
@@ -444,7 +447,6 @@ EAPDYN += src/eap_peer/eap_md5.so
 else
 L_CFLAGS += -DEAP_MD5
 OBJS += src/eap_peer/eap_md5.c
-OBJS_h += src/eap_server/eap_server_md5.c
 endif
 CHAP=y
 CONFIG_IEEE8021X_EAPOL=y
@@ -467,7 +469,6 @@ else
 L_CFLAGS += -DEAP_MSCHAPv2
 OBJS += src/eap_peer/eap_mschapv2.c
 OBJS += src/eap_peer/mschapv2.c
-OBJS_h += src/eap_server/eap_server_mschapv2.c
 endif
 MS_FUNCS=y
 CONFIG_IEEE8021X_EAPOL=y
@@ -481,7 +482,6 @@ EAPDYN += src/eap_peer/eap_gtc.so
 else
 L_CFLAGS += -DEAP_GTC
 OBJS += src/eap_peer/eap_gtc.c
-OBJS_h += src/eap_server/eap_server_gtc.c
 endif
 CONFIG_IEEE8021X_EAPOL=y
 endif
@@ -506,7 +506,6 @@ EAPDYN += src/eap_peer/eap_sim.so
 else
 L_CFLAGS += -DEAP_SIM
 OBJS += src/eap_peer/eap_sim.c
-OBJS_h += src/eap_server/eap_server_sim.c
 endif
 CONFIG_IEEE8021X_EAPOL=y
 CONFIG_EAP_SIM_COMMON=y
@@ -534,7 +533,6 @@ EAPDYN += src/eap_peer/eap_psk.so
 else
 L_CFLAGS += -DEAP_PSK
 OBJS += src/eap_peer/eap_psk.c src/eap_common/eap_psk_common.c
-OBJS_h += src/eap_server/eap_server_psk.c
 endif
 CONFIG_IEEE8021X_EAPOL=y
 NEED_AES=y
@@ -551,7 +549,6 @@ EAPDYN += src/eap_peer/eap_aka.so
 else
 L_CFLAGS += -DEAP_AKA
 OBJS += src/eap_peer/eap_aka.c
-OBJS_h += src/eap_server/eap_server_aka.c
 endif
 CONFIG_IEEE8021X_EAPOL=y
 CONFIG_EAP_SIM_COMMON=y
@@ -577,7 +574,6 @@ endif
 
 ifdef CONFIG_EAP_SIM_COMMON
 OBJS += src/eap_common/eap_sim_common.c
-OBJS_h += src/eap_server/eap_sim_db.c
 NEED_AES=y
 NEED_FIPS186_2_PRF=y
 endif
@@ -592,7 +588,6 @@ else
 L_CFLAGS += -DEAP_FAST
 OBJS += src/eap_peer/eap_fast.c src/eap_peer/eap_fast_pac.c
 OBJS += src/eap_common/eap_fast_common.c
-OBJS_h += src/eap_server/eap_server_fast.c
 endif
 TLS_FUNCS=y
 CONFIG_IEEE8021X_EAPOL=y
@@ -607,7 +602,6 @@ EAPDYN += src/eap_peer/eap_pax.so
 else
 L_CFLAGS += -DEAP_PAX
 OBJS += src/eap_peer/eap_pax.c src/eap_common/eap_pax_common.c
-OBJS_h += src/eap_server/eap_server_pax.c
 endif
 CONFIG_IEEE8021X_EAPOL=y
 endif
@@ -620,7 +614,6 @@ EAPDYN += src/eap_peer/eap_sake.so
 else
 L_CFLAGS += -DEAP_SAKE
 OBJS += src/eap_peer/eap_sake.c src/eap_common/eap_sake_common.c
-OBJS_h += src/eap_server/eap_server_sake.c
 endif
 CONFIG_IEEE8021X_EAPOL=y
 endif
@@ -633,7 +626,6 @@ EAPDYN += src/eap_peer/eap_gpsk.so
 else
 L_CFLAGS += -DEAP_GPSK
 OBJS += src/eap_peer/eap_gpsk.c src/eap_common/eap_gpsk_common.c
-OBJS_h += src/eap_server/eap_server_gpsk.c
 endif
 CONFIG_IEEE8021X_EAPOL=y
 ifdef CONFIG_EAP_GPSK_SHA256
@@ -646,7 +638,6 @@ endif
 ifdef CONFIG_EAP_PWD
 L_CFLAGS += -DEAP_PWD
 OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c
-OBJS_h += src/eap_server/eap_server_pwd.c
 CONFIG_IEEE8021X_EAPOL=y
 NEED_SHA256=y
 endif
@@ -659,7 +650,6 @@ EAPDYN += src/eap_peer/eap_eke.so
 else
 L_CFLAGS += -DEAP_EKE
 OBJS += src/eap_peer/eap_eke.c src/eap_common/eap_eke_common.c
-OBJS_h += src/eap_server/eap_server_eke.c
 endif
 CONFIG_IEEE8021X_EAPOL=y
 NEED_DH_GROUPS=y
@@ -682,7 +672,6 @@ 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
-OBJS_h += src/eap_server/eap_server_wsc.c
 CONFIG_IEEE8021X_EAPOL=y
 NEED_DH_GROUPS=y
 NEED_SHA256=y
@@ -745,8 +734,6 @@ else
 L_CFLAGS += -DEAP_IKEV2
 OBJS += src/eap_peer/eap_ikev2.c src/eap_peer/ikev2.c
 OBJS += src/eap_common/eap_ikev2_common.c src/eap_common/ikev2_common.c
-OBJS_h += src/eap_server/eap_server_ikev2.c
-OBJS_h += src/eap_server/ikev2.c
 endif
 CONFIG_IEEE8021X_EAPOL=y
 NEED_DH_GROUPS=y
@@ -762,7 +749,6 @@ EAPDYN += src/eap_peer/eap_vendor_test.so
 else
 L_CFLAGS += -DEAP_VENDOR_TEST
 OBJS += src/eap_peer/eap_vendor_test.c
-OBJS_h += src/eap_server/eap_server_vendor_test.c
 endif
 CONFIG_IEEE8021X_EAPOL=y
 endif
@@ -772,8 +758,6 @@ ifdef CONFIG_EAP_TNC
 L_CFLAGS += -DEAP_TNC
 OBJS += src/eap_peer/eap_tnc.c
 OBJS += src/eap_peer/tncc.c
-OBJS_h += src/eap_server/eap_server_tnc.c
-OBJS_h += src/eap_server/tncs.c
 NEED_BASE64=y
 ifndef CONFIG_NATIVE_WINDOWS
 ifndef CONFIG_DRIVER_BSD
@@ -820,6 +804,8 @@ OBJS += src/ap/ap_drv_ops.c
 OBJS += src/ap/beacon.c
 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
@@ -829,6 +815,9 @@ endif
 ifdef CONFIG_WNM
 OBJS += src/ap/wnm_ap.c
 endif
+ifdef CONFIG_MBO
+OBJS += src/ap/mbo_ap.c
+endif
 ifdef CONFIG_CTRL_IFACE
 OBJS += src/ap/ctrl_iface_ap.c
 endif
@@ -845,6 +834,11 @@ L_CFLAGS += -DCONFIG_IEEE80211AC
 endif
 endif
 
+ifdef CONFIG_MBO
+OBJS += mbo.c
+L_CFLAGS += -DCONFIG_MBO
+endif
+
 ifdef NEED_AP_MLME
 OBJS += src/ap/wmm.c
 OBJS += src/ap/ap_list.c
@@ -880,34 +874,10 @@ OBJS += src/ap/peerkey_auth.c
 endif
 endif
 
-ifdef CONFIG_EAP_SERVER
-L_CFLAGS += -DEAP_SERVER
-OBJS_h += src/eap_server/eap_server.c
-OBJS_h += src/eap_server/eap_server_identity.c
-OBJS_h += src/eap_server/eap_server_methods.c
-endif
-
-ifdef CONFIG_RADIUS_CLIENT
-OBJS_h += src/utils/ip_addr.c
-OBJS_h += src/radius/radius.c
-OBJS_h += src/radius/radius_client.c
-endif
-
-ifdef CONFIG_AUTHENTICATOR
-OBJS_h += src/eapol_auth/eapol_auth_sm.c
-OBJS_h += src/ap/ieee802_1x.c
-endif
-
-ifdef CONFIG_WPA_AUTHENTICATOR
-OBJS_h += src/ap/wpa_auth.c
-OBJS_h += src/ap/wpa_auth_ie.c
-OBJS_h += src/ap/pmksa_cache_auth.c
-ifdef CONFIG_IEEE80211R
-OBJS_h += src/ap/wpa_auth_ft.c
-endif
-ifdef CONFIG_PEERKEY
-OBJS_h += src/ap/peerkey_auth.c
-endif
+ifdef CONFIG_ACS
+L_CFLAGS += -DCONFIG_ACS
+OBJS += src/ap/acs.c
+LIBS += -lm
 endif
 
 ifdef CONFIG_PCSC
@@ -961,7 +931,6 @@ ifdef TLS_FUNCS
 NEED_DES=y
 # Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST)
 OBJS += src/eap_peer/eap_tls_common.c
-OBJS_h += src/eap_server/eap_server_tls_common.c
 ifndef CONFIG_FIPS
 NEED_TLS_PRF=y
 NEED_SHA1=y
@@ -986,6 +955,7 @@ ifeq ($(CONFIG_TLS), openssl)
 ifdef TLS_FUNCS
 L_CFLAGS += -DEAP_TLS_OPENSSL
 OBJS += src/crypto/tls_openssl.c
+OBJS += src/crypto/tls_openssl_ocsp.c
 LIBS += -lssl
 endif
 OBJS += src/crypto/crypto_openssl.c
@@ -1034,6 +1004,7 @@ OBJS += src/tls/tlsv1_cred.c
 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
 OBJS += src/tls/rsa.c
 OBJS += src/tls/x509v3.c
@@ -1087,6 +1058,8 @@ 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
@@ -1273,10 +1246,19 @@ SHA256OBJS += src/crypto/sha256-prf.c
 ifdef CONFIG_INTERNAL_SHA256
 SHA256OBJS += src/crypto/sha256-internal.c
 endif
+ifdef CONFIG_INTERNAL_SHA384
+L_CFLAGS += -DCONFIG_INTERNAL_SHA384
+SHA256OBJS += src/crypto/sha384-internal.c
+endif
+ifdef CONFIG_INTERNAL_SHA512
+L_CFLAGS += -DCONFIG_INTERNAL_SHA512
+SHA256OBJS += src/crypto/sha512-internal.c
+endif
 ifdef NEED_TLS_PRF_SHA256
 SHA256OBJS += src/crypto/sha256-tlsprf.c
 endif
 ifdef NEED_HMAC_SHA256_KDF
+L_CFLAGS += -DCONFIG_HMAC_SHA256_KDF
 SHA256OBJS += src/crypto/sha256-kdf.c
 endif
 OBJS += $(SHA256OBJS)
@@ -1319,6 +1301,7 @@ endif
 L_CFLAGS += -DCONFIG_CTRL_IFACE
 ifeq ($(CONFIG_CTRL_IFACE), unix)
 L_CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
+OBJS += src/common/ctrl_iface_common.c
 endif
 ifeq ($(CONFIG_CTRL_IFACE), udp)
 L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP
@@ -1342,12 +1325,6 @@ ifdef CONFIG_WPS
 DBUS_OBJS += dbus/dbus_old_handlers_wps.c
 endif
 DBUS_OBJS += dbus/dbus_dict_helpers.c
-ifndef DBUS_LIBS
-DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
-endif
-ifndef DBUS_INCLUDE
-DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
-endif
 DBUS_CFLAGS += $(DBUS_INCLUDE)
 endif
 
@@ -1363,12 +1340,6 @@ endif
 ifdef CONFIG_P2P
 DBUS_OBJS += dbus/dbus_new_handlers_p2p.c
 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
 DBUS_OBJS += dbus/dbus_new_introspect.c
 DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
@@ -1383,7 +1354,11 @@ endif
 
 OBJS += $(DBUS_OBJS)
 L_CFLAGS += $(DBUS_CFLAGS)
-LIBS += $(DBUS_LIBS)
+
+ifdef CONFIG_CTRL_IFACE_BINDER
+WPA_SUPPLICANT_USE_BINDER=y
+L_CFLAGS += -DCONFIG_BINDER -DCONFIG_CTRL_IFACE_BINDER
+endif
 
 ifdef CONFIG_READLINE
 OBJS_c += src/utils/edit_readline.c
@@ -1529,12 +1504,6 @@ endif
 
 OBJS += src/drivers/driver_common.c
 
-OBJS_wpa_rm := ctrl_iface.c ctrl_iface_unix.c
-OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.c
-ifdef CONFIG_AUTHENTICATOR
-OBJS_wpa += tests/link_test.c
-endif
-OBJS_wpa += $(OBJS_l2)
 OBJS += wpa_supplicant.c events.c blacklist.c wpas_glue.c scan.c
 OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.c
 OBJS_t += src/radius/radius_client.c
@@ -1608,6 +1577,13 @@ endif
 ifeq ($(CONFIG_TLS), openssl)
 LOCAL_SHARED_LIBRARIES += libcrypto libssl libkeystore_binder
 endif
+
+# With BoringSSL we need libkeystore-engine in order to provide access to
+# keystore keys.
+ifneq (,$(wildcard external/boringssl/flavor.mk))
+LOCAL_SHARED_LIBRARIES += libkeystore-engine
+endif
+
 ifdef CONFIG_DRIVER_NL80211
 ifneq ($(wildcard external/libnl),)
 LOCAL_SHARED_LIBRARIES += libnl
@@ -1618,6 +1594,13 @@ endif
 LOCAL_CFLAGS := $(L_CFLAGS)
 LOCAL_SRC_FILES := $(OBJS)
 LOCAL_C_INCLUDES := $(INCLUDES)
+ifeq ($(DBUS), y)
+LOCAL_SHARED_LIBRARIES += libdbus
+endif
+ifeq ($(WPA_SUPPLICANT_USE_BINDER), y)
+LOCAL_SHARED_LIBRARIES += libbinder libutils
+LOCAL_STATIC_LIBRARIES += libwpa_binder libwpa_binder_interface
+endif
 include $(BUILD_EXECUTABLE)
 
 ########################
@@ -1656,3 +1639,42 @@ LOCAL_COPY_HEADERS_TO := libwpa_client
 LOCAL_COPY_HEADERS := src/common/wpa_ctrl.h
 LOCAL_COPY_HEADERS += src/common/qca-vendor.h
 include $(BUILD_SHARED_LIBRARY)
+
+ifeq ($(WPA_SUPPLICANT_USE_BINDER), y)
+### Binder interface library ###
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libwpa_binder_interface
+LOCAL_AIDL_INCLUDES := \
+    $(LOCAL_PATH)/binder \
+    frameworks/native/aidl/binder
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+    $(LOCAL_PATH)/binder
+LOCAL_CPPFLAGS := $(L_CPPFLAGS)
+LOCAL_SRC_FILES := \
+    binder/binder_constants.cpp \
+    binder/fi/w1/wpa_supplicant/ISupplicant.aidl \
+    binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl \
+    binder/fi/w1/wpa_supplicant/IIface.aidl
+LOCAL_SHARED_LIBRARIES := libbinder
+include $(BUILD_STATIC_LIBRARY)
+
+### Binder service library ###
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libwpa_binder
+LOCAL_CPPFLAGS := $(L_CPPFLAGS)
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_C_INCLUDES := $(INCLUDES)
+LOCAL_SRC_FILES := \
+    binder/binder.cpp binder/binder_manager.cpp \
+    binder/supplicant.cpp binder/iface.cpp
+LOCAL_SHARED_LIBRARIES := \
+    libbinder \
+    libutils
+LOCAL_STATIC_LIBRARIES := libwpa_binder_interface
+include $(BUILD_STATIC_LIBRARY)
+
+endif # BINDER == y
index facd90e..f28055f 100644 (file)
@@ -1,5 +1,149 @@
 ChangeLog for wpa_supplicant
 
+2016-10-02 - v2.6
+       * fixed WNM Sleep Mode processing when PMF is not enabled
+         [http://w1.fi/security/2015-6/] (CVE-2015-5310)
+       * fixed EAP-pwd last fragment validation
+         [http://w1.fi/security/2015-7/] (CVE-2015-5315)
+       * fixed EAP-pwd unexpected Confirm message processing
+         [http://w1.fi/security/2015-8/] (CVE-2015-5316)
+       * fixed WPS configuration update vulnerability with malformed passphrase
+         [http://w1.fi/security/2016-1/] (CVE-2016-4476)
+       * fixed configuration update vulnerability with malformed parameters set
+         over the local control interface
+         [http://w1.fi/security/2016-1/] (CVE-2016-4477)
+       * fixed TK configuration to the driver in EAPOL-Key 3/4 retry case
+       * extended channel switch support for P2P GO
+       * started to throttle control interface event message bursts to avoid
+         issues with monitor sockets running out of buffer space
+       * mesh mode fixes/improvements
+         - generate proper AID for peer
+         - enable WMM by default
+         - add VHT support
+         - fix PMKID derivation
+         - improve robustness on various exchanges
+         - fix peer link counting in reconnect case
+         - improve mesh joining behavior
+         - allow DTIM period to be configured
+         - allow HT to be disabled (disable_ht=1)
+         - add MESH_PEER_ADD and MESH_PEER_REMOVE commands
+         - add support for PMKSA caching
+         - add minimal support for SAE group negotiation
+         - allow pairwise/group cipher to be configured in the network profile
+         - use ieee80211w profile parameter to enable/disable PMF and derive
+           a separate TX IGTK if PMF is enabled instead of using MGTK
+           incorrectly
+         - fix AEK and MTK derivation
+         - remove GTKdata and IGTKdata from Mesh Peering Confirm/Close
+         - note: these changes are not fully backwards compatible for secure
+           (RSN) mesh network
+       * fixed PMKID derivation with SAE
+       * added support for requesting and fetching arbitrary ANQP-elements
+         without internal support in wpa_supplicant for the specific element
+         (anqp[265]=<hexdump> in "BSS <BSSID>" command output)
+       * P2P
+         - filter control characters in group client device names to be
+           consistent with other P2P peer cases
+         - support VHT 80+80 MHz and 160 MHz
+         - indicate group completion in P2P Client role after data association
+           instead of already after the WPS provisioning step
+         - improve group-join operation to use SSID, if known, to filter BSS
+           entries
+         - added optional ssid=<hexdump> argument to P2P_CONNECT for join case
+         - added P2P_GROUP_MEMBER command to fetch client interface address
+       * P2PS
+         - fix follow-on PD Response behavior
+         - fix PD Response generation for unknown peer
+         - fix persistent group reporting
+         - add channel policy to PD Request
+         - add group SSID to the P2PS-PROV-DONE event
+         - allow "P2P_CONNECT <addr> p2ps" to be used without specifying the
+           default PIN
+       * BoringSSL
+         - support for OCSP stapling
+         - support building of h20-osu-client
+       * D-Bus
+         - add ExpectDisconnect()
+         - add global config parameters as properties
+         - add SaveConfig()
+         - add VendorElemAdd(), VendorElemGet(), VendorElemRem()
+       * fixed Suite B 192-bit AKM to use proper PMK length
+         (note: this makes old releases incompatible with the fixed behavior)
+       * improved PMF behavior for cases where the AP and STA has different
+         configuration by not trying to connect in some corner cases where the
+         connection cannot succeed
+       * added option to reopen debug log (e.g., to rotate the file) upon
+         receipt of SIGHUP signal
+       * EAP-pwd: added support for Brainpool Elliptic Curves
+         (with OpenSSL 1.0.2 and newer)
+       * fixed EAPOL reauthentication after FT protocol run
+       * fixed FTIE generation for 4-way handshake after FT protocol run
+       * extended INTERFACE_ADD command to allow certain type (sta/ap)
+         interface to be created
+       * fixed and improved various FST operations
+       * added 80+80 MHz and 160 MHz VHT support for IBSS/mesh
+       * fixed SIGNAL_POLL in IBSS and mesh cases
+       * added an option to abort an ongoing scan (used to speed up connection
+         and can also be done with the new ABORT_SCAN command)
+       * TLS client
+         - do not verify CA certificates when ca_cert is not specified
+         - support validating server certificate hash
+         - support SHA384 and SHA512 hashes
+         - add signature_algorithms extension into ClientHello
+         - support TLS v1.2 signature algorithm with SHA384 and SHA512
+         - support server certificate probing
+         - allow specific TLS versions to be disabled with phase2 parameter
+         - support extKeyUsage
+         - support PKCS #5 v2.0 PBES2
+         - support PKCS #5 with PKCS #12 style key decryption
+         - minimal support for PKCS #12
+         - support OCSP stapling (including ocsp_multi)
+       * OpenSSL
+         - support OpenSSL 1.1 API changes
+         - drop support for OpenSSL 0.9.8
+         - drop support for OpenSSL 1.0.0
+       * added support for multiple schedule scan plans (sched_scan_plans)
+       * added support for external server certificate chain validation
+         (tls_ext_cert_check=1 in the network profile phase1 parameter)
+       * made phase2 parser more strict about correct use of auth=<val> and
+         autheap=<val> values
+       * improved GAS offchannel operations with comeback request
+       * added SIGNAL_MONITOR command to request signal strength monitoring
+         events
+       * added command for retrieving HS 2.0 icons with in-memory storage
+         (REQ_HS20_ICON, GET_HS20_ICON, DEL_HS20_ICON commands and
+         RX-HS20-ICON event)
+       * enabled ACS support for AP mode operations with wpa_supplicant
+       * EAP-PEAP: fixed interoperability issue with Windows 2012r2 server
+         ("Invalid Compound_MAC in cryptobinding TLV")
+       * EAP-TTLS: fixed success after fragmented final Phase 2 message
+       * VHT: added interoperability workaround for 80+80 and 160 MHz channels
+       * WNM: workaround for broken AP operating class behavior
+       * added kqueue(2) support for eloop (CONFIG_ELOOP_KQUEUE)
+       * nl80211:
+         - add support for full station state operations
+         - do not add NL80211_ATTR_SMPS_MODE attribute if HT is disabled
+         - add NL80211_ATTR_PREV_BSSID with Connect command
+         - fix IEEE 802.1X/WEP EAP reauthentication and rekeying to use
+           unencrypted EAPOL frames
+       * added initial MBO support; number of extensions to WNM BSS Transition
+         Management
+       * added support for PBSS/PCP and P2P on 60 GHz
+       * Interworking: add credential realm to EAP-TLS identity
+       * fixed EAPOL-Key Request Secure bit to be 1 if PTK is set
+       * HS 2.0: add support for configuring frame filters
+       * added POLL_STA command to check connectivity in AP mode
+       * added initial functionality for location related operations
+       * started to ignore pmf=1/2 parameter for non-RSN networks
+       * added wps_disabled=1 network profile parameter to allow AP mode to
+         be started without enabling WPS
+       * wpa_cli: added action script support for AP-ENABLED and AP-DISABLED
+         events
+       * improved Public Action frame addressing
+         - add gas_address3 configuration parameter to control Address 3
+           behavior
+       * number of small fixes
+
 2015-09-27 - v2.5
        * fixed P2P validation of SSID element length before copying it
          [http://w1.fi/security/2015-1/] (CVE-2015-1863)
index ad9ead9..f3e86c1 100644 (file)
@@ -6,6 +6,17 @@ ifndef CFLAGS
 CFLAGS = -MMD -O2 -Wall -g
 endif
 
+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/
@@ -17,6 +28,16 @@ CFLAGS += -I$(abspath ../src/utils)
 
 -include .config
 
+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
@@ -89,6 +110,7 @@ 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
@@ -149,6 +171,10 @@ 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
@@ -278,14 +304,23 @@ 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
@@ -386,7 +421,6 @@ EAPDYN += ../src/eap_peer/eap_tls.so
 else
 CFLAGS += -DEAP_TLS
 OBJS += ../src/eap_peer/eap_tls.o
-OBJS_h += ../src/eap_server/eap_server_tls.o
 endif
 TLS_FUNCS=y
 CONFIG_IEEE8021X_EAPOL=y
@@ -397,7 +431,6 @@ ifdef CONFIG_EAP_UNAUTH_TLS
 CFLAGS += -DEAP_UNAUTH_TLS
 ifndef CONFIG_EAP_TLS
 OBJS += ../src/eap_peer/eap_tls.o
-OBJS_h += ../src/eap_server/eap_server_tls.o
 TLS_FUNCS=y
 endif
 CONFIG_IEEE8021X_EAPOL=y
@@ -412,7 +445,6 @@ else
 CFLAGS += -DEAP_PEAP
 OBJS += ../src/eap_peer/eap_peap.o
 OBJS += ../src/eap_common/eap_peap_common.o
-OBJS_h += ../src/eap_server/eap_server_peap.o
 endif
 TLS_FUNCS=y
 CONFIG_IEEE8021X_EAPOL=y
@@ -426,7 +458,6 @@ EAPDYN += ../src/eap_peer/eap_ttls.so
 else
 CFLAGS += -DEAP_TTLS
 OBJS += ../src/eap_peer/eap_ttls.o
-OBJS_h += ../src/eap_server/eap_server_ttls.o
 endif
 TLS_FUNCS=y
 ifndef CONFIG_FIPS
@@ -444,7 +475,6 @@ EAPDYN += ../src/eap_peer/eap_md5.so
 else
 CFLAGS += -DEAP_MD5
 OBJS += ../src/eap_peer/eap_md5.o
-OBJS_h += ../src/eap_server/eap_server_md5.o
 endif
 CHAP=y
 CONFIG_IEEE8021X_EAPOL=y
@@ -467,7 +497,6 @@ else
 CFLAGS += -DEAP_MSCHAPv2
 OBJS += ../src/eap_peer/eap_mschapv2.o
 OBJS += ../src/eap_peer/mschapv2.o
-OBJS_h += ../src/eap_server/eap_server_mschapv2.o
 endif
 MS_FUNCS=y
 CONFIG_IEEE8021X_EAPOL=y
@@ -481,7 +510,6 @@ EAPDYN += ../src/eap_peer/eap_gtc.so
 else
 CFLAGS += -DEAP_GTC
 OBJS += ../src/eap_peer/eap_gtc.o
-OBJS_h += ../src/eap_server/eap_server_gtc.o
 endif
 CONFIG_IEEE8021X_EAPOL=y
 endif
@@ -506,7 +534,6 @@ EAPDYN += ../src/eap_peer/eap_sim.so
 else
 CFLAGS += -DEAP_SIM
 OBJS += ../src/eap_peer/eap_sim.o
-OBJS_h += ../src/eap_server/eap_server_sim.o
 endif
 CONFIG_IEEE8021X_EAPOL=y
 CONFIG_EAP_SIM_COMMON=y
@@ -534,7 +561,6 @@ EAPDYN += ../src/eap_peer/eap_psk.so
 else
 CFLAGS += -DEAP_PSK
 OBJS += ../src/eap_peer/eap_psk.o ../src/eap_common/eap_psk_common.o
-OBJS_h += ../src/eap_server/eap_server_psk.o
 endif
 CONFIG_IEEE8021X_EAPOL=y
 NEED_AES=y
@@ -551,7 +577,6 @@ EAPDYN += ../src/eap_peer/eap_aka.so
 else
 CFLAGS += -DEAP_AKA
 OBJS += ../src/eap_peer/eap_aka.o
-OBJS_h += ../src/eap_server/eap_server_aka.o
 endif
 CONFIG_IEEE8021X_EAPOL=y
 CONFIG_EAP_SIM_COMMON=y
@@ -577,7 +602,6 @@ endif
 
 ifdef CONFIG_EAP_SIM_COMMON
 OBJS += ../src/eap_common/eap_sim_common.o
-OBJS_h += ../src/eap_server/eap_sim_db.o
 NEED_AES=y
 NEED_FIPS186_2_PRF=y
 endif
@@ -592,7 +616,6 @@ else
 CFLAGS += -DEAP_FAST
 OBJS += ../src/eap_peer/eap_fast.o ../src/eap_peer/eap_fast_pac.o
 OBJS += ../src/eap_common/eap_fast_common.o
-OBJS_h += ../src/eap_server/eap_server_fast.o
 endif
 TLS_FUNCS=y
 CONFIG_IEEE8021X_EAPOL=y
@@ -607,7 +630,6 @@ EAPDYN += ../src/eap_peer/eap_pax.so
 else
 CFLAGS += -DEAP_PAX
 OBJS += ../src/eap_peer/eap_pax.o ../src/eap_common/eap_pax_common.o
-OBJS_h += ../src/eap_server/eap_server_pax.o
 endif
 CONFIG_IEEE8021X_EAPOL=y
 endif
@@ -620,7 +642,6 @@ EAPDYN += ../src/eap_peer/eap_sake.so
 else
 CFLAGS += -DEAP_SAKE
 OBJS += ../src/eap_peer/eap_sake.o ../src/eap_common/eap_sake_common.o
-OBJS_h += ../src/eap_server/eap_server_sake.o
 endif
 CONFIG_IEEE8021X_EAPOL=y
 endif
@@ -633,7 +654,6 @@ EAPDYN += ../src/eap_peer/eap_gpsk.so
 else
 CFLAGS += -DEAP_GPSK
 OBJS += ../src/eap_peer/eap_gpsk.o ../src/eap_common/eap_gpsk_common.o
-OBJS_h += ../src/eap_server/eap_server_gpsk.o
 endif
 CONFIG_IEEE8021X_EAPOL=y
 ifdef CONFIG_EAP_GPSK_SHA256
@@ -646,7 +666,6 @@ endif
 ifdef CONFIG_EAP_PWD
 CFLAGS += -DEAP_PWD
 OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o
-OBJS_h += ../src/eap_server/eap_server_pwd.o
 CONFIG_IEEE8021X_EAPOL=y
 NEED_SHA256=y
 endif
@@ -659,7 +678,6 @@ EAPDYN += ../src/eap_peer/eap_eke.so
 else
 CFLAGS += -DEAP_EKE
 OBJS += ../src/eap_peer/eap_eke.o ../src/eap_common/eap_eke_common.o
-OBJS_h += ../src/eap_server/eap_server_eke.o
 endif
 CONFIG_IEEE8021X_EAPOL=y
 NEED_DH_GROUPS=y
@@ -682,7 +700,6 @@ 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
-OBJS_h += ../src/eap_server/eap_server_wsc.o
 CONFIG_IEEE8021X_EAPOL=y
 NEED_DH_GROUPS=y
 NEED_SHA256=y
@@ -745,8 +762,6 @@ else
 CFLAGS += -DEAP_IKEV2
 OBJS += ../src/eap_peer/eap_ikev2.o ../src/eap_peer/ikev2.o
 OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o
-OBJS_h += ../src/eap_server/eap_server_ikev2.o
-OBJS_h += ../src/eap_server/ikev2.o
 endif
 CONFIG_IEEE8021X_EAPOL=y
 NEED_DH_GROUPS=y
@@ -762,7 +777,6 @@ EAPDYN += ../src/eap_peer/eap_vendor_test.so
 else
 CFLAGS += -DEAP_VENDOR_TEST
 OBJS += ../src/eap_peer/eap_vendor_test.o
-OBJS_h += ../src/eap_server/eap_server_vendor_test.o
 endif
 CONFIG_IEEE8021X_EAPOL=y
 endif
@@ -772,8 +786,6 @@ ifdef CONFIG_EAP_TNC
 CFLAGS += -DEAP_TNC
 OBJS += ../src/eap_peer/eap_tnc.o
 OBJS += ../src/eap_peer/tncc.o
-OBJS_h += ../src/eap_server/eap_server_tnc.o
-OBJS_h += ../src/eap_server/tncs.o
 NEED_BASE64=y
 ifndef CONFIG_NATIVE_WINDOWS
 ifndef CONFIG_DRIVER_BSD
@@ -833,6 +845,8 @@ 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
 ifdef CONFIG_IEEE80211N
 OBJS += ../src/ap/ieee802_11_ht.o
 ifdef CONFIG_IEEE80211AC
@@ -842,6 +856,9 @@ endif
 ifdef CONFIG_WNM
 OBJS += ../src/ap/wnm_ap.o
 endif
+ifdef CONFIG_MBO
+OBJS += ../src/ap/mbo_ap.o
+endif
 ifdef CONFIG_CTRL_IFACE
 OBJS += ../src/ap/ctrl_iface_ap.o
 endif
@@ -858,6 +875,11 @@ CFLAGS += -DCONFIG_IEEE80211AC
 endif
 endif
 
+ifdef CONFIG_MBO
+OBJS += mbo.o
+CFLAGS += -DCONFIG_MBO
+endif
+
 ifdef NEED_AP_MLME
 OBJS += ../src/ap/wmm.o
 OBJS += ../src/ap/ap_list.o
@@ -893,34 +915,10 @@ OBJS += ../src/ap/peerkey_auth.o
 endif
 endif
 
-ifdef CONFIG_EAP_SERVER
-CFLAGS += -DEAP_SERVER
-OBJS_h += ../src/eap_server/eap_server.o
-OBJS_h += ../src/eap_server/eap_server_identity.o
-OBJS_h += ../src/eap_server/eap_server_methods.o
-endif
-
-ifdef CONFIG_RADIUS_CLIENT
-OBJS_h += ../src/utils/ip_addr.o
-OBJS_h += ../src/radius/radius.o
-OBJS_h += ../src/radius/radius_client.o
-endif
-
-ifdef CONFIG_AUTHENTICATOR
-OBJS_h += ../src/eapol_auth/eapol_auth_sm.o
-OBJS_h += ../src/ap/ieee802_1x.o
-endif
-
-ifdef CONFIG_WPA_AUTHENTICATOR
-OBJS_h += ../src/ap/wpa_auth.o
-OBJS_h += ../src/ap/wpa_auth_ie.o
-OBJS_h += ../src/ap/pmksa_cache_auth.o
-ifdef CONFIG_IEEE80211R
-OBJS_h += ../src/ap/wpa_auth_ft.o
-endif
-ifdef CONFIG_PEERKEY
-OBJS_h += ../src/ap/peerkey_auth.o
-endif
+ifdef CONFIG_ACS
+CFLAGS += -DCONFIG_ACS
+OBJS += ../src/ap/acs.o
+LIBS += -lm
 endif
 
 ifdef CONFIG_PCSC
@@ -933,9 +931,13 @@ ifdef CONFIG_NATIVE_WINDOWS
 #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
@@ -974,7 +976,6 @@ ifdef TLS_FUNCS
 NEED_DES=y
 # Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST)
 OBJS += ../src/eap_peer/eap_tls_common.o
-OBJS_h += ../src/eap_server/eap_server_tls_common.o
 ifndef CONFIG_FIPS
 NEED_TLS_PRF=y
 NEED_SHA1=y
@@ -999,6 +1000,7 @@ 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
@@ -1049,6 +1051,7 @@ 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/asn1.o
 OBJS += ../src/tls/rsa.o
 OBJS += ../src/tls/x509v3.o
@@ -1102,6 +1105,8 @@ 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
@@ -1287,10 +1292,19 @@ 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_HMAC_SHA256_KDF
+CFLAGS += -DCONFIG_HMAC_SHA256_KDF
 OBJS += ../src/crypto/sha256-kdf.o
 endif
 OBJS += $(SHA256OBJS)
@@ -1333,6 +1347,7 @@ 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
@@ -1374,6 +1389,7 @@ ifndef DBUS_INCLUDE
 DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
 endif
 DBUS_CFLAGS += $(DBUS_INCLUDE)
+DBUS_INTERFACE=fi.epitest.hostap.WPASupplicant
 endif
 
 ifdef CONFIG_CTRL_IFACE_DBUS_NEW
@@ -1399,6 +1415,7 @@ DBUS_OBJS += dbus/dbus_new_introspect.o
 DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
 endif
 DBUS_CFLAGS += $(DBUS_INCLUDE)
+DBUS_INTERFACE=fi.w1.wpa_supplicant1
 endif
 
 ifdef DBUS
@@ -1412,7 +1429,7 @@ LIBS += $(DBUS_LIBS)
 
 ifdef CONFIG_READLINE
 OBJS_c += ../src/utils/edit_readline.o
-LIBS_c += -lncurses -lreadline
+LIBS_c += -lreadline -lncurses
 else
 ifdef CONFIG_WPA_CLI_EDIT
 OBJS_c += ../src/utils/edit.o
@@ -1443,6 +1460,10 @@ ifdef CONFIG_IPV6
 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
@@ -1569,12 +1590,6 @@ endif
 OBJS += ../src/drivers/driver_common.o
 OBJS_priv += ../src/drivers/driver_common.o
 
-OBJS_wpa_rm := ctrl_iface.o ctrl_iface_unix.o
-OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.o
-ifdef CONFIG_AUTHENTICATOR
-OBJS_wpa += tests/link_test.o
-endif
-OBJS_wpa += $(OBJS_l2)
 OBJS += wpa_supplicant.o events.o blacklist.o wpas_glue.o scan.o
 OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.o
 OBJS_t += ../src/radius/radius_client.o
@@ -1636,6 +1651,7 @@ endif
 OBJS += $(FST_OBJS)
 OBJS_t += $(FST_OBJS)
 OBJS_t2 += $(FST_OBJS)
+OBJS_nfc += $(FST_OBJS)
 endif
 
 ifndef LDO
@@ -1691,9 +1707,11 @@ wpa_cli: $(OBJS_c)
 
 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
 
 libwpa_client.a: $(LIBCTRL)
@@ -1705,12 +1723,12 @@ libwpa_client.so: $(LIBCTRLSO)
        @$(E) "  CC  $@ ($^)"
        $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -fPIC $^
 
-link_test: $(OBJS) $(OBJS_h) tests/link_test.o
-       $(Q)$(LDO) $(LDFLAGS) -o link_test $(OBJS) $(OBJS_h) tests/link_test.o $(LIBS)
+libwpa_test1: libwpa_test.o libwpa_client.a
+       $(Q)$(LDO) $(LDFLAGS) -o libwpa_test1 libwpa_test.o libwpa_client.a $(LIBS_c)
        @$(E) "  LD " $@
 
-test_wpa: $(OBJS_wpa) $(OBJS_h)
-       $(Q)$(LDO) $(LDFLAGS) -o test_wpa $(OBJS_wpa) $(LIBS)
+libwpa_test2: libwpa_test.o libwpa_client.so
+       $(Q)$(LDO) $(LDFLAGS) -o libwpa_test2 libwpa_test.o -L. -lwpa_client $(LIBS_c)
        @$(E) "  LD " $@
 
 nfc_pw_token: $(OBJS_nfc)
@@ -1760,11 +1778,13 @@ else
 endif
 
 %.service: %.service.in
-       $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+       $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' \
+               -e 's|\@DBUS_INTERFACE\@|$(DBUS_INTERFACE)|g' $< >$@
        @$(E) "  sed" $<
 
 %@.service: %.service.arg.in
-       $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+       $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' \
+               -e 's|\@DBUS_INTERFACE\@|$(DBUS_INTERFACE)|g' $< >$@
        @$(E) "  sed" $<
 
 wpa_supplicant.exe: wpa_supplicant
@@ -1795,17 +1815,6 @@ wpa_gui-qt4/lang/wpa_gui_de.qm: wpa_gui-qt4/lang/wpa_gui_de.ts
 wpa_gui-qt4: wpa_gui-qt4/Makefile wpa_gui-qt4/lang/wpa_gui_de.qm
        $(MAKE) -C wpa_gui-qt4
 
-TEST_EAP_SIM_COMMON_OBJS = $(SHA1OBJS) $(MD5OBJS) \
-       ../src/utils/common.o ../src/utils/os_unix.o \
-       ../src/utils/wpa_debug.o $(AESOBJS) \
-       tests/test_eap_sim_common.o
-test-eap_sim_common: $(TEST_EAP_SIM_COMMON_OBJS)
-       $(LDO) $(LDFLAGS) -o $@ $(TEST_EAP_SIM_COMMON_OBJS) $(LIBS)
-       ./test-eap_sim_common
-       rm test-eap_sim_common
-
-tests: test-eap_sim_common
-
 FIPSDIR=/usr/local/ssl/fips-2.0
 FIPSLD=$(FIPSDIR)/bin/fipsld
 fips:
@@ -1826,5 +1835,6 @@ clean:
        rm -rf lcov-html
        rm -f libwpa_client.a
        rm -f libwpa_client.so
+       rm -f libwpa_test1 libwpa_test2
 
 -include $(OBJS:%.o=%.d)
index f9c65d2..11ab01a 100644 (file)
@@ -1,7 +1,7 @@
 WPA Supplicant
 ==============
 
-Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
 This program is licensed under the BSD license (the one with
@@ -72,11 +72,13 @@ Supported WPA/IEEE 802.11i features:
   * EAP-TTLS/CHAP
   * EAP-SIM
   * EAP-AKA
+  * EAP-AKA'
   * EAP-PSK
   * EAP-PAX
   * EAP-SAKE
   * EAP-IKEv2
   * EAP-GPSK
+  * EAP-pwd
   * LEAP (note: requires special support from the driver for IEEE 802.11
          authentication)
   (following methods are supported, but since they do not generate keying
@@ -163,18 +165,12 @@ systems. In case of Windows builds, WinPcap is used by default
 
 
 Optional libraries for EAP-TLS, EAP-PEAP, and EAP-TTLS:
-- OpenSSL (tested with 0.9.7c and 0.9.7d, and 0.9.8 versions; assumed to
+- OpenSSL (tested with 1.0.1 and 1.0.2 versions; assumed to
   work with most relatively recent versions; this is likely to be
   available with most distributions, http://www.openssl.org/)
 - GnuTLS
 - internal TLSv1 implementation
 
-TLS options for EAP-FAST:
-- OpenSSL 0.9.8d _with_ openssl-0.9.8d-tls-extensions.patch applied
-  (i.e., the default OpenSSL package does not include support for
-  extensions needed for EAP-FAST)
-- internal TLSv1 implementation
-
 One of these libraries is needed when EAP-TLS, EAP-PEAP, EAP-TTLS, or
 EAP-FAST support is enabled. WPA-PSK mode does not require this or EAPOL/EAP
 implementation. A configuration file, .config, for compilation is
@@ -308,7 +304,7 @@ Following build time configuration options are used to control IEEE
 802.1X/EAPOL and EAP state machines and all EAP methods. Including
 TLS, PEAP, or TTLS will require linking wpa_supplicant with OpenSSL
 library for TLS implementation. Alternatively, GnuTLS or the internal
-TLSv1 implementation can be used for TLS functionaly.
+TLSv1 implementation can be used for TLS functionality.
 
 CONFIG_IEEE8021X_EAPOL=y
 CONFIG_EAP_MD5=y
@@ -320,15 +316,17 @@ CONFIG_EAP_GTC=y
 CONFIG_EAP_OTP=y
 CONFIG_EAP_SIM=y
 CONFIG_EAP_AKA=y
+CONFIG_EAP_AKA_PRIME=y
 CONFIG_EAP_PSK=y
 CONFIG_EAP_SAKE=y
 CONFIG_EAP_GPSK=y
 CONFIG_EAP_PAX=y
 CONFIG_EAP_LEAP=y
 CONFIG_EAP_IKEV2=y
+CONFIG_EAP_PWD=y
 
 Following option can be used to include GSM SIM/USIM interface for GSM/UMTS
-authentication algorithm (for EAP-SIM/EAP-AKA). This requires pcsc-lite
+authentication algorithm (for EAP-SIM/EAP-AKA/EAP-AKA'). This requires pcsc-lite
 (http://www.linuxnet.com/) for smart card access.
 
 CONFIG_PCSC=y
@@ -409,10 +407,10 @@ Command line options
 --------------------
 
 usage:
-  wpa_supplicant [-BddfhKLqqtuvwW] [-P<pid file>] [-g<global ctrl>] \
+  wpa_supplicant [-BddfhKLqqtuvW] [-P<pid file>] [-g<global ctrl>] \
         [-G<group>] \
         -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \
-        [-b<br_ifname> [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
+        [-b<br_ifname> [-MN -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
         [-p<driver_param>] [-b<br_ifname>] [-m<P2P Device config file>] ...
 
 options:
@@ -435,8 +433,8 @@ options:
   -q = decrease debugging verbosity (-qq even less)
   -u = enable DBus control interface
   -v = show version
-  -w = wait for interface to be added, if needed
   -W = wait for a control interface monitor before starting
+  -M = start describing matching interface
   -N = start describing new interface
   -m = Configuration file for the P2P Device
 
@@ -479,6 +477,22 @@ wpa_supplicant \
        -c wpa2.conf -i wlan1 -D wext
 
 
+If the interfaces on which wpa_supplicant is to run are not known or do
+not exist, wpa_supplicant can match an interface when it arrives. Each
+matched interface is separated with -M argument and the -i argument now
+allows for pattern matching.
+
+As an example, the following command would start wpa_supplicant for a
+specific wired interface called lan0, any interface starting with wlan
+and lastly any other interface. Each match has its own configuration
+file, and for the wired interface a specific driver has also been given.
+
+wpa_supplicant \
+       -M -c wpa_wired.conf -ilan0 -D wired \
+       -M -c wpa1.conf -iwlan* \
+       -M -c wpa2.conf
+
+
 If the interface is added in a Linux bridge (e.g., br0), the bridge
 interface needs to be configured to wpa_supplicant in addition to the
 main interface:
@@ -500,7 +514,7 @@ reloading can be triggered with 'wpa_cli reconfigure' command.
 
 Configuration file can include one or more network blocks, e.g., one
 for each used SSID. wpa_supplicant will automatically select the best
-betwork based on the order of network blocks in the configuration
+network based on the order of network blocks in the configuration
 file, network security level (WPA/WPA2 is preferred), and signal
 strength.
 
@@ -792,7 +806,7 @@ addresses, etc.
 
 One wpa_cli process in "action" mode needs to be started for each
 interface. For example, the following command starts wpa_cli for the
-default ingterface (-i can be used to select the interface in case of
+default interface (-i can be used to select the interface in case of
 more than one interface being used at the same time):
 
 wpa_cli -a/sbin/wpa_action.sh -B
@@ -1008,8 +1022,8 @@ event message is indicated that the external processing can start. Once
 the operation has been completed, "RADIO_WORK done <id>" is used to
 indicate that to wpa_supplicant. This allows other radio works to be
 performed. If this command is forgotten (e.g., due to the external
-program terminating), wpa_supplicant will time out the radio owrk item
-and send "EXT-RADIO-WORK-TIMEOUT <id>" event ot indicate that this has
+program terminating), wpa_supplicant will time out the radio work item
+and send "EXT-RADIO-WORK-TIMEOUT <id>" event to indicate that this has
 happened. "RADIO_WORK done <id>" can also be used to cancel items that
 have not yet been started.
 
index 161dc06..e4eed20 100644 (file)
@@ -229,7 +229,7 @@ Credentials can be pre-configured for automatic network selection:
 #
 # sp_priority: Credential priority within a provisioning SP
 #      This is the priority of the credential among all credentials
-#      provisionined by the same SP (i.e., for entries that have identical
+#      provisioned by the same SP (i.e., for entries that have identical
 #      provisioning_sp value). The range of this priority is 0-255 with 0
 #      being the highest and 255 the lower priority.
 #
@@ -564,3 +564,68 @@ OK
 <3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
 <3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
 <3>ANQP fetch completed
+
+
+Hotspot 2.0 Rel 2 online signup and OSEN
+----------------------------------------
+
+Following parameters can be used to create a network profile for
+link-layer protected Hotspot 2.0 online signup connection with
+OSEN. Note that ssid and identify (NAI) values need to be set based on
+the information for the selected provider in the OSU Providers list
+ANQP-element.
+
+network={
+    ssid="HS 2.0 OSU"
+    proto=OSEN
+    key_mgmt=OSEN
+    pairwise=CCMP
+    group=GTK_NOT_USED
+    eap=WFA-UNAUTH-TLS
+    identity="anonymous@example.com"
+    ca_cert="osu-ca.pem"
+    ocsp=2
+}
+
+
+Hotspot 2.0 connection with external network selection
+------------------------------------------------------
+
+When an component controlling wpa_supplicant takes care of Interworking
+network selection, following configuration and network profile
+parameters can be used to configure a temporary network profile for a
+Hotspot 2.0 connection (e.g., with SET, ADD_NETWORK, SET_NETWORK, and
+SELECT_NETWORK control interface commands):
+
+interworking=1
+hs20=1
+auto_interworking=0
+
+network={
+    ssid="test-hs20"
+    proto=RSN
+    key_mgmt=WPA-EAP
+    pairwise=CCMP
+    anonymous_identity="anonymous@example.com"
+    identity="hs20-test@example.com"
+    password="password"
+    ca_cert="ca.pem"
+    eap=TTLS
+    phase2="auth=MSCHAPV2"
+    update_identifier=54321
+    #ocsp=2
+}
+
+
+These parameters are set based on the PPS MO credential and/or NAI Realm
+list ANQP-element:
+
+anonymous_identity: Credential/UsernamePassword/Username with username part
+                   replaced with "anonymous"
+identity: Credential/UsernamePassword/Username
+password: Credential/UsernamePassword/Password
+update_identifier: PPS/UpdateIdentifier
+ca_cert: from the downloaded trust root based on PPS information
+eap: Credential/UsernamePassword/EAPMethod or NAI Realm list
+phase2: Credential/UsernamePassword/EAPMethod or NAI Realm list
+ocsp: Credential/CheckAAAServerCertStatus
index 6a5b032..23ac7fa 100644 (file)
@@ -151,6 +151,7 @@ join-a-group style PD instead of GO Negotiation style PD.
 p2p_connect <peer device address> <pbc|pin|PIN#|p2ps> [display|keypad|p2ps]
        [persistent|persistent=<network id>] [join|auth]
        [go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [provdisc] [auto]
+       [ssid=<hexdump>]
 
 Start P2P group formation with a discovered P2P peer. This includes
 optional group owner negotiation, group interface setup, provisioning,
@@ -195,11 +196,17 @@ connection.
 out whether the peer device is operating as a GO and if so, use
 join-a-group operation rather than GO Negotiation.
 
+"ssid=<hexdump>" can be used to specify the Group SSID for join
+operations. This allows the P2P Client interface to filter scan results
+based on SSID to avoid selecting an incorrect BSS entry in case the same
+P2P Device or Interface address have been used in multiple groups
+recently.
+
 P2PS attribute changes to p2p_connect command:
 
 P2PS supports two WPS provisioning methods namely PIN method and P2PS default.
-The remaining paramters hold same role as in legacy P2P. In case of P2PS default
-config method "p2ps" keyword is added in p2p_connect command.
+The remaining parameters hold same role as in legacy P2P. In case of P2PS
+default config method "p2ps" keyword is added in p2p_connect command.
 
 For example:
 p2p_connect 02:0a:f5:85:11:00 12345670 p2ps persistent join
@@ -281,7 +288,7 @@ group interface is used as a parameter for this command.
 p2p_cancel
 
 Cancel an ongoing P2P group formation and joining-a-group related
-operation. This operations unauthorizes the specific peer device (if any
+operation. This operation unauthorizes the specific peer device (if any
 had been authorized to start group formation), stops P2P find (if in
 progress), stops pending operations for join-a-group, and removes the
 P2P group interface (if one was used) that is in the WPS provisioning
@@ -633,12 +640,17 @@ p2p_set managed <0/1>
 Disable/enable managed P2P Device operations. This is disabled by
 default.
 
-p2p_set listen_channel <1/6/11>
+p2p_set listen_channel <channel> [<op_class>]
 
 Set P2P Listen channel. This is mainly meant for testing purposes and
 changing the Listen channel during normal operations can result in
 protocol failures.
 
+When specifying a social channel on the 2.4 GHz band (1/6/11) there is
+no need to specify the operating class since it defaults to 81.  When
+specifying a social channel on the 60 GHz band (2), specify the 60 GHz
+operating class (180).
+
 p2p_set ssid_postfix <postfix>
 
 Set postfix string to be added to the automatically generated P2P SSID
@@ -650,7 +662,7 @@ p2p_set per_sta_psk <0/1>
 Disabled(default)/enables use of per-client PSK in the P2P groups. This
 can be used to request GO to assign a unique PSK for each client during
 WPS provisioning. When enabled, this allow clients to be removed from
-the group securily with p2p_remove_client command since that client's
+the group securely with p2p_remove_client command since that client's
 PSK is removed at the same time to prevent it from connecting back using
 the old PSK. When per-client PSK is not used, the client can still be
 disconnected, but it will be able to re-join the group since the PSK it
index 6c3ee6d..02505bb 100644 (file)
@@ -32,6 +32,9 @@
 #CONFIG_DRIVER_NL80211=y
 CONFIG_LIBNL20=y
 
+# QCA vendor extensions to nl80211
+CONFIG_DRIVER_NL80211_QCA=y
+
 # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
 #CONFIG_DRIVER_BSD=y
 #CFLAGS += -I/usr/local/include
@@ -92,7 +95,7 @@ CONFIG_EAP_TTLS=y
 # functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
 # the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch)
 # to add the needed functions.
-CONFIG_EAP_FAST=y
+#CONFIG_EAP_FAST=y
 
 # EAP-GTC
 CONFIG_EAP_GTC=y
@@ -321,6 +324,10 @@ CONFIG_IEEE80211W=y
 # Add introspection support for new DBus control interface
 #CONFIG_CTRL_IFACE_DBUS_INTRO=y
 
+# Add support for Binder control interface
+# Only applicable for Android platforms.
+#CONFIG_CTRL_IFACE_BINDER=y
+
 # Add support for loading EAP methods dynamically as shared libraries.
 # When this option is enabled, each EAP method can be either included
 # statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn).
@@ -479,4 +486,7 @@ CONFIG_WIFI_DISPLAY=y
 # Enable Fast Session Transfer (FST)
 #CONFIG_FST=y
 
+# Support Multi Band Operation
+#CONFIG_MBO=y
+
 include $(wildcard $(LOCAL_PATH)/android_config_*.inc)
index 7a4f4cf..5afb772 100644 (file)
@@ -56,12 +56,32 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
        if (!conf->secondary_channel)
                goto no_vht;
 
-       center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
+       switch (conf->vht_oper_chwidth) {
+       case VHT_CHANWIDTH_80MHZ:
+       case VHT_CHANWIDTH_80P80MHZ:
+               center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
+               break;
+       case VHT_CHANWIDTH_160MHZ:
+               center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
+               break;
+       default:
+               /*
+                * conf->vht_oper_chwidth might not be set for non-P2P GO cases,
+                * try oper_cwidth 160 MHz first then VHT 80 MHz, if 160 MHz is
+                * not supported.
+                */
+               conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ;
+               center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
+               if (!center_chan) {
+                       conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+                       center_chan = wpas_p2p_get_vht80_center(wpa_s, mode,
+                                                               channel);
+               }
+               break;
+       }
        if (!center_chan)
                goto no_vht;
 
-       /* Use 80 MHz channel */
-       conf->vht_oper_chwidth = 1;
        conf->vht_oper_centr_freq_seg0_idx = center_chan;
        return;
 
@@ -72,14 +92,24 @@ no_vht:
        conf->vht_oper_centr_freq_seg0_idx =
                conf->channel + conf->secondary_channel * 2;
 #endif /* CONFIG_P2P */
+       conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
 }
 #endif /* CONFIG_IEEE80211N */
 
 
-void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
-                              struct wpa_ssid *ssid,
-                              struct hostapd_config *conf)
+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);
+
+       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 */
 
@@ -166,6 +196,8 @@ void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
                }
        }
 #endif /* CONFIG_IEEE80211N */
+
+       return 0;
 }
 
 
@@ -179,15 +211,23 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
 
        os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
 
-       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);
+       if (wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf))
+               return -1;
+
+       if (ssid->pbss > 1) {
+               wpa_printf(MSG_ERROR, "Invalid pbss value(%d) for AP mode",
+                          ssid->pbss);
                return -1;
        }
+       bss->pbss = ssid->pbss;
 
-       wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
+#ifdef CONFIG_ACS
+       if (ssid->acs) {
+               /* Setting channel to 0 in order to enable ACS */
+               conf->channel = 0;
+               wpa_printf(MSG_DEBUG, "Use automatic channel selection");
+       }
+#endif /* CONFIG_ACS */
 
        if (ieee80211_is_dfs(ssid->frequency) && wpa_s->conf->country[0]) {
                conf->ieee80211h = 1;
@@ -229,12 +269,12 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
        bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk;
 
        if (ssid->p2p_group) {
-               os_memcpy(bss->ip_addr_go, wpa_s->parent->conf->ip_addr_go, 4);
-               os_memcpy(bss->ip_addr_mask, wpa_s->parent->conf->ip_addr_mask,
+               os_memcpy(bss->ip_addr_go, wpa_s->p2pdev->conf->ip_addr_go, 4);
+               os_memcpy(bss->ip_addr_mask, wpa_s->p2pdev->conf->ip_addr_mask,
                          4);
                os_memcpy(bss->ip_addr_start,
-                         wpa_s->parent->conf->ip_addr_start, 4);
-               os_memcpy(bss->ip_addr_end, wpa_s->parent->conf->ip_addr_end,
+                         wpa_s->p2pdev->conf->ip_addr_start, 4);
+               os_memcpy(bss->ip_addr_end, wpa_s->p2pdev->conf->ip_addr_end,
                          4);
        }
 #endif /* CONFIG_P2P */
@@ -254,7 +294,10 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
 
        if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt))
                bss->wpa = ssid->proto;
-       bss->wpa_key_mgmt = ssid->key_mgmt;
+       if (ssid->key_mgmt == DEFAULT_KEY_MGMT)
+               bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+       else
+               bss->wpa_key_mgmt = ssid->key_mgmt;
        bss->wpa_pairwise = ssid->pairwise_cipher;
        if (ssid->psk_set) {
                bin_clear_free(bss->ssid.wpa_psk, sizeof(*bss->ssid.wpa_psk));
@@ -263,6 +306,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                        return -1;
                os_memcpy(bss->ssid.wpa_psk->psk, ssid->psk, PMK_LEN);
                bss->ssid.wpa_psk->group = 1;
+               bss->ssid.wpa_psk_set = 1;
        } else if (ssid->passphrase) {
                bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
        } else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] ||
@@ -297,13 +341,17 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                conf->beacon_int = wpa_s->conf->beacon_int;
 
 #ifdef CONFIG_P2P
-       if (wpa_s->conf->p2p_go_ctwindow > conf->beacon_int) {
-               wpa_printf(MSG_INFO,
-                          "CTWindow (%d) is bigger than beacon interval (%d) - avoid configuring it",
-                          wpa_s->conf->p2p_go_ctwindow, conf->beacon_int);
-               conf->p2p_go_ctwindow = 0;
-       } else {
-               conf->p2p_go_ctwindow = wpa_s->conf->p2p_go_ctwindow;
+       if (ssid->mode == WPAS_MODE_P2P_GO ||
+           ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
+               if (wpa_s->conf->p2p_go_ctwindow > conf->beacon_int) {
+                       wpa_printf(MSG_INFO,
+                                  "CTWindow (%d) is bigger than beacon interval (%d) - avoid configuring it",
+                                  wpa_s->conf->p2p_go_ctwindow,
+                                  conf->beacon_int);
+                       conf->p2p_go_ctwindow = 0;
+               } else {
+                       conf->p2p_go_ctwindow = wpa_s->conf->p2p_go_ctwindow;
+               }
        }
 #endif /* CONFIG_P2P */
 
@@ -372,6 +420,8 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
             !(bss->wpa & 2)))
                goto no_wps; /* WPS2 does not allow WPA/TKIP-only
                              * configuration */
+       if (ssid->wps_disabled)
+               goto no_wps;
        bss->eap_server = 1;
 
        if (!ssid->ignore_broadcast_ssid)
@@ -400,6 +450,8 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                os_memcpy(bss->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
        os_memcpy(bss->os_version, wpa_s->conf->os_version, 4);
        bss->pbc_in_m1 = wpa_s->conf->pbc_in_m1;
+       if (ssid->eap.fragment_size != DEFAULT_FRAGMENT_SIZE)
+               bss->fragment_size = ssid->eap.fragment_size;
 no_wps:
 #endif /* CONFIG_WPS */
 
@@ -416,6 +468,9 @@ no_wps:
                        wpabuf_dup(wpa_s->conf->ap_vendor_elements);
        }
 
+       bss->ftm_responder = wpa_s->conf->ftm_responder;
+       bss->ftm_initiator = wpa_s->conf->ftm_initiator;
+
        return 0;
 }
 
@@ -448,14 +503,14 @@ static void ap_wps_event_cb(void *ctx, enum wps_event event,
        if (event == WPS_EV_FAIL) {
                struct wps_event_fail *fail = &data->fail;
 
-               if (wpa_s->parent && wpa_s->parent != wpa_s &&
+               if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s &&
                    wpa_s == wpa_s->global->p2p_group_formation) {
                        /*
                         * src/ap/wps_hostapd.c has already sent this on the
                         * main interface, so only send on the parent interface
                         * here if needed.
                         */
-                       wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+                       wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL
                                "msg=%d config_error=%d",
                                fail->msg, fail->config_error);
                }
@@ -530,6 +585,11 @@ static void wpas_ap_configured_cb(void *ctx)
 {
        struct wpa_supplicant *wpa_s = ctx;
 
+#ifdef CONFIG_ACS
+       if (wpa_s->current_ssid && wpa_s->current_ssid->acs)
+               wpa_s->assoc_freq = wpa_s->ap_iface->freq;
+#endif /* CONFIG_ACS */
+
        wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
 
        if (wpa_s->ap_configured_cb)
@@ -595,8 +655,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                params.p2p = 1;
 #endif /* CONFIG_P2P */
 
-       if (wpa_s->parent->set_ap_uapsd)
-               params.uapsd = wpa_s->parent->ap_uapsd;
+       if (wpa_s->p2pdev->set_ap_uapsd)
+               params.uapsd = wpa_s->p2pdev->ap_uapsd;
        else if (params.p2p && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
                params.uapsd = 1; /* mandatory for P2P GO */
        else
@@ -605,12 +665,17 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
        if (ieee80211_is_dfs(params.freq.freq))
                params.freq.freq = 0; /* set channel after CAC */
 
+       if (params.p2p)
+               wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_GO);
+       else
+               wpa_drv_get_ext_capa(wpa_s, WPA_IF_AP_BSS);
+
        if (wpa_drv_associate(wpa_s, &params) < 0) {
                wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
                return -1;
        }
 
-       wpa_s->ap_iface = hapd_iface = os_zalloc(sizeof(*wpa_s->ap_iface));
+       wpa_s->ap_iface = hapd_iface = hostapd_alloc_iface();
        if (hapd_iface == NULL)
                return -1;
        hapd_iface->owner = wpa_s;
@@ -627,6 +692,13 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
+       /* Use the maximum oper channel width if it's given. */
+       if (ssid->max_oper_chwidth)
+               conf->vht_oper_chwidth = ssid->max_oper_chwidth;
+
+       ieee80211_freq_to_chan(ssid->vht_center_freq2,
+                              &conf->vht_oper_centr_freq_seg1_idx);
+
        os_memcpy(wpa_s->ap_iface->conf->wmm_ac_params,
                  wpa_s->conf->wmm_ac_params,
                  sizeof(wpa_s->conf->wmm_ac_params));
@@ -668,7 +740,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                }
 
                hapd_iface->bss[i]->msg_ctx = wpa_s;
-               hapd_iface->bss[i]->msg_ctx_parent = wpa_s->parent;
+               hapd_iface->bss[i]->msg_ctx_parent = wpa_s->p2pdev;
                hapd_iface->bss[i]->public_action_cb = ap_public_action_rx;
                hapd_iface->bss[i]->public_action_cb_ctx = wpa_s;
                hapd_iface->bss[i]->vendor_action_cb = ap_vendor_action_rx;
@@ -864,7 +936,10 @@ int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
                return -1;
 
        if (pin == NULL) {
-               unsigned int rpin = wps_generate_pin();
+               unsigned int rpin;
+
+               if (wps_generate_pin(&rpin) < 0)
+                       return -1;
                ret_len = os_snprintf(buf, buflen, "%08d", rpin);
                if (os_snprintf_error(buflen, ret_len))
                        return -1;
@@ -930,7 +1005,8 @@ const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout)
        if (wpa_s->ap_iface == NULL)
                return NULL;
        hapd = wpa_s->ap_iface->bss[0];
-       pin = wps_generate_pin();
+       if (wps_generate_pin(&pin) < 0)
+               return NULL;
        os_snprintf(pin_txt, sizeof(pin_txt), "%08u", pin);
        os_free(hapd->conf->ap_pin);
        hapd->conf->ap_pin = os_strdup(pin_txt);
@@ -1265,8 +1341,8 @@ int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
        hapd = wpa_s->ap_iface->bss[0];
        wps = hapd->wps;
 
-       if (wpa_s->parent->conf->wps_nfc_dh_pubkey == NULL ||
-           wpa_s->parent->conf->wps_nfc_dh_privkey == NULL) {
+       if (wpa_s->p2pdev->conf->wps_nfc_dh_pubkey == NULL ||
+           wpa_s->p2pdev->conf->wps_nfc_dh_privkey == NULL) {
                wpa_printf(MSG_DEBUG, "P2P: No NFC DH key known");
                return -1;
        }
@@ -1275,9 +1351,9 @@ int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
        wpabuf_free(wps->dh_pubkey);
        wpabuf_free(wps->dh_privkey);
        wps->dh_privkey = wpabuf_dup(
-               wpa_s->parent->conf->wps_nfc_dh_privkey);
+               wpa_s->p2pdev->conf->wps_nfc_dh_privkey);
        wps->dh_pubkey = wpabuf_dup(
-               wpa_s->parent->conf->wps_nfc_dh_pubkey);
+               wpa_s->p2pdev->conf->wps_nfc_dh_pubkey);
        if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) {
                wps->dh_ctx = NULL;
                wpabuf_free(wps->dh_pubkey);
@@ -1308,6 +1384,58 @@ int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s)
        hapd = wpa_s->ap_iface->bss[0];
        return hostapd_ctrl_iface_stop_ap(hapd);
 }
+
+
+int wpas_ap_pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf,
+                            size_t len)
+{
+       size_t reply_len = 0, i;
+       char ap_delimiter[] = "---- AP ----\n";
+       char mesh_delimiter[] = "---- mesh ----\n";
+       size_t dlen;
+
+       if (wpa_s->ap_iface) {
+               dlen = os_strlen(ap_delimiter);
+               if (dlen > len - reply_len)
+                       return reply_len;
+               os_memcpy(&buf[reply_len], ap_delimiter, dlen);
+               reply_len += dlen;
+
+               for (i = 0; i < wpa_s->ap_iface->num_bss; i++) {
+                       reply_len += hostapd_ctrl_iface_pmksa_list(
+                               wpa_s->ap_iface->bss[i],
+                               &buf[reply_len], len - reply_len);
+               }
+       }
+
+       if (wpa_s->ifmsh) {
+               dlen = os_strlen(mesh_delimiter);
+               if (dlen > len - reply_len)
+                       return reply_len;
+               os_memcpy(&buf[reply_len], mesh_delimiter, dlen);
+               reply_len += dlen;
+
+               reply_len += hostapd_ctrl_iface_pmksa_list(
+                       wpa_s->ifmsh->bss[0], &buf[reply_len],
+                       len - reply_len);
+       }
+
+       return reply_len;
+}
+
+
+void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s)
+{
+       size_t i;
+
+       if (wpa_s->ap_iface) {
+               for (i = 0; i < wpa_s->ap_iface->num_bss; i++)
+                       hostapd_ctrl_iface_pmksa_flush(wpa_s->ap_iface->bss[i]);
+       }
+
+       if (wpa_s->ifmsh)
+               hostapd_ctrl_iface_pmksa_flush(wpa_s->ifmsh->bss[0]);
+}
 #endif /* CONFIG_CTRL_IFACE */
 
 
index 594168c..5a59ddc 100644 (file)
@@ -76,12 +76,16 @@ int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
                           const struct wpabuf *pw, const u8 *pubkey_hash);
 
 struct hostapd_config;
-void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
-                              struct wpa_ssid *ssid,
-                              struct hostapd_config *conf);
+int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
+                             struct wpa_ssid *ssid,
+                             struct hostapd_config *conf);
 
 int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s);
 
+int wpas_ap_pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf,
+                            size_t len);
+void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s);
+
 void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
                                   struct dfs_event *radar);
 void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
index a2cf7a5..072a1d5 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * WPA Supplicant - auto scan
  * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ * Copyright 2015      Intel Deutschland GmbH
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
 #include "scan.h"
 #include "autoscan.h"
 
-#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
-extern const struct autoscan_ops autoscan_exponential_ops;
-#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
-
-#ifdef CONFIG_AUTOSCAN_PERIODIC
-extern const struct autoscan_ops autoscan_periodic_ops;
-#endif /* CONFIG_AUTOSCAN_PERIODIC */
 
 static const struct autoscan_ops * autoscan_modules[] = {
 #ifdef CONFIG_AUTOSCAN_EXPONENTIAL
@@ -50,6 +44,11 @@ int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
        size_t nlen;
        int i;
        const struct autoscan_ops *ops = NULL;
+       struct sched_scan_plan *scan_plans;
+
+       /* Give preference to scheduled scan plans if supported/configured */
+       if (wpa_s->sched_scan_plans)
+               return 0;
 
        if (wpa_s->autoscan && wpa_s->autoscan_priv)
                return 0;
@@ -79,11 +78,23 @@ int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
                return -1;
        }
 
+       scan_plans = os_malloc(sizeof(*wpa_s->sched_scan_plans));
+       if (!scan_plans)
+               return -1;
+
        wpa_s->autoscan_params = NULL;
 
        wpa_s->autoscan_priv = ops->init(wpa_s, params);
-       if (wpa_s->autoscan_priv == NULL)
+       if (!wpa_s->autoscan_priv) {
+               os_free(scan_plans);
                return -1;
+       }
+
+       scan_plans[0].interval = 5;
+       scan_plans[0].iterations = 0;
+       os_free(wpa_s->sched_scan_plans);
+       wpa_s->sched_scan_plans = scan_plans;
+       wpa_s->sched_scan_plans_num = 1;
        wpa_s->autoscan = ops;
 
        wpa_printf(MSG_DEBUG, "autoscan: Initialized module '%s' with "
@@ -116,7 +127,10 @@ void autoscan_deinit(struct wpa_supplicant *wpa_s)
                wpa_s->autoscan_priv = NULL;
 
                wpa_s->scan_interval = 5;
-               wpa_s->sched_scan_interval = 0;
+
+               os_free(wpa_s->sched_scan_plans);
+               wpa_s->sched_scan_plans = NULL;
+               wpa_s->sched_scan_plans_num = 0;
        }
 }
 
@@ -134,7 +148,7 @@ int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
                        return -1;
 
                wpa_s->scan_interval = interval;
-               wpa_s->sched_scan_interval = interval;
+               wpa_s->sched_scan_plans[0].interval = interval;
 
                request_scan(wpa_s);
        }
index e2a7652..560684f 100644 (file)
@@ -27,6 +27,16 @@ void autoscan_deinit(struct wpa_supplicant *wpa_s);
 int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
                         struct wpa_scan_results *scan_res);
 
+/* Available autoscan modules */
+
+#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+extern const struct autoscan_ops autoscan_exponential_ops;
+#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
+
+#ifdef CONFIG_AUTOSCAN_PERIODIC
+extern const struct autoscan_ops autoscan_periodic_ops;
+#endif /* CONFIG_AUTOSCAN_PERIODIC */
+
 #else /* CONFIG_AUTOSCAN */
 
 static inline int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
index f74cdbf..798b43c 100644 (file)
 #include "config_ssid.h"
 #include "bgscan.h"
 
-#ifdef CONFIG_BGSCAN_SIMPLE
-extern const struct bgscan_ops bgscan_simple_ops;
-#endif /* CONFIG_BGSCAN_SIMPLE */
-#ifdef CONFIG_BGSCAN_LEARN
-extern const struct bgscan_ops bgscan_learn_ops;
-#endif /* CONFIG_BGSCAN_LEARN */
 
 static const struct bgscan_ops * bgscan_modules[] = {
 #ifdef CONFIG_BGSCAN_SIMPLE
index 9131e4e..3df1550 100644 (file)
@@ -39,6 +39,15 @@ void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above,
                                 int current_signal, int current_noise,
                                 int current_txrate);
 
+/* Available bgscan modules */
+
+#ifdef CONFIG_BGSCAN_SIMPLE
+extern const struct bgscan_ops bgscan_simple_ops;
+#endif /* CONFIG_BGSCAN_SIMPLE */
+#ifdef CONFIG_BGSCAN_LEARN
+extern const struct bgscan_ops bgscan_learn_ops;
+#endif /* CONFIG_BGSCAN_LEARN */
+
 #else /* CONFIG_BGSCAN */
 
 static inline int bgscan_init(struct wpa_supplicant *wpa_s,
index 1051ee3..3a8778d 100644 (file)
@@ -12,6 +12,7 @@
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "drivers/driver.h"
+#include "eap_peer/eap.h"
 #include "wpa_supplicant_i.h"
 #include "config.h"
 #include "notify.h"
@@ -60,6 +61,9 @@ struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
        anqp = os_zalloc(sizeof(*anqp));
        if (anqp == NULL)
                return NULL;
+#ifdef CONFIG_INTERWORKING
+       dl_list_init(&anqp->anqp_elems);
+#endif /* CONFIG_INTERWORKING */
        anqp->users = 1;
        return anqp;
 }
@@ -80,6 +84,7 @@ static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
 
 #define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
 #ifdef CONFIG_INTERWORKING
+       dl_list_init(&n->anqp_elems);
        ANQP_DUP(capability_list);
        ANQP_DUP(venue_name);
        ANQP_DUP(network_auth_type);
@@ -141,6 +146,10 @@ int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
  */
 static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
 {
+#ifdef CONFIG_INTERWORKING
+       struct wpa_bss_anqp_elem *elem;
+#endif /* CONFIG_INTERWORKING */
+
        if (anqp == NULL)
                return;
 
@@ -159,6 +168,13 @@ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
        wpabuf_free(anqp->nai_realm);
        wpabuf_free(anqp->anqp_3gpp);
        wpabuf_free(anqp->domain_name);
+
+       while ((elem = dl_list_first(&anqp->anqp_elems,
+                                    struct wpa_bss_anqp_elem, list))) {
+               dl_list_del(&elem->list);
+               wpabuf_free(elem->payload);
+               os_free(elem);
+       }
 #endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_HS20
        wpabuf_free(anqp->hs20_capability_list);
@@ -198,8 +214,8 @@ static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s,
 }
 
 
-static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
-                          const char *reason)
+void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+                   const char *reason)
 {
        if (wpa_s->last_scan_res) {
                unsigned int i;
@@ -288,6 +304,47 @@ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
 }
 
 
+static int wpa_bss_is_wps_candidate(struct wpa_supplicant *wpa_s,
+                                   struct wpa_bss *bss)
+{
+#ifdef CONFIG_WPS
+       struct wpa_ssid *ssid;
+       struct wpabuf *wps_ie;
+       int pbc = 0, ret;
+
+       wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+       if (!wps_ie)
+               return 0;
+
+       if (wps_is_selected_pbc_registrar(wps_ie)) {
+               pbc = 1;
+       } else if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
+               wpabuf_free(wps_ie);
+               return 0;
+       }
+
+       for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+               if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
+                       continue;
+               if (ssid->ssid_len &&
+                   (ssid->ssid_len != bss->ssid_len ||
+                    os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) != 0))
+                       continue;
+
+               if (pbc)
+                       ret = eap_is_wps_pbc_enrollee(&ssid->eap);
+               else
+                       ret = eap_is_wps_pin_enrollee(&ssid->eap);
+               wpabuf_free(wps_ie);
+               return ret;
+       }
+       wpabuf_free(wps_ie);
+#endif /* CONFIG_WPS */
+
+       return 0;
+}
+
+
 static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
 {
        struct wpa_ssid *ssid;
@@ -326,7 +383,8 @@ static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
        struct wpa_bss *bss;
 
        dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-               if (!wpa_bss_known(wpa_s, bss)) {
+               if (!wpa_bss_known(wpa_s, bss) &&
+                   !wpa_bss_is_wps_candidate(wpa_s, bss)) {
                        wpa_bss_remove(wpa_s, bss, __func__);
                        return 0;
                }
@@ -784,7 +842,7 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
        struct wpa_bss *bss, *n;
 
        os_get_reltime(&wpa_s->last_scan);
-       if (!new_scan)
+       if ((info && info->aborted) || !new_scan)
                return; /* do not expire entries without new scan */
 
        dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
@@ -1004,20 +1062,7 @@ 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)
 {
-       const u8 *end, *pos;
-
-       pos = (const u8 *) (bss + 1);
-       end = pos + bss->ie_len;
-
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
-                       break;
-               if (pos[0] == ie)
-                       return pos;
-               pos += 2 + pos[1];
-       }
-
-       return NULL;
+       return get_ie((const u8 *) (bss + 1), bss->ie_len, ie);
 }
 
 
@@ -1037,8 +1082,8 @@ const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
        pos = (const u8 *) (bss + 1);
        end = pos + bss->ie_len;
 
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
+       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]))
@@ -1074,8 +1119,8 @@ const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
        pos += bss->ie_len;
        end = pos + bss->beacon_ie_len;
 
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
+       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]))
@@ -1110,8 +1155,8 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
        pos = (const u8 *) (bss + 1);
        end = pos + bss->ie_len;
 
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
+       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]))
@@ -1155,8 +1200,8 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
        pos += bss->ie_len;
        end = pos + bss->beacon_ie_len;
 
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
+       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]))
index b215380..84e8fb0 100644 (file)
@@ -19,6 +19,12 @@ struct wpa_scan_res;
 #define WPA_BSS_ASSOCIATED             BIT(5)
 #define WPA_BSS_ANQP_FETCH_TRIED       BIT(6)
 
+struct wpa_bss_anqp_elem {
+       struct dl_list list;
+       u16 infoid;
+       struct wpabuf *payload;
+};
+
 /**
  * struct wpa_bss_anqp - ANQP data for a BSS entry (struct wpa_bss)
  */
@@ -34,6 +40,7 @@ struct wpa_bss_anqp {
        struct wpabuf *nai_realm;
        struct wpabuf *anqp_3gpp;
        struct wpabuf *domain_name;
+       struct dl_list anqp_elems; /* list of struct wpa_bss_anqp_elem */
 #endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_HS20
        struct wpabuf *hs20_capability_list;
@@ -106,6 +113,8 @@ 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,
                             struct os_reltime *fetch_time);
+void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+                   const char *reason);
 void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
                        int new_scan);
 int wpa_bss_init(struct wpa_supplicant *wpa_s);
@@ -141,6 +150,17 @@ static inline int bss_is_dmg(const struct wpa_bss *bss)
        return bss->freq > 45000;
 }
 
+/**
+ * Test whether a BSS is a PBSS.
+ * This checks whether a BSS is a DMG-band PBSS. PBSS is used for P2P DMG
+ * network.
+ */
+static inline int bss_is_pbss(struct wpa_bss *bss)
+{
+       return bss_is_dmg(bss) &&
+               (bss->caps & IEEE80211_CAP_DMG_MASK) == IEEE80211_CAP_DMG_PBSS;
+}
+
 static inline void wpa_bss_update_level(struct wpa_bss *bss, int new_level)
 {
        if (bss != NULL && new_level < 0)
index b1adab7..dd922ca 100644 (file)
@@ -32,7 +32,11 @@ struct parse_data {
        /* Configuration variable name */
        char *name;
 
-       /* Parser function for this variable */
+       /* 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 parse_data *data, struct wpa_ssid *ssid,
                      int line, const char *value);
 
@@ -59,7 +63,7 @@ static int wpa_config_parse_str(const struct parse_data *data,
                                struct wpa_ssid *ssid,
                                int line, const char *value)
 {
-       size_t res_len, *dst_len;
+       size_t res_len, *dst_len, prev_len;
        char **dst, *tmp;
 
        if (os_strcmp(value, "NULL") == 0) {
@@ -105,6 +109,21 @@ static int wpa_config_parse_str(const struct parse_data *data,
 set:
        dst = (char **) (((u8 *) ssid) + (long) data->param1);
        dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
+
+       if (data->param2)
+               prev_len = *dst_len;
+       else if (*dst)
+               prev_len = os_strlen(*dst);
+       else
+               prev_len = 0;
+       if ((*dst == NULL && tmp == NULL) ||
+           (*dst && tmp && prev_len == res_len &&
+            os_memcmp(*dst, tmp, res_len) == 0)) {
+               /* No change to the previously configured value */
+               os_free(tmp);
+               return 1;
+       }
+
        os_free(*dst);
        *dst = tmp;
        if (data->param2)
@@ -190,6 +209,9 @@ static int wpa_config_parse_int(const struct parse_data *data,
                           line, value);
                return -1;
        }
+
+       if (*dst == val)
+               return 1;
        *dst = val;
        wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
 
@@ -456,9 +478,17 @@ static int wpa_config_parse_psk(const struct parse_data *data,
                }
                wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
                                      (u8 *) value, len);
+               if (has_ctrl_char((u8 *) value, len)) {
+                       wpa_printf(MSG_ERROR,
+                                  "Line %d: Invalid passphrase character",
+                                  line);
+                       return -1;
+               }
                if (ssid->passphrase && os_strlen(ssid->passphrase) == len &&
-                   os_memcmp(ssid->passphrase, value, len) == 0)
-                       return 0;
+                   os_memcmp(ssid->passphrase, value, len) == 0) {
+                       /* No change to the previously configured value */
+                       return 1;
+               }
                ssid->psk_set = 0;
                str_clear_free(ssid->passphrase);
                ssid->passphrase = dup_binstr(value, len);
@@ -569,6 +599,8 @@ static int wpa_config_parse_proto(const struct parse_data *data,
                errors++;
        }
 
+       if (!errors && ssid->proto == val)
+               return 1;
        wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
        ssid->proto = val;
        return errors ? -1 : 0;
@@ -705,6 +737,8 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
                errors++;
        }
 
+       if (!errors && ssid->key_mgmt == val)
+               return 1;
        wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
        ssid->key_mgmt = val;
        return errors ? -1 : 0;
@@ -899,6 +933,9 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
 
 static int wpa_config_parse_cipher(int line, const char *value)
 {
+#ifdef CONFIG_NO_WPA
+       return -1;
+#else /* CONFIG_NO_WPA */
        int val = wpa_parse_cipher(value);
        if (val < 0) {
                wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
@@ -911,12 +948,16 @@ static int wpa_config_parse_cipher(int line, const char *value)
                return -1;
        }
        return val;
+#endif /* CONFIG_NO_WPA */
 }
 
 
 #ifndef NO_CONFIG_WRITE
 static char * wpa_config_write_cipher(int cipher)
 {
+#ifdef CONFIG_NO_WPA
+       return NULL;
+#else /* CONFIG_NO_WPA */
        char *buf = os_zalloc(50);
        if (buf == NULL)
                return NULL;
@@ -927,6 +968,7 @@ static char * wpa_config_write_cipher(int cipher)
        }
 
        return buf;
+#endif /* CONFIG_NO_WPA */
 }
 #endif /* NO_CONFIG_WRITE */
 
@@ -945,6 +987,8 @@ static int wpa_config_parse_pairwise(const struct parse_data *data,
                return -1;
        }
 
+       if (ssid->pairwise_cipher == val)
+               return 1;
        wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
        ssid->pairwise_cipher = val;
        return 0;
@@ -981,6 +1025,8 @@ static int wpa_config_parse_group(const struct parse_data *data,
                return -1;
        }
 
+       if (ssid->group_cipher == val)
+               return 1;
        wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
        ssid->group_cipher = val;
        return 0;
@@ -1042,6 +1088,8 @@ static int wpa_config_parse_auth_alg(const struct parse_data *data,
                errors++;
        }
 
+       if (!errors && ssid->auth_alg == val)
+               return 1;
        wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
        ssid->auth_alg = val;
        return errors ? -1 : 0;
@@ -1296,6 +1344,32 @@ static int wpa_config_parse_eap(const struct parse_data *data,
        methods[num_methods].method = EAP_TYPE_NONE;
        num_methods++;
 
+       if (!errors && ssid->eap.eap_methods) {
+               struct eap_method_type *prev_m;
+               size_t i, j, prev_methods, match = 0;
+
+               prev_m = ssid->eap.eap_methods;
+               for (i = 0; prev_m[i].vendor != EAP_VENDOR_IETF ||
+                            prev_m[i].method != EAP_TYPE_NONE; i++) {
+                       /* Count the methods */
+               }
+               prev_methods = i + 1;
+
+               for (i = 0; prev_methods == num_methods && i < prev_methods;
+                    i++) {
+                       for (j = 0; j < num_methods; j++) {
+                               if (prev_m[i].vendor == methods[j].vendor &&
+                                   prev_m[i].method == methods[j].method) {
+                                       match++;
+                                       break;
+                               }
+                       }
+               }
+               if (match == num_methods) {
+                       os_free(methods);
+                       return 1;
+               }
+       }
        wpa_hexdump(MSG_MSGDUMP, "eap methods",
                    (u8 *) methods, num_methods * sizeof(*methods));
        os_free(ssid->eap.eap_methods);
@@ -1348,6 +1422,8 @@ static int wpa_config_parse_password(const struct parse_data *data,
        u8 *hash;
 
        if (os_strcmp(value, "NULL") == 0) {
+               if (!ssid->eap.password)
+                       return 1; /* Already unset */
                wpa_printf(MSG_DEBUG, "Unset configuration string 'password'");
                bin_clear_free(ssid->eap.password, ssid->eap.password_len);
                ssid->eap.password = NULL;
@@ -1411,6 +1487,12 @@ static int wpa_config_parse_password(const struct parse_data *data,
 
        wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
 
+       if (ssid->eap.password && ssid->eap.password_len == 16 &&
+           os_memcmp(ssid->eap.password, hash, 16) == 0 &&
+           (ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
+               bin_clear_free(hash, 16);
+               return 1;
+       }
        bin_clear_free(ssid->eap.password, ssid->eap.password_len);
        ssid->eap.password = hash;
        ssid->eap.password_len = 16;
@@ -1837,6 +1919,8 @@ static const struct parse_data ssid_fields[] = {
        { FUNC(auth_alg) },
        { FUNC(scan_freq) },
        { FUNC(freq_list) },
+       { INT_RANGE(max_oper_chwidth, VHT_CHANWIDTH_USE_HT,
+                   VHT_CHANWIDTH_80P80MHZ) },
 #ifdef IEEE8021X_EAPOL
        { FUNC(eap) },
        { STR_LENe(identity) },
@@ -1910,6 +1994,9 @@ static const struct parse_data ssid_fields[] = {
        { INT_RANGE(mixed_cell, 0, 1) },
        { INT_RANGE(frequency, 0, 65000) },
        { INT_RANGE(fixed_freq, 0, 1) },
+#ifdef CONFIG_ACS
+       { INT_RANGE(acs, 0, 1) },
+#endif /* CONFIG_ACS */
 #ifdef CONFIG_MESH
        { FUNC(mesh_basic_rates) },
        { INT(dot11MeshMaxRetries) },
@@ -1918,6 +2005,7 @@ static const struct parse_data ssid_fields[] = {
        { INT(dot11MeshHoldingTimeout) },
 #endif /* CONFIG_MESH */
        { INT(wpa_ptk_rekey) },
+       { INT(group_rekey) },
        { STR(bgscan) },
        { INT_RANGE(ignore_broadcast_ssid, 0, 2) },
 #ifdef CONFIG_P2P
@@ -1967,6 +2055,8 @@ static const struct parse_data ssid_fields[] = {
        { INT(update_identifier) },
 #endif /* CONFIG_HS20 */
        { INT_RANGE(mac_addr, 0, 2) },
+       { INT_RANGE(pbss, 0, 2) },
+       { INT_RANGE(wps_disabled, 0, 1) },
 };
 
 #undef OFFSET
@@ -2271,6 +2361,11 @@ void wpa_config_free(struct wpa_config *config)
        os_free(config->bgscan);
        os_free(config->wowlan_triggers);
        os_free(config->fst_group_id);
+       os_free(config->sched_scan_plans);
+#ifdef CONFIG_MBO
+       os_free(config->non_pref_chan);
+#endif /* CONFIG_MBO */
+
        os_free(config);
 }
 
@@ -2453,7 +2548,8 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
  * @var: Variable name, e.g., "ssid"
  * @value: Variable value
  * @line: Line number in configuration file or 0 if not used
- * Returns: 0 on success, -1 on failure
+ * Returns: 0 on success with possible change in the value, 1 on success with
+ * no change to previously configured value, or -1 on failure
  *
  * This function can be used to set network configuration variables based on
  * both the configuration file and management interface input. The value
@@ -2474,7 +2570,8 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
                if (os_strcmp(var, field->name) != 0)
                        continue;
 
-               if (field->parser(field, ssid, line, value)) {
+               ret = field->parser(field, ssid, line, value);
+               if (ret < 0) {
                        if (line) {
                                wpa_printf(MSG_ERROR, "Line %d: failed to "
                                           "parse %s '%s'.", line, var, value);
@@ -2573,9 +2670,8 @@ char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
        return props;
 
 err:
-       value = *props;
-       while (value)
-               os_free(value++);
+       for (i = 0; props[i]; i++)
+               os_free(props[i]);
        os_free(props);
        return NULL;
 #endif /* NO_CONFIG_WRITE */
@@ -2604,8 +2700,19 @@ char * wpa_config_get(struct wpa_ssid *ssid, const char *var)
 
        for (i = 0; i < NUM_SSID_FIELDS; i++) {
                const struct parse_data *field = &ssid_fields[i];
-               if (os_strcmp(var, field->name) == 0)
-                       return field->writer(field, ssid);
+               if (os_strcmp(var, field->name) == 0) {
+                       char *ret = field->writer(field, ssid);
+
+                       if (ret && has_newline(ret)) {
+                               wpa_printf(MSG_ERROR,
+                                          "Found newline in value for %s; not returning it",
+                                          var);
+                               os_free(ret);
+                               ret = NULL;
+                       }
+
+                       return ret;
+               }
        }
 
        return NULL;
@@ -2790,6 +2897,8 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
 
        if (os_strcmp(var, "password") == 0 &&
            os_strncmp(value, "ext:", 4) == 0) {
+               if (has_newline(value))
+                       return -1;
                str_clear_free(cred->password);
                cred->password = os_strdup(value);
                cred->ext_password = 1;
@@ -2840,9 +2949,14 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
        }
 
        val = wpa_config_parse_string(value, &len);
-       if (val == NULL) {
+       if (val == NULL ||
+           (os_strcmp(var, "excluded_ssid") != 0 &&
+            os_strcmp(var, "roaming_consortium") != 0 &&
+            os_strcmp(var, "required_roaming_consortium") != 0 &&
+            has_newline(val))) {
                wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
                           "value '%s'.", line, var, value);
+               os_free(val);
                return -1;
        }
 
@@ -3540,6 +3654,11 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
        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;
+
+#ifdef CONFIG_MBO
+       config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA;
+#endif /* CONFIG_MBO */
 
        if (ctrl_interface)
                config->ctrl_interface = os_strdup(ctrl_interface);
@@ -3646,6 +3765,12 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
                return -1;
        }
 
+       if (has_newline(pos)) {
+               wpa_printf(MSG_ERROR, "Line %d: invalid %s value with newline",
+                          line, data->name);
+               return -1;
+       }
+
        tmp = os_strdup(pos);
        if (tmp == NULL)
                return -1;
@@ -3684,22 +3809,12 @@ static int wpa_global_config_parse_bin(const struct global_parse_data *data,
                                       struct wpa_config *config, int line,
                                       const char *pos)
 {
-       size_t len;
        struct wpabuf **dst, *tmp;
 
-       len = os_strlen(pos);
-       if (len & 0x01)
-               return -1;
-
-       tmp = wpabuf_alloc(len / 2);
-       if (tmp == NULL)
+       tmp = wpabuf_parse_bin(pos);
+       if (!tmp)
                return -1;
 
-       if (hexstr2bin(pos, wpabuf_put(tmp, len / 2), len / 2)) {
-               wpabuf_free(tmp);
-               return -1;
-       }
-
        dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
        wpabuf_free(*dst);
        *dst = tmp;
@@ -4246,6 +4361,16 @@ static const struct global_parse_data global_fields[] = {
        { INT_RANGE(fst_priority, 1, FST_MAX_PRIO_VALUE), 0 },
        { INT_RANGE(fst_llt, 1, FST_MAX_LLT_MS), 0 },
 #endif /* CONFIG_FST */
+       { INT_RANGE(wpa_rsc_relaxation, 0, 1), 0 },
+       { STR(sched_scan_plans), CFG_CHANGED_SCHED_SCAN_PLANS },
+#ifdef CONFIG_MBO
+       { STR(non_pref_chan), 0 },
+       { INT_RANGE(mbo_cell_capa, MBO_CELL_CAPA_AVAILABLE,
+                   MBO_CELL_CAPA_NOT_SUPPORTED), 0 },
+#endif /*CONFIG_MBO */
+       { INT(gas_address3), 0 },
+       { INT_RANGE(ftm_responder, 0, 1), 0 },
+       { INT_RANGE(ftm_initiator, 0, 1), 0 },
 };
 
 #undef FUNC
@@ -4304,6 +4429,23 @@ int wpa_config_get_value(const char *name, struct wpa_config *config,
 }
 
 
+int wpa_config_get_num_global_field_names(void)
+{
+       return NUM_GLOBAL_FIELDS;
+}
+
+
+const char * wpa_config_get_global_field_name(unsigned int i, int *no_var)
+{
+       if (i >= NUM_GLOBAL_FIELDS)
+               return NULL;
+
+       if (no_var)
+               *no_var = !global_fields[i].param1;
+       return global_fields[i].name;
+}
+
+
 int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
 {
        size_t i;
index 627f38b..48e64be 100644 (file)
@@ -39,6 +39,8 @@
 #define DEFAULT_KEY_MGMT_OFFLOAD 1
 #define DEFAULT_CERT_IN_CB 1
 #define DEFAULT_P2P_GO_CTWINDOW 0
+#define DEFAULT_WPA_RSC_RELAXATION 1
+#define DEFAULT_MBO_CELL_CAPA MBO_CELL_CAPA_NOT_SUPPORTED
 
 #include "config_ssid.h"
 #include "wps/wps.h"
@@ -331,6 +333,7 @@ struct wpa_cred {
 #define CFG_CHANGED_EXT_PW_BACKEND BIT(14)
 #define CFG_CHANGED_NFC_PASSWORD_TOKEN BIT(15)
 #define CFG_CHANGED_P2P_PASSPHRASE_LEN BIT(16)
+#define CFG_CHANGED_SCHED_SCAN_PLANS BIT(17)
 
 /**
  * struct wpa_config - wpa_supplicant configuration data
@@ -761,12 +764,17 @@ struct wpa_config {
         * frequency list of the local device and the peer device.
         *
         * @P2P_GO_FREQ_MOVE_STAY: Prefer to stay on the current frequency.
+        *
+        * @P2P_GO_FREQ_MOVE_SCM_ECSA: Same as
+        * P2P_GO_FREQ_MOVE_SCM_PEER_SUPPORTS but a transition is possible only
+        * if all the group members advertise eCSA support.
         */
        enum {
                P2P_GO_FREQ_MOVE_SCM = 0,
                P2P_GO_FREQ_MOVE_SCM_PEER_SUPPORTS = 1,
                P2P_GO_FREQ_MOVE_STAY = 2,
-               P2P_GO_FREQ_MOVE_MAX = P2P_GO_FREQ_MOVE_STAY,
+               P2P_GO_FREQ_MOVE_SCM_ECSA = 3,
+               P2P_GO_FREQ_MOVE_MAX = P2P_GO_FREQ_MOVE_SCM_ECSA,
        } p2p_go_freq_change_policy;
 
 #define DEFAULT_P2P_GO_FREQ_MOVE P2P_GO_FREQ_MOVE_STAY
@@ -1031,7 +1039,8 @@ struct wpa_config {
         *
         * By default, PMF is disabled unless enabled by the per-network
         * ieee80211w=1 or ieee80211w=2 parameter. pmf=1/2 can be used to change
-        * this default behavior.
+        * this default behavior for RSN network (this is not applicable for
+        * non-RSN cases).
         */
        enum mfp_options pmf;
 
@@ -1247,6 +1256,78 @@ struct wpa_config {
         * interface.
         */
        int fst_llt;
+
+        /**
+         * wpa_rsc_relaxation - RSC relaxation on GTK installation
+         *
+         * Values:
+         * 0 - use the EAPOL-Key RSC value on GTK installation
+         * 1 - use the null RSC if a bogus RSC value is detected in message 3
+         * of 4-Way Handshake or message 1 of Group Key Handshake.
+         */
+        int wpa_rsc_relaxation;
+
+       /**
+        * sched_scan_plans - Scan plans for scheduled scan
+        *
+        * Each scan plan specifies the interval between scans and the number of
+        * iterations. The last scan plan only specifies the scan interval and
+        * will be run infinitely.
+        *
+        * format: <interval:iterations> <interval2:iterations2> ... <interval>
+        */
+        char *sched_scan_plans;
+
+#ifdef CONFIG_MBO
+       /**
+        * non_pref_chan - Non-preferred channels list, separated by spaces.
+        *
+        * format: op_class:chan:preference:reason<:detail>
+        * Detail is optional.
+        */
+       char *non_pref_chan;
+
+       /**
+        * mbo_cell_capa - Cellular capabilities for MBO
+        */
+       enum mbo_cellular_capa mbo_cell_capa;
+#endif /* CONFIG_MBO */
+
+       /**
+        * gas_address3 - GAS Address3 field behavior
+        *
+        * Values:
+        * 0 - P2P specification (Address3 = AP BSSID)
+        * 1 = IEEE 802.11 standard compliant (Address3 = Wildcard BSSID when
+        *      sent to not-associated AP; if associated, AP BSSID)
+        */
+       int gas_address3;
+
+       /**
+        * ftm_responder - Publish FTM (fine timing measurement)
+        * responder functionality
+        *
+        * Values:
+        * 0 - do not publish FTM responder functionality (Default)
+        * 1 - publish FTM responder functionality in
+        *      bit 70 of Extended Capabilities element
+        * Note, actual FTM responder operation is managed outside
+        * wpa_supplicant.
+        */
+       int ftm_responder;
+
+       /**
+        * ftm_initiator - Publish FTM (fine timing measurement)
+        * initiator functionality
+        *
+        * Values:
+        * 0 - do not publish FTM initiator functionality (Default)
+        * 1 - publish FTM initiator functionality in
+        *      bit 71 of Extended Capabilities element
+        * Note, actual FTM initiator operation is managed outside
+        * wpa_supplicant.
+        */
+       int ftm_initiator;
 };
 
 
@@ -1305,6 +1386,9 @@ void wpa_config_debug_dump_networks(struct wpa_config *config);
 /* Prototypes for common functions from config.c */
 int wpa_config_process_global(struct wpa_config *config, char *pos, int line);
 
+int wpa_config_get_num_global_field_names(void);
+
+const char * wpa_config_get_global_field_name(unsigned int i, int *no_var);
 
 /* Prototypes for backend specific functions from the selected config_*.c */
 
index fb438ea..7ae1654 100644 (file)
@@ -747,10 +747,16 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
        INT(no_auto_peer);
        INT(frequency);
        INT(fixed_freq);
+#ifdef CONFIG_ACS
+       INT(acs);
+#endif /* CONFIG_ACS */
        write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
        INT(disabled);
        INT(peerkey);
        INT(mixed_cell);
+       INT(max_oper_chwidth);
+       INT(pbss);
+       INT(wps_disabled);
 #ifdef CONFIG_IEEE80211W
        write_int(f, "ieee80211w", ssid->ieee80211w,
                  MGMT_FRAME_PROTECTION_DEFAULT);
@@ -779,6 +785,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
        INT_DEF(dot11MeshHoldingTimeout, DEFAULT_MESH_HOLDING_TIMEOUT);
 #endif /* CONFIG_MESH */
        INT(wpa_ptk_rekey);
+       INT(group_rekey);
        INT(ignore_broadcast_ssid);
 #ifdef CONFIG_HT_OVERRIDES
        INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
@@ -1136,6 +1143,22 @@ 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 (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],
+                       config->ip_addr_go[2], config->ip_addr_go[3]);
+       if (WPA_GET_BE32(config->ip_addr_mask))
+               fprintf(f, "ip_addr_mask=%u.%u.%u.%u\n",
+                       config->ip_addr_mask[0], config->ip_addr_mask[1],
+                       config->ip_addr_mask[2], config->ip_addr_mask[3]);
+       if (WPA_GET_BE32(config->ip_addr_start))
+               fprintf(f, "ip_addr_start=%u.%u.%u.%u\n",
+                       config->ip_addr_start[0], config->ip_addr_start[1],
+                       config->ip_addr_start[2], config->ip_addr_start[3]);
+       if (WPA_GET_BE32(config->ip_addr_end))
+               fprintf(f, "ip_addr_end=%u.%u.%u.%u\n",
+                       config->ip_addr_end[0], config->ip_addr_end[1],
+                       config->ip_addr_end[2], config->ip_addr_end[3]);
 #endif /* CONFIG_P2P */
        if (config->country[0] && config->country[1]) {
                fprintf(f, "country=%c%c\n",
@@ -1299,6 +1322,28 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
 
        if (config->wps_priority)
                fprintf(f, "wps_priority=%d\n", config->wps_priority);
+
+       if (config->wpa_rsc_relaxation != DEFAULT_WPA_RSC_RELAXATION)
+               fprintf(f, "wpa_rsc_relaxation=%d\n",
+                       config->wpa_rsc_relaxation);
+
+       if (config->sched_scan_plans)
+               fprintf(f, "sched_scan_plans=%s\n", config->sched_scan_plans);
+
+#ifdef CONFIG_MBO
+       if (config->non_pref_chan)
+               fprintf(f, "non_pref_chan=%s\n", config->non_pref_chan);
+       if (config->mbo_cell_capa != DEFAULT_MBO_CELL_CAPA)
+               fprintf(f, "mbo_cell_capa=%u\n", config->mbo_cell_capa);
+#endif /* CONFIG_MBO */
+
+       if (config->gas_address3)
+               fprintf(f, "gas_address3=%d\n", config->gas_address3);
+
+       if (config->ftm_responder)
+               fprintf(f, "ftm_responder=%d\n", config->ftm_responder);
+       if (config->ftm_initiator)
+               fprintf(f, "ftm_initiator=%d\n", config->ftm_initiator);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
index 7ef326c..010b594 100644 (file)
@@ -360,6 +360,19 @@ struct wpa_ssid {
        } mode;
 
        /**
+        * pbss - Whether to use PBSS. Relevant to DMG networks only.
+        * 0 = do not use PBSS
+        * 1 = use PBSS
+        * 2 = don't care (not allowed in AP mode)
+        * Used together with mode configuration. When mode is AP, it
+        * means to start a PCP instead of a regular AP. When mode is INFRA it
+        * means connect to a PCP instead of AP. In this mode you can also
+        * specify 2 (don't care) meaning connect to either AP or PCP.
+        * P2P_GO and P2P_GROUP_FORMATION modes must use PBSS in DMG network.
+        */
+       int pbss;
+
+       /**
         * disabled - Whether this network is currently disabled
         *
         * 0 = this network can be used (default).
@@ -431,6 +444,18 @@ struct wpa_ssid {
         */
        int fixed_freq;
 
+#ifdef CONFIG_ACS
+       /**
+        * ACS - Automatic Channel Selection for AP mode
+        *
+        * If present, it will be handled together with frequency.
+        * frequency will be used to determine hardware mode only, when it is
+        * used for both hardware mode and channel when used alone. This will
+        * force the channel to be set to 0, thus enabling ACS.
+        */
+       int acs;
+#endif /* CONFIG_ACS */
+
        /**
         * mesh_basic_rates - BSS Basic rate set for mesh network
         *
@@ -449,6 +474,10 @@ struct wpa_ssid {
 
        int vht;
 
+       u8 max_oper_chwidth;
+
+       unsigned int vht_center_freq2;
+
        /**
         * wpa_ptk_rekey - Maximum lifetime for PTK in seconds
         *
@@ -458,6 +487,14 @@ struct wpa_ssid {
        int wpa_ptk_rekey;
 
        /**
+        * 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.
+        */
+       int group_rekey;
+
+       /**
         * scan_freq - Array of frequencies to scan or %NULL for all
         *
         * This is an optional zero-terminated array of frequencies in
@@ -719,6 +756,14 @@ struct wpa_ssid {
         * this MBSS will trigger a peering attempt.
         */
        int no_auto_peer;
+
+       /**
+        * wps_disabled - WPS disabled in AP mode
+        *
+        * 0 = WPS enabled and configured (default)
+        * 1 = WPS disabled
+        */
+       int wps_disabled;
 };
 
 #endif /* CONFIG_SSID_H */
index 199f04f..82ba3b0 100644 (file)
@@ -933,6 +933,7 @@ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
 #ifdef CONFIG_HS20
        INT(update_identifier);
 #endif /* CONFIG_HS20 */
+       INT(group_rekey);
 
 #undef STR
 #undef INT
index 3b97806..d814fdf 100644 (file)
@@ -15,6 +15,7 @@
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "utils/uuid.h"
+#include "utils/module_tests.h"
 #include "common/version.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
@@ -55,6 +56,7 @@
 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,
+                                                 const char *input,
                                                  char *buf, int len);
 static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s,
                                        char *val);
@@ -310,6 +312,33 @@ static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band)
 }
 
 
+static int wpas_ctrl_iface_set_lci(struct wpa_supplicant *wpa_s,
+                                  const char *cmd)
+{
+       struct wpabuf *lci;
+
+       if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) {
+               wpabuf_free(wpa_s->lci);
+               wpa_s->lci = NULL;
+               return 0;
+       }
+
+       lci = wpabuf_parse_bin(cmd);
+       if (!lci)
+               return -1;
+
+       if (os_get_reltime(&wpa_s->lci_time)) {
+               wpabuf_free(lci);
+               return -1;
+       }
+
+       wpabuf_free(wpa_s->lci);
+       wpa_s->lci = lci;
+
+       return 0;
+}
+
+
 static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                                         char *cmd)
 {
@@ -371,6 +400,20 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                wps_corrupt_pkhash = atoi(value);
                wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
                           wps_corrupt_pkhash);
+       } else if (os_strcasecmp(cmd, "wps_force_auth_types") == 0) {
+               if (value[0] == '\0') {
+                       wps_force_auth_types_in_use = 0;
+               } else {
+                       wps_force_auth_types = strtol(value, NULL, 0);
+                       wps_force_auth_types_in_use = 1;
+               }
+       } else if (os_strcasecmp(cmd, "wps_force_encr_types") == 0) {
+               if (value[0] == '\0') {
+                       wps_force_encr_types_in_use = 0;
+               } else {
+                       wps_force_encr_types = strtol(value, NULL, 0);
+                       wps_force_encr_types_in_use = 1;
+               }
 #endif /* CONFIG_WPS_TESTING */
        } else if (os_strcasecmp(cmd, "ampdu") == 0) {
                if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
@@ -378,7 +421,6 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
 #ifdef CONFIG_TDLS
 #ifdef CONFIG_TDLS_TESTING
        } else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
-               extern unsigned int tdls_testing;
                tdls_testing = strtol(value, NULL, 0);
                wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
 #endif /* CONFIG_TDLS_TESTING */
@@ -467,6 +509,14 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                wpa_s->extra_roc_dur = atoi(value);
        } else if (os_strcasecmp(cmd, "test_failure") == 0) {
                wpa_s->test_failure = atoi(value);
+       } else if (os_strcasecmp(cmd, "p2p_go_csa_on_inv") == 0) {
+               wpa_s->p2p_go_csa_on_inv = !!atoi(value);
+       } else if (os_strcasecmp(cmd, "ignore_auth_resp") == 0) {
+               wpa_s->ignore_auth_resp = !!atoi(value);
+       } else if (os_strcasecmp(cmd, "ignore_assoc_disallow") == 0) {
+               wpa_s->ignore_assoc_disallow = !!atoi(value);
+       } else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) {
+               wpa_s->reject_btm_req_reason = atoi(value);
 #endif /* CONFIG_TESTING_OPTIONS */
 #ifndef CONFIG_NO_CONFIG_BLOBS
        } else if (os_strcmp(cmd, "blob") == 0) {
@@ -474,6 +524,14 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_NO_CONFIG_BLOBS */
        } else if (os_strcasecmp(cmd, "setband") == 0) {
                ret = wpas_ctrl_set_band(wpa_s, value);
+#ifdef CONFIG_MBO
+       } else if (os_strcasecmp(cmd, "non_pref_chan") == 0) {
+               ret = wpas_mbo_update_non_pref_chan(wpa_s, value);
+       } else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) {
+               wpas_mbo_update_cell_capa(wpa_s, atoi(value));
+#endif /* CONFIG_MBO */
+       } else if (os_strcasecmp(cmd, "lci") == 0) {
+               ret = wpas_ctrl_iface_set_lci(wpa_s, value);
        } else {
                value[-1] = '=';
                ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -940,7 +998,8 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
        if (os_strcmp(cmd, "any") == 0)
                _bssid = NULL;
        else if (os_strcmp(cmd, "get") == 0) {
-               ret = wps_generate_pin();
+               if (wps_generate_pin((unsigned int *) &ret) < 0)
+                       return -1;
                goto done;
        } else if (hwaddr_aton(cmd, bssid)) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
@@ -1833,6 +1892,10 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
                                                  "mode=P2P GO - group "
                                                  "formation\n");
                                break;
+                       case WPAS_MODE_MESH:
+                               ret = os_snprintf(pos, end - pos,
+                                                 "mode=mesh\n");
+                               break;
                        default:
                                ret = 0;
                                break;
@@ -2703,6 +2766,40 @@ static int wpa_supplicant_ctrl_iface_mesh_group_remove(
        return 0;
 }
 
+
+static int wpa_supplicant_ctrl_iface_mesh_peer_remove(
+       struct wpa_supplicant *wpa_s, char *cmd)
+{
+       u8 addr[ETH_ALEN];
+
+       if (hwaddr_aton(cmd, addr) < 0)
+               return -1;
+
+       return wpas_mesh_peer_remove(wpa_s, addr);
+}
+
+
+static int wpa_supplicant_ctrl_iface_mesh_peer_add(
+       struct wpa_supplicant *wpa_s, char *cmd)
+{
+       u8 addr[ETH_ALEN];
+       int duration;
+       char *pos;
+
+       pos = os_strstr(cmd, " duration=");
+       if (pos) {
+               *pos = '\0';
+               duration = atoi(pos + 10);
+       } else {
+               duration = -1;
+       }
+
+       if (hwaddr_aton(cmd, addr))
+               return -1;
+
+       return wpas_mesh_peer_add(wpa_s, addr, duration);
+}
+
 #endif /* CONFIG_MESH */
 
 
@@ -2832,15 +2929,10 @@ static int wpa_supplicant_ctrl_iface_add_network(
 
        wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
 
-       ssid = wpa_config_add_network(wpa_s->conf);
+       ssid = wpa_supplicant_add_network(wpa_s);
        if (ssid == NULL)
                return -1;
 
-       wpas_notify_network_added(wpa_s, ssid);
-
-       ssid->disabled = 1;
-       wpa_config_set_network_defaults(ssid);
-
        ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
        if (os_snprintf_error(buflen, ret))
                return -1;
@@ -2853,7 +2945,7 @@ static int wpa_supplicant_ctrl_iface_remove_network(
 {
        int id;
        struct wpa_ssid *ssid;
-       int was_disabled;
+       int result;
 
        /* cmd: "<network id>" or "all" */
        if (os_strcmp(cmd, "all") == 0) {
@@ -2889,54 +2981,17 @@ static int wpa_supplicant_ctrl_iface_remove_network(
        id = atoi(cmd);
        wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
 
-       ssid = wpa_config_get_network(wpa_s->conf, id);
-       if (ssid)
-               wpas_notify_network_removed(wpa_s, ssid);
-       if (ssid == NULL) {
+       result = wpa_supplicant_remove_network(wpa_s, id);
+       if (result == -1) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
                           "id=%d", id);
                return -1;
        }
-
-       if (wpa_s->last_ssid == ssid)
-               wpa_s->last_ssid = NULL;
-
-       if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
-#ifdef CONFIG_SME
-               wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
-               /*
-                * Invalidate the EAP session cache if the current or
-                * previously used network is removed.
-                */
-               eapol_sm_invalidate_cached_session(wpa_s->eapol);
-       }
-
-       if (ssid == wpa_s->current_ssid) {
-               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);
-       }
-
-       was_disabled = ssid->disabled;
-
-       if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+       if (result == -2) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
                           "network id=%d", id);
                return -1;
        }
-
-       if (!was_disabled && wpa_s->sched_scanning) {
-               wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove "
-                          "network from filters");
-               wpa_supplicant_cancel_sched_scan(wpa_s);
-               wpa_supplicant_req_scan(wpa_s, 0, 0);
-       }
-
        return 0;
 }
 
@@ -2945,22 +3000,29 @@ static int wpa_supplicant_ctrl_iface_update_network(
        struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
        char *name, char *value)
 {
-       if (wpa_config_set(ssid, name, value, 0) < 0) {
+       int ret;
+
+       ret = wpa_config_set(ssid, name, value, 0);
+       if (ret < 0) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
                           "variable '%s'", name);
                return -1;
        }
+       if (ret == 1)
+               return 0; /* No change to the previously configured value */
 
        if (os_strcmp(name, "bssid") != 0 &&
-           os_strcmp(name, "priority") != 0)
+           os_strcmp(name, "priority") != 0) {
                wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
 
-       if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
-               /*
-                * Invalidate the EAP session cache if anything in the current
-                * or previously used configuration changes.
-                */
-               eapol_sm_invalidate_cached_session(wpa_s->eapol);
+               if (wpa_s->current_ssid == ssid ||
+                   wpa_s->current_ssid == NULL) {
+                       /*
+                        * Invalidate the EAP session cache if anything in the
+                        * current or previously used configuration changes.
+                        */
+                       eapol_sm_invalidate_cached_session(wpa_s->eapol);
+               }
        }
 
        if ((os_strcmp(name, "psk") == 0 &&
@@ -3935,6 +3997,15 @@ static int wpa_supplicant_ctrl_iface_get_capability(
        }
 #endif /* CONFIG_FIPS */
 
+#ifdef CONFIG_ACS
+       if (os_strcmp(field, "acs") == 0) {
+               res = os_snprintf(buf, buflen, "ACS");
+               if (os_snprintf_error(buflen, res))
+                       return -1;
+               return res;
+       }
+#endif /* CONFIG_ACS */
+
        wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
                   field);
 
@@ -4195,9 +4266,10 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        if (mask & WPA_BSS_MASK_P2P_SCAN) {
                ie = (const u8 *) (bss + 1);
                ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
-               if (ret < 0 || ret >= end - pos)
+               if (ret >= end - pos)
                        return 0;
-               pos += ret;
+               if (ret > 0)
+                       pos += ret;
        }
 #endif /* CONFIG_P2P */
 
@@ -4231,6 +4303,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 #ifdef CONFIG_INTERWORKING
        if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
                struct wpa_bss_anqp *anqp = bss->anqp;
+               struct wpa_bss_anqp_elem *elem;
+
                pos = anqp_add_hex(pos, end, "anqp_capability_list",
                                   anqp->capability_list);
                pos = anqp_add_hex(pos, end, "anqp_venue_name",
@@ -4260,6 +4334,15 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
                                   anqp->hs20_osu_providers_list);
 #endif /* CONFIG_HS20 */
+
+               dl_list_for_each(elem, &anqp->anqp_elems,
+                                struct wpa_bss_anqp_elem, list) {
+                       char title[20];
+
+                       os_snprintf(title, sizeof(title), "anqp[%u]",
+                                   elem->infoid);
+                       pos = anqp_add_hex(pos, end, title, elem->payload);
+               }
        }
 #endif /* CONFIG_INTERWORKING */
 
@@ -4267,9 +4350,10 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        if (mask & WPA_BSS_MASK_MESH_SCAN) {
                ie = (const u8 *) (bss + 1);
                ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end);
-               if (ret < 0 || ret >= end - pos)
+               if (ret >= end - pos)
                        return 0;
-               pos += ret;
+               if (ret > 0)
+                       pos += ret;
        }
 #endif /* CONFIG_MESH */
 
@@ -4676,7 +4760,7 @@ static int p2ps_ctrl_parse_cpt_priority(const char *pos, u8 *cpt)
                        return -1;
                }
 
-               if (isblank(*last)) {
+               if (isblank((unsigned char) *last)) {
                        i++;
                        break;
                }
@@ -4848,6 +4932,30 @@ static int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd)
 }
 
 
+static int parse_freq(int chwidth, int freq2)
+{
+       if (freq2 < 0)
+               return -1;
+       if (freq2)
+               return VHT_CHANWIDTH_80P80MHZ;
+
+       switch (chwidth) {
+       case 0:
+       case 20:
+       case 40:
+               return VHT_CHANWIDTH_USE_HT;
+       case 80:
+               return VHT_CHANWIDTH_80MHZ;
+       case 160:
+               return VHT_CHANWIDTH_160MHZ;
+       default:
+               wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d",
+                          chwidth);
+               return -1;
+       }
+}
+
+
 static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
                            char *buf, size_t buflen)
 {
@@ -4864,7 +4972,9 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
        int go_intent = -1;
        int freq = 0;
        int pd;
-       int ht40, vht;
+       int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
+       u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL;
+       size_t group_ssid_len = 0;
 
        if (!wpa_s->global->p2p_init_wpa_s)
                return -1;
@@ -4877,7 +4987,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] [auto] */
+        * [ht40] [vht] [auto] [ssid=<hexdump>] */
 
        if (hwaddr_aton(cmd, addr))
                return -1;
@@ -4925,11 +5035,41 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
                        return -1;
        }
 
+       pos2 = os_strstr(pos, " freq2=");
+       if (pos2)
+               freq2 = atoi(pos2 + 7);
+
+       pos2 = os_strstr(pos, " max_oper_chwidth=");
+       if (pos2)
+               chwidth = atoi(pos2 + 18);
+
+       max_oper_chwidth = parse_freq(chwidth, freq2);
+       if (max_oper_chwidth < 0)
+               return -1;
+
+       pos2 = os_strstr(pos, " ssid=");
+       if (pos2) {
+               char *end;
+
+               pos2 += 6;
+               end = os_strchr(pos2, ' ');
+               if (!end)
+                       group_ssid_len = os_strlen(pos2) / 2;
+               else
+                       group_ssid_len = (end - pos2) / 2;
+               if (group_ssid_len == 0 || group_ssid_len > SSID_MAX_LEN ||
+                   hexstr2bin(pos2, _group_ssid, group_ssid_len) < 0)
+                       return -1;
+               group_ssid = _group_ssid;
+       }
+
        if (os_strncmp(pos, "pin", 3) == 0) {
                /* Request random PIN (to be displayed) and enable the PIN */
                wps_method = WPS_PIN_DISPLAY;
        } else if (os_strncmp(pos, "pbc", 3) == 0) {
                wps_method = WPS_PBC;
+       } else if (os_strstr(pos, "p2ps") != NULL) {
+               wps_method = WPS_P2PS;
        } else {
                pin = pos;
                pos = os_strchr(pin, ' ');
@@ -4938,8 +5078,6 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
                        *pos++ = '\0';
                        if (os_strncmp(pos, "display", 7) == 0)
                                wps_method = WPS_PIN_DISPLAY;
-                       else if (os_strncmp(pos, "p2ps", 4) == 0)
-                               wps_method = WPS_P2PS;
                }
                if (!wps_pin_str_valid(pin)) {
                        os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
@@ -4949,8 +5087,9 @@ 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, persistent_id, pd,
-                                  ht40, vht);
+                                  auth, go_intent, freq, freq2, persistent_id,
+                                  pd, ht40, vht, max_oper_chwidth,
+                                  group_ssid, group_ssid_len);
        if (new_pin == -2) {
                os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
                return 25;
@@ -5505,7 +5644,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
        struct wpa_ssid *ssid;
        u8 *_peer = NULL, peer[ETH_ALEN];
        int freq = 0, pref_freq = 0;
-       int ht40, vht;
+       int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
 
        id = atoi(cmd);
        pos = os_strstr(cmd, " peer=");
@@ -5543,8 +5682,20 @@ 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;
 
-       return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, vht,
-                              pref_freq);
+       pos = os_strstr(cmd, "freq2=");
+       if (pos)
+               freq2 = atoi(pos + 6);
+
+       pos = os_strstr(cmd, " max_oper_chwidth=");
+       if (pos)
+               chwidth = atoi(pos + 18);
+
+       max_oper_chwidth = parse_freq(chwidth, freq2);
+       if (max_oper_chwidth < 0)
+               return -1;
+
+       return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
+                              max_oper_chwidth, pref_freq);
 }
 
 
@@ -5591,7 +5742,8 @@ 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 ht40, int vht)
+                                        int id, int freq, int vht_center_freq2,
+                                        int ht40, int vht, int vht_chwidth)
 {
        struct wpa_ssid *ssid;
 
@@ -5603,8 +5755,9 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
-       return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, ht40, vht,
-                                            NULL, 0, 0);
+       return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq,
+                                            vht_center_freq2, 0, ht40, vht,
+                                            vht_chwidth, NULL, 0, 0);
 }
 
 
@@ -5613,11 +5766,14 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
        int freq = 0, persistent = 0, group_id = -1;
        int vht = wpa_s->conf->p2p_go_vht;
        int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+       int max_oper_chwidth, chwidth = 0, freq2 = 0;
        char *token, *context = NULL;
 
        while ((token = str_token(cmd, " ", &context))) {
                if (sscanf(token, "freq=%d", &freq) == 1 ||
-                   sscanf(token, "persistent=%d", &group_id) == 1) {
+                   sscanf(token, "freq2=%d", &freq2) == 1 ||
+                   sscanf(token, "persistent=%d", &group_id) == 1 ||
+                   sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1) {
                        continue;
                } else if (os_strcmp(token, "ht40") == 0) {
                        ht40 = 1;
@@ -5634,11 +5790,40 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
                }
        }
 
+       max_oper_chwidth = parse_freq(chwidth, freq2);
+       if (max_oper_chwidth < 0)
+               return -1;
+
        if (group_id >= 0)
                return p2p_ctrl_group_add_persistent(wpa_s, group_id,
-                                                    freq, ht40, vht);
+                                                    freq, freq2, ht40, vht,
+                                                    max_oper_chwidth);
+
+       return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht,
+                                 max_oper_chwidth);
+}
+
+
+static int p2p_ctrl_group_member(struct wpa_supplicant *wpa_s, const char *cmd,
+                                char *buf, size_t buflen)
+{
+       u8 dev_addr[ETH_ALEN];
+       struct wpa_ssid *ssid;
+       int res;
+       const u8 *iaddr;
+
+       ssid = wpa_s->current_ssid;
+       if (!wpa_s->global->p2p || !ssid || ssid->mode != WPAS_MODE_P2P_GO ||
+           hwaddr_aton(cmd, dev_addr))
+               return -1;
 
-       return wpas_p2p_group_add(wpa_s, persistent, freq, ht40, vht);
+       iaddr = p2p_group_get_client_interface_addr(wpa_s->p2p_group, dev_addr);
+       if (!iaddr)
+               return -1;
+       res = os_snprintf(buf, buflen, MACSTR, MAC2STR(iaddr));
+       if (os_snprintf_error(buflen, res))
+               return -1;
+       return res;
 }
 
 
@@ -5797,8 +5982,15 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
        }
 
        if (os_strcmp(cmd, "listen_channel") == 0) {
-               return p2p_set_listen_channel(wpa_s->global->p2p, 81,
-                                             atoi(param), 1);
+               char *pos;
+               u8 channel, op_class;
+
+               channel = atoi(param);
+               pos = os_strchr(param, ' ');
+               op_class = pos ? atoi(pos) : 81;
+
+               return p2p_set_listen_channel(wpa_s->global->p2p, op_class,
+                                             channel, 1);
        }
 
        if (os_strcmp(cmd, "ssid_postfix") == 0) {
@@ -6059,6 +6251,21 @@ static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd)
        return 0;
 }
 
+
+static int p2p_ctrl_iface_p2p_lo_start(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       int freq = 0, period = 0, interval = 0, count = 0;
+
+       if (sscanf(cmd, "%d %d %d %d", &freq, &period, &interval, &count) != 4)
+       {
+               wpa_printf(MSG_DEBUG,
+                          "CTRL: Invalid P2P LO Start parameter: '%s'", cmd);
+               return -1;
+       }
+
+       return wpas_p2p_lo_start(wpa_s, freq, period, interval, count);
+}
+
 #endif /* CONFIG_P2P */
 
 
@@ -6176,6 +6383,7 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
        u16 id[MAX_ANQP_INFO_ID];
        size_t num_id = 0;
        u32 subtypes = 0;
+       int get_cell_pref = 0;
 
        used = hwaddr_aton2(dst, dst_addr);
        if (used < 0)
@@ -6193,6 +6401,15 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
 #else /* CONFIG_HS20 */
                        return -1;
 #endif /* CONFIG_HS20 */
+               } else if (os_strncmp(pos, "mbo:", 4) == 0) {
+#ifdef CONFIG_MBO
+                       int num = atoi(pos + 4);
+                       if (num != MBO_ANQP_SUBTYPE_CELL_CONN_PREF)
+                               return -1;
+                       get_cell_pref = 1;
+#else /* CONFIG_MBO */
+                       return -1;
+#endif /* CONFIG_MBO */
                } else {
                        id[num_id] = atoi(pos);
                        if (id[num_id])
@@ -6207,7 +6424,8 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
        if (num_id == 0)
                return -1;
 
-       return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes);
+       return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes,
+                            get_cell_pref);
 }
 
 
@@ -6378,7 +6596,7 @@ static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
        if (subtypes == 0)
                return -1;
 
-       return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0);
+       return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0, 0);
 }
 
 
@@ -6401,7 +6619,7 @@ static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
 
        ret = hs20_anqp_send_req(wpa_s, addr,
                                 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
-                                buf, len);
+                                buf, len, 0);
 
        os_free(buf);
 
@@ -6447,14 +6665,59 @@ static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
 
        ret = hs20_anqp_send_req(wpa_s, dst_addr,
                                 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
-                                buf, len);
+                                buf, len, 0);
        os_free(buf);
 
        return ret;
 }
 
 
-static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd)
+static int get_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd, char *reply,
+                        int buflen)
+{
+       u8 dst_addr[ETH_ALEN];
+       int used;
+       char *ctx = NULL, *icon, *poffset, *psize;
+
+       used = hwaddr_aton2(cmd, dst_addr);
+       if (used < 0)
+               return -1;
+       cmd += used;
+
+       icon = str_token(cmd, " ", &ctx);
+       poffset = str_token(cmd, " ", &ctx);
+       psize = str_token(cmd, " ", &ctx);
+       if (!icon || !poffset || !psize)
+               return -1;
+
+       wpa_s->fetch_osu_icon_in_progress = 0;
+       return hs20_get_icon(wpa_s, dst_addr, icon, atoi(poffset), atoi(psize),
+                            reply, buflen);
+}
+
+
+static int del_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd)
+{
+       u8 dst_addr[ETH_ALEN];
+       int used;
+       char *icon;
+
+       if (!cmd[0])
+               return hs20_del_icon(wpa_s, NULL, NULL);
+
+       used = hwaddr_aton2(cmd, dst_addr);
+       if (used < 0)
+               return -1;
+
+       while (cmd[used] == ' ')
+               used++;
+       icon = cmd[used] ? &cmd[used] : NULL;
+
+       return hs20_del_icon(wpa_s, dst_addr, icon);
+}
+
+
+static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd, int inmem)
 {
        u8 dst_addr[ETH_ALEN];
        int used;
@@ -6470,7 +6733,7 @@ static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd)
 
        wpa_s->fetch_osu_icon_in_progress = 0;
        return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST),
-                                 (u8 *) icon, os_strlen(icon));
+                                 (u8 *) icon, os_strlen(icon), inmem);
 }
 
 #endif /* CONFIG_HS20 */
@@ -6560,14 +6823,27 @@ static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
 
 static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd)
 {
-       int query_reason;
+       int query_reason, list = 0;
 
        query_reason = atoi(cmd);
 
-       wpa_printf(MSG_DEBUG, "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d",
-                  query_reason);
+       cmd = os_strchr(cmd, ' ');
+       if (cmd) {
+               cmd++;
+               if (os_strncmp(cmd, "list", 4) == 0) {
+                       list = 1;
+               } else {
+                       wpa_printf(MSG_DEBUG, "WNM Query: Invalid option %s",
+                                  cmd);
+                       return -1;
+               }
+       }
 
-       return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason);
+       wpa_printf(MSG_DEBUG,
+                  "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d%s",
+                  query_reason, list ? " candidate list" : "");
+
+       return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason, list);
 }
 
 #endif /* CONFIG_WNM */
@@ -6632,6 +6908,28 @@ static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
 }
 
 
+static int wpas_ctrl_iface_signal_monitor(struct wpa_supplicant *wpa_s,
+                                         const char *cmd)
+{
+       const char *pos;
+       int threshold = 0;
+       int hysteresis = 0;
+
+       if (wpa_s->bgscan && wpa_s->bgscan_priv) {
+               wpa_printf(MSG_DEBUG,
+                          "Reject SIGNAL_MONITOR command - bgscan is active");
+               return -1;
+       }
+       pos = os_strstr(cmd, "THRESHOLD=");
+       if (pos)
+               threshold = atoi(pos + 10);
+       pos = os_strstr(cmd, "HYSTERESIS=");
+       if (pos)
+               hysteresis = atoi(pos + 11);
+       return wpa_drv_signal_monitor(wpa_s, threshold, hysteresis);
+}
+
+
 static int wpas_ctrl_iface_get_pref_freq_list(
        struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
 {
@@ -6679,6 +6977,34 @@ static int wpas_ctrl_iface_get_pref_freq_list(
 }
 
 
+static int wpas_ctrl_iface_driver_flags(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_flags);
+       if (os_snprintf_error(buflen, ret))
+               return -1;
+
+       pos = buf + ret;
+       end = buf + buflen;
+
+       for (i = 0; i < 64; i++) {
+               if (wpa_s->drv_flags & (1LLU << i)) {
+                       ret = os_snprintf(pos, end - pos, "%s\n",
+                                         driver_flag_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)
 {
@@ -6736,13 +7062,13 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
 
        /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
        vendor_id = strtoul(cmd, &pos, 16);
-       if (!isblank(*pos))
+       if (!isblank((unsigned char) *pos))
                return -EINVAL;
 
        subcmd = strtoul(pos, &pos, 10);
 
        if (*pos != '\0') {
-               if (!isblank(*pos++))
+               if (!isblank((unsigned char) *pos++))
                        return -EINVAL;
                data_len = os_strlen(pos);
        }
@@ -6790,10 +7116,20 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
 
        wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
 
+       wpas_abort_ongoing_scan(wpa_s);
+
+       if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+               /*
+                * Avoid possible auto connect re-connection on getting
+                * disconnected due to state flush.
+                */
+               wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+       }
+
 #ifdef CONFIG_P2P
+       wpas_p2p_group_remove(p2p_wpa_s, "*");
        wpas_p2p_cancel(p2p_wpa_s);
        p2p_ctrl_flush(p2p_wpa_s);
-       wpas_p2p_group_remove(p2p_wpa_s, "*");
        wpas_p2p_service_flush(p2p_wpa_s);
        p2p_wpa_s->global->p2p_disabled = 0;
        p2p_wpa_s->global->p2p_per_sta_psk = 0;
@@ -6803,12 +7139,15 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
        p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL;
        p2p_wpa_s->global->p2p_go_avoid_freq.num = 0;
        p2p_wpa_s->global->pending_p2ps_group = 0;
+       p2p_wpa_s->global->pending_p2ps_group_freq = 0;
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_WPS_TESTING
        wps_version_number = 0x20;
        wps_testing_dummy_cred = 0;
        wps_corrupt_pkhash = 0;
+       wps_force_auth_types_in_use = 0;
+       wps_force_encr_types_in_use = 0;
 #endif /* CONFIG_WPS_TESTING */
 #ifdef CONFIG_WPS
        wpa_s->wps_fragment_size = 0;
@@ -6820,7 +7159,6 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
 
 #ifdef CONFIG_TDLS
 #ifdef CONFIG_TDLS_TESTING
-       extern unsigned int tdls_testing;
        tdls_testing = 0;
 #endif /* CONFIG_TDLS_TESTING */
        wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL);
@@ -6866,7 +7204,10 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
        wpa_s->next_ssid = NULL;
 
 #ifdef CONFIG_INTERWORKING
+#ifdef CONFIG_HS20
        hs20_cancel_fetch_osu(wpa_s);
+       hs20_del_icon(wpa_s, NULL, NULL);
+#endif /* CONFIG_HS20 */
 #endif /* CONFIG_INTERWORKING */
 
        wpa_s->ext_mgmt_frame_handling = 0;
@@ -6874,6 +7215,11 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
 #ifdef CONFIG_TESTING_OPTIONS
        wpa_s->extra_roc_dur = 0;
        wpa_s->test_failure = WPAS_TEST_FAILURE_NONE;
+       wpa_s->p2p_go_csa_on_inv = 0;
+       wpa_s->ignore_auth_resp = 0;
+       wpa_s->ignore_assoc_disallow = 0;
+       wpa_s->reject_btm_req_reason = 0;
+       wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL);
 #endif /* CONFIG_TESTING_OPTIONS */
 
        wpa_s->disconnected = 0;
@@ -6891,6 +7237,11 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
        }
 
        eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+       wpa_s->wnmsleep_used = 0;
+
+#ifdef CONFIG_SME
+       wpa_s->sme.last_unprot_disconnect.sec = 0;
+#endif /* CONFIG_SME */
 }
 
 
@@ -6947,6 +7298,13 @@ static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit)
                        eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
                                             work, NULL);
 
+               /*
+                * work->type points to a buffer in ework, so need to replace
+                * that here with a fixed string to avoid use of freed memory
+                * in debug prints.
+                */
+               work->type = "freed-ext-work";
+               work->ctx = NULL;
                os_free(ework);
                return;
        }
@@ -7396,6 +7754,76 @@ static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s)
 }
 
 
+static int wpas_ctrl_iface_mgmt_rx_process(struct wpa_supplicant *wpa_s,
+                                          char *cmd)
+{
+       char *pos, *param;
+       size_t len;
+       u8 *buf;
+       int freq = 0, datarate = 0, ssi_signal = 0;
+       union wpa_event_data event;
+
+       if (!wpa_s->ext_mgmt_frame_handling)
+               return -1;
+
+       /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */
+
+       wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd);
+
+       pos = cmd;
+       param = os_strstr(pos, "freq=");
+       if (param) {
+               param += 5;
+               freq = atoi(param);
+       }
+
+       param = os_strstr(pos, " datarate=");
+       if (param) {
+               param += 10;
+               datarate = atoi(param);
+       }
+
+       param = os_strstr(pos, " ssi_signal=");
+       if (param) {
+               param += 12;
+               ssi_signal = atoi(param);
+       }
+
+       param = os_strstr(pos, " frame=");
+       if (param == NULL)
+               return -1;
+       param += 7;
+
+       len = os_strlen(param);
+       if (len & 1)
+               return -1;
+       len /= 2;
+
+       buf = os_malloc(len);
+       if (buf == NULL)
+               return -1;
+
+       if (hexstr2bin(param, buf, len) < 0) {
+               os_free(buf);
+               return -1;
+       }
+
+       os_memset(&event, 0, sizeof(event));
+       event.rx_mgmt.freq = freq;
+       event.rx_mgmt.frame = buf;
+       event.rx_mgmt.frame_len = len;
+       event.rx_mgmt.ssi_signal = ssi_signal;
+       event.rx_mgmt.datarate = datarate;
+       wpa_s->ext_mgmt_frame_handling = 0;
+       wpa_supplicant_event(wpa_s, EVENT_RX_MGMT, &event);
+       wpa_s->ext_mgmt_frame_handling = 1;
+
+       os_free(buf);
+
+       return 0;
+}
+
+
 static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd)
 {
        char *pos, *param;
@@ -7495,7 +7923,8 @@ static u16 ipv4_hdr_checksum(const void *buf, size_t len)
 #define HWSIM_PACKETLEN 1500
 #define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
 
-void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
+                             size_t len)
 {
        struct wpa_supplicant *wpa_s = ctx;
        const struct ether_header *eth;
@@ -7529,6 +7958,8 @@ static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
                                            char *cmd)
 {
        int enabled = atoi(cmd);
+       char *pos;
+       const char *ifname;
 
        if (!enabled) {
                if (wpa_s->l2_test) {
@@ -7542,7 +7973,13 @@ static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
        if (wpa_s->l2_test)
                return 0;
 
-       wpa_s->l2_test = l2_packet_init(wpa_s->ifname, wpa_s->own_addr,
+       pos = os_strstr(cmd, " ifname=");
+       if (pos)
+               ifname = pos + 8;
+       else
+               ifname = wpa_s->ifname;
+
+       wpa_s->l2_test = l2_packet_init(ifname, wpa_s->own_addr,
                                        ETHERTYPE_IP, wpas_data_test_rx,
                                        wpa_s, 1);
        if (wpa_s->l2_test == NULL)
@@ -7663,8 +8100,6 @@ done:
 static int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd)
 {
 #ifdef WPA_TRACE_BFD
-       extern char wpa_trace_fail_func[256];
-       extern unsigned int wpa_trace_fail_after;
        char *pos;
 
        wpa_trace_fail_after = atoi(cmd);
@@ -7687,9 +8122,6 @@ static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s,
                                    char *buf, size_t buflen)
 {
 #ifdef WPA_TRACE_BFD
-       extern char wpa_trace_fail_func[256];
-       extern unsigned int wpa_trace_fail_after;
-
        return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
                           wpa_trace_fail_func);
 #else /* WPA_TRACE_BFD */
@@ -7701,8 +8133,6 @@ static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s,
 static int wpas_ctrl_test_fail(struct wpa_supplicant *wpa_s, char *cmd)
 {
 #ifdef WPA_TRACE_BFD
-       extern char wpa_trace_test_fail_func[256];
-       extern unsigned int wpa_trace_test_fail_after;
        char *pos;
 
        wpa_trace_test_fail_after = atoi(cmd);
@@ -7725,9 +8155,6 @@ static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s,
                                    char *buf, size_t buflen)
 {
 #ifdef WPA_TRACE_BFD
-       extern char wpa_trace_test_fail_func[256];
-       extern unsigned int wpa_trace_test_fail_after;
-
        return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
                           wpa_trace_test_fail_func);
 #else /* WPA_TRACE_BFD */
@@ -7735,62 +8162,64 @@ static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s,
 #endif /* WPA_TRACE_BFD */
 }
 
-#endif /* CONFIG_TESTING_OPTIONS */
-
 
-static void wpas_ctrl_vendor_elem_update(struct wpa_supplicant *wpa_s)
+static void wpas_ctrl_event_test_cb(void *eloop_ctx, void *timeout_ctx)
 {
-       unsigned int i;
-       char buf[30];
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       int i, count = (intptr_t) timeout_ctx;
 
-       wpa_printf(MSG_DEBUG, "Update vendor elements");
+       wpa_printf(MSG_DEBUG, "TEST: Send %d control interface event messages",
+                  count);
+       for (i = 0; i < count; i++) {
+               wpa_msg_ctrl(wpa_s, MSG_INFO, "TEST-EVENT-MESSAGE %d/%d",
+                            i + 1, count);
+       }
+}
 
-       for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
-               if (wpa_s->vendor_elem[i]) {
-                       int res;
 
-                       res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
-                       if (!os_snprintf_error(sizeof(buf), res)) {
-                               wpa_hexdump_buf(MSG_DEBUG, buf,
-                                               wpa_s->vendor_elem[i]);
-                       }
-               }
-       }
+static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+       int count;
 
-#ifdef CONFIG_P2P
-       if (wpa_s->parent == wpa_s &&
-           wpa_s->global->p2p &&
-           !wpa_s->global->p2p_disabled)
-               p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem);
-#endif /* CONFIG_P2P */
+       count = atoi(cmd);
+       if (count <= 0)
+               return -1;
+
+       return eloop_register_timeout(0, 0, wpas_ctrl_event_test_cb, wpa_s,
+                                     (void *) (intptr_t) count);
 }
 
 
-static struct wpa_supplicant *
-wpas_ctrl_vendor_elem_iface(struct wpa_supplicant *wpa_s,
-                           enum wpa_vendor_elem_frame frame)
+static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s,
+                                  const char *cmd)
 {
-       switch (frame) {
-#ifdef CONFIG_P2P
-       case VENDOR_ELEM_PROBE_REQ_P2P:
-       case VENDOR_ELEM_PROBE_RESP_P2P:
-       case VENDOR_ELEM_PROBE_RESP_P2P_GO:
-       case VENDOR_ELEM_BEACON_P2P_GO:
-       case VENDOR_ELEM_P2P_PD_REQ:
-       case VENDOR_ELEM_P2P_PD_RESP:
-       case VENDOR_ELEM_P2P_GO_NEG_REQ:
-       case VENDOR_ELEM_P2P_GO_NEG_RESP:
-       case VENDOR_ELEM_P2P_GO_NEG_CONF:
-       case VENDOR_ELEM_P2P_INV_REQ:
-       case VENDOR_ELEM_P2P_INV_RESP:
-       case VENDOR_ELEM_P2P_ASSOC_REQ:
-               return wpa_s->parent;
-#endif /* CONFIG_P2P */
-       default:
-               return wpa_s;
+       struct wpabuf *buf;
+       size_t len;
+
+       len = os_strlen(cmd);
+       if (len & 1)
+               return -1;
+       len /= 2;
+
+       if (len == 0) {
+               buf = NULL;
+       } else {
+               buf = wpabuf_alloc(len);
+               if (buf == NULL)
+                       return -1;
+
+               if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+                       wpabuf_free(buf);
+                       return -1;
+               }
        }
+
+       wpa_sm_set_test_assoc_ie(wpa_s->wpa, buf);
+       return 0;
 }
 
+#endif /* CONFIG_TESTING_OPTIONS */
+
 
 static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
 {
@@ -7803,7 +8232,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
        frame = atoi(pos);
        if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
                return -1;
-       wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+       wpa_s = wpas_vendor_elem(wpa_s, frame);
 
        pos = os_strchr(pos, ' ');
        if (pos == NULL)
@@ -7834,7 +8263,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_ctrl_vendor_elem_update(wpa_s);
+               wpas_vendor_elem_update(wpa_s);
                return 0;
        }
 
@@ -7845,7 +8274,7 @@ 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);
-       wpas_ctrl_vendor_elem_update(wpa_s);
+       wpas_vendor_elem_update(wpa_s);
 
        return 0;
 }
@@ -7858,7 +8287,7 @@ static int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd,
 
        if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
                return -1;
-       wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+       wpa_s = wpas_vendor_elem(wpa_s, frame);
 
        if (wpa_s->vendor_elem[frame] == NULL)
                return 0;
@@ -7876,12 +8305,12 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
        size_t len;
        u8 *buf;
        struct ieee802_11_elems elems;
-       u8 *ie, *end;
+       int res;
 
        frame = atoi(pos);
        if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
                return -1;
-       wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+       wpa_s = wpas_vendor_elem(wpa_s, frame);
 
        pos = os_strchr(pos, ' ');
        if (pos == NULL)
@@ -7891,7 +8320,7 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
        if (*pos == '*') {
                wpabuf_free(wpa_s->vendor_elem[frame]);
                wpa_s->vendor_elem[frame] = NULL;
-               wpas_ctrl_vendor_elem_update(wpa_s);
+               wpas_vendor_elem_update(wpa_s);
                return 0;
        }
 
@@ -7919,65 +8348,149 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
                return -1;
        }
 
-       ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]);
-       end = ie + wpabuf_len(wpa_s->vendor_elem[frame]);
-
-       for (; ie + 1 < end; ie += 2 + ie[1]) {
-               if (ie + len > end)
-                       break;
-               if (os_memcmp(ie, buf, len) != 0)
-                       continue;
-
-               if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) {
-                       wpabuf_free(wpa_s->vendor_elem[frame]);
-                       wpa_s->vendor_elem[frame] = NULL;
-               } else {
-                       os_memmove(ie, ie + len,
-                                  end - (ie + len));
-                       wpa_s->vendor_elem[frame]->used -= len;
-               }
-               os_free(buf);
-               wpas_ctrl_vendor_elem_update(wpa_s);
-               return 0;
-       }
-
+       res = wpas_vendor_elem_remove(wpa_s, frame, buf, len);
        os_free(buf);
-
-       return -1;
+       return res;
 }
 
 
 static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep)
 {
        struct wpa_supplicant *wpa_s = ctx;
+       size_t len;
+       const u8 *data;
 
-       if (neighbor_rep) {
-               wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
-                            "length=%u",
-                            (unsigned int) wpabuf_len(neighbor_rep));
-               wpabuf_free(neighbor_rep);
-       } else {
+       /*
+        * Neighbor Report element (IEEE P802.11-REVmc/D5.0)
+        * BSSID[6]
+        * BSSID Information[4]
+        * Operating Class[1]
+        * Channel Number[1]
+        * PHY Type[1]
+        * Optional Subelements[variable]
+        */
+#define NR_IE_MIN_LEN (ETH_ALEN + 4 + 1 + 1 + 1)
+
+       if (!neighbor_rep || wpabuf_len(neighbor_rep) == 0) {
                wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED);
+               goto out;
+       }
+
+       data = wpabuf_head_u8(neighbor_rep);
+       len = wpabuf_len(neighbor_rep);
+
+       while (len >= 2 + NR_IE_MIN_LEN) {
+               const u8 *nr;
+               char lci[256 * 2 + 1];
+               char civic[256 * 2 + 1];
+               u8 nr_len = data[1];
+               const u8 *pos = data, *end;
+
+               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);
+                       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);
+                       goto out;
+               }
+               pos += 2;
+               end = pos + nr_len;
+
+               nr = pos;
+               pos += NR_IE_MIN_LEN;
+
+               lci[0] = '\0';
+               civic[0] = '\0';
+               while (end - pos > 2) {
+                       u8 s_id, s_len;
+
+                       s_id = *pos++;
+                       s_len = *pos++;
+                       if (s_len > end - pos)
+                               goto out;
+                       if (s_id == WLAN_EID_MEASURE_REPORT && s_len > 3) {
+                               /* Measurement Token[1] */
+                               /* Measurement Report Mode[1] */
+                               /* Measurement Type[1] */
+                               /* Measurement Report[variable] */
+                               switch (pos[2]) {
+                               case MEASURE_TYPE_LCI:
+                                       if (lci[0])
+                                               break;
+                                       wpa_snprintf_hex(lci, sizeof(lci),
+                                                        pos, s_len);
+                                       break;
+                               case MEASURE_TYPE_LOCATION_CIVIC:
+                                       if (civic[0])
+                                               break;
+                                       wpa_snprintf_hex(civic, sizeof(civic),
+                                                        pos, s_len);
+                                       break;
+                               }
+                       }
+
+                       pos += s_len;
+               }
+
+               wpa_msg(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
+                       "bssid=" MACSTR
+                       " info=0x%x op_class=%u chan=%u phy_type=%u%s%s%s%s",
+                       MAC2STR(nr), WPA_GET_LE32(nr + ETH_ALEN),
+                       nr[ETH_ALEN + 4], nr[ETH_ALEN + 5],
+                       nr[ETH_ALEN + 6],
+                       lci[0] ? " lci=" : "", lci,
+                       civic[0] ? " civic=" : "", civic);
+
+               data = end;
+               len -= 2 + nr_len;
        }
+
+out:
+       wpabuf_free(neighbor_rep);
 }
 
 
-static int wpas_ctrl_iface_send_neigbor_rep(struct wpa_supplicant *wpa_s,
-                                           char *cmd)
+static int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s,
+                                            char *cmd)
 {
-       struct wpa_ssid ssid;
-       struct wpa_ssid *ssid_p = NULL;
-       int ret = 0;
+       struct wpa_ssid_value ssid, *ssid_p = NULL;
+       int ret, lci = 0, civic = 0;
+       char *ssid_s;
 
-       if (os_strncmp(cmd, " ssid=", 6) == 0) {
-               ssid.ssid_len = os_strlen(cmd + 6);
-               if (ssid.ssid_len > SSID_MAX_LEN)
+       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");
                        return -1;
-               ssid.ssid = (u8 *) (cmd + 6);
+               }
+
                ssid_p = &ssid;
+
+               /*
+                * Move cmd after the SSID text that may include "lci" or
+                * "civic".
+                */
+               cmd = os_strchr(ssid_s + 6, ssid_s[5] == '"' ? '"' : ' ');
+               if (cmd)
+                       cmd++;
+
        }
 
-       ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p,
+       if (cmd && os_strstr(cmd, "lci"))
+               lci = 1;
+
+       if (cmd && os_strstr(cmd, "civic"))
+               civic = 1;
+
+       ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p, lci, civic,
                                                 wpas_ctrl_neighbor_rep_cb,
                                                 wpa_s);
 
@@ -8062,10 +8575,7 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
                        }
                } else if (wpa_s->sched_scanning &&
                           (type & MAC_ADDR_RAND_SCHED_SCAN)) {
-                       /* simulate timeout to restart the sched scan */
-                       wpa_s->sched_scan_timed_out = 1;
-                       wpa_s->prev_sched_ssid = NULL;
-                       wpa_supplicant_cancel_sched_scan(wpa_s);
+                       wpas_scan_restart_sched_scan(wpa_s);
                }
                return 0;
        }
@@ -8091,12 +8601,8 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
                wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
                                            addr, mask);
 
-               if (wpa_s->sched_scanning && !wpa_s->pno) {
-                       /* simulate timeout to restart the sched scan */
-                       wpa_s->sched_scan_timed_out = 1;
-                       wpa_s->prev_sched_ssid = NULL;
-                       wpa_supplicant_cancel_sched_scan(wpa_s);
-               }
+               if (wpa_s->sched_scanning && !wpa_s->pno)
+                       wpas_scan_restart_sched_scan(wpa_s);
        }
 
        if (type & MAC_ADDR_RAND_PNO) {
@@ -8112,6 +8618,29 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
 }
 
 
+static int wpas_ctrl_iface_pmksa(struct wpa_supplicant *wpa_s,
+                                char *buf, size_t buflen)
+{
+       size_t reply_len;
+
+       reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, buf, buflen);
+#ifdef CONFIG_AP
+       reply_len += wpas_ap_pmksa_cache_list(wpa_s, &buf[reply_len],
+                                             buflen - reply_len);
+#endif /* CONFIG_AP */
+       return reply_len;
+}
+
+
+static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s)
+{
+       wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+#ifdef CONFIG_AP
+       wpas_ap_pmksa_cache_flush(wpa_s);
+#endif /* CONFIG_AP */
+}
+
+
 static int wpas_ctrl_cmd_debug_level(const char *cmd)
 {
        if (os_strcmp(cmd, "PING") == 0 ||
@@ -8183,10 +8712,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                reply_len = wpa_supplicant_ctrl_iface_status(
                        wpa_s, buf + 6, reply, reply_size);
        } else if (os_strcmp(buf, "PMKSA") == 0) {
-               reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
-                                                   reply_size);
+               reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size);
        } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
-               wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+               wpas_ctrl_iface_pmksa_flush(wpa_s);
        } else if (os_strncmp(buf, "SET ", 4) == 0) {
                if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
                        reply_len = -1;
@@ -8354,6 +8882,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s,
                                                                buf + 18))
                        reply_len = -1;
+       } else if (os_strncmp(buf, "MESH_PEER_REMOVE ", 17) == 0) {
+               if (wpa_supplicant_ctrl_iface_mesh_peer_remove(wpa_s, buf + 17))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "MESH_PEER_ADD ", 14) == 0) {
+               if (wpa_supplicant_ctrl_iface_mesh_peer_add(wpa_s, buf + 14))
+                       reply_len = -1;
 #endif /* CONFIG_MESH */
 #ifdef CONFIG_P2P
        } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
@@ -8388,6 +8922,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
                if (p2p_ctrl_group_add(wpa_s, buf + 14))
                        reply_len = -1;
+       } else if (os_strncmp(buf, "P2P_GROUP_MEMBER ", 17) == 0) {
+               reply_len = p2p_ctrl_group_member(wpa_s, buf + 17, reply,
+                                                 reply_size);
        } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
                if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
                        reply_len = -1;
@@ -8453,6 +8990,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
                if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
                        reply_len = -1;
+       } else if (os_strncmp(buf, "P2P_LO_START ", 13) == 0) {
+               if (p2p_ctrl_iface_p2p_lo_start(wpa_s, buf + 13))
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "P2P_LO_STOP") == 0) {
+               if (wpas_p2p_lo_stop(wpa_s))
+                       reply_len = -1;
 #endif /* CONFIG_P2P */
 #ifdef CONFIG_WIFI_DISPLAY
        } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
@@ -8506,10 +9049,21 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
                        reply_len = -1;
        } else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) {
-               if (hs20_icon_request(wpa_s, buf + 18) < 0)
+               if (hs20_icon_request(wpa_s, buf + 18, 0) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "REQ_HS20_ICON ", 14) == 0) {
+               if (hs20_icon_request(wpa_s, buf + 14, 1) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "GET_HS20_ICON ", 14) == 0) {
+               reply_len = get_hs20_icon(wpa_s, buf + 14, reply, reply_size);
+       } else if (os_strncmp(buf, "DEL_HS20_ICON ", 14) == 0) {
+               if (del_hs20_icon(wpa_s, buf + 14) < 0)
                        reply_len = -1;
        } else if (os_strcmp(buf, "FETCH_OSU") == 0) {
-               if (hs20_fetch_osu(wpa_s) < 0)
+               if (hs20_fetch_osu(wpa_s, 0) < 0)
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "FETCH_OSU no-scan") == 0) {
+               if (hs20_fetch_osu(wpa_s, 1) < 0)
                        reply_len = -1;
        } else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) {
                hs20_cancel_fetch_osu(wpa_s);
@@ -8548,16 +9102,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                reply_len = wpa_supplicant_ctrl_iface_list_networks(
                        wpa_s, NULL, reply, reply_size);
        } else if (os_strcmp(buf, "DISCONNECT") == 0) {
-#ifdef CONFIG_SME
-               wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
-               wpa_s->reassociate = 0;
-               wpa_s->disconnected = 1;
-               wpa_supplicant_cancel_sched_scan(wpa_s);
-               wpa_supplicant_cancel_scan(wpa_s);
-               wpa_supplicant_deauthenticate(wpa_s,
-                                             WLAN_REASON_DEAUTH_LEAVING);
-               eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+               wpas_request_disconnection(wpa_s);
        } else if (os_strcmp(buf, "SCAN") == 0) {
                wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len);
        } else if (os_strncmp(buf, "SCAN ", 5) == 0) {
@@ -8565,6 +9110,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
                reply_len = wpa_supplicant_ctrl_iface_scan_results(
                        wpa_s, reply, reply_size);
+       } else if (os_strcmp(buf, "ABORT_SCAN") == 0) {
+               if (wpas_abort_ongoing_scan(wpa_s) < 0)
+                       reply_len = -1;
        } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
                if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
                        reply_len = -1;
@@ -8623,9 +9171,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
                reply_len = wpa_supplicant_global_iface_list(
                        wpa_s->global, reply, reply_size);
-       } else if (os_strcmp(buf, "INTERFACES") == 0) {
+       } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
                reply_len = wpa_supplicant_global_iface_interfaces(
-                       wpa_s->global, reply, reply_size);
+                       wpa_s->global, buf + 10, reply, reply_size);
        } else if (os_strncmp(buf, "BSS ", 4) == 0) {
                reply_len = wpa_supplicant_ctrl_iface_bss(
                        wpa_s, buf + 4, reply, reply_size);
@@ -8706,6 +9254,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
                reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
                                                       reply_size);
+       } else if (os_strncmp(buf, "SIGNAL_MONITOR", 14) == 0) {
+               if (wpas_ctrl_iface_signal_monitor(wpa_s, buf + 14))
+                       reply_len = -1;
        } else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) {
                reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
                                                       reply_size);
@@ -8714,6 +9265,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
                        reply_len = -1;
 #endif /* CONFIG_AUTOSCAN */
+       } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
+               reply_len = wpas_ctrl_iface_driver_flags(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,
@@ -8744,6 +9298,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                        reply_len = -1;
        } else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) {
                wpas_ctrl_iface_mgmt_tx_done(wpa_s);
+       } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) {
+               if (wpas_ctrl_iface_mgmt_rx_process(wpa_s, buf + 16) < 0)
+                       reply_len = -1;
        } else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) {
                if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0)
                        reply_len = -1;
@@ -8769,6 +9326,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                        reply_len = -1;
        } else if (os_strcmp(buf, "GET_FAIL") == 0) {
                reply_len = wpas_ctrl_get_fail(wpa_s, reply, reply_size);
+       } else if (os_strncmp(buf, "EVENT_TEST ", 11) == 0) {
+               if (wpas_ctrl_event_test(wpa_s, buf + 11) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) {
+               if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0)
+                       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)
@@ -8780,7 +9343,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0)
                        reply_len = -1;
        } else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) {
-               if (wpas_ctrl_iface_send_neigbor_rep(wpa_s, buf + 20))
+               if (wpas_ctrl_iface_send_neighbor_rep(wpa_s, buf + 20))
                        reply_len = -1;
        } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
                wpas_ctrl_iface_erp_flush(wpa_s);
@@ -8813,10 +9376,11 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
        struct wpa_supplicant *wpa_s;
        unsigned int create_iface = 0;
        u8 mac_addr[ETH_ALEN];
+       enum wpa_driver_if_type type = WPA_IF_STATION;
 
        /*
         * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
-        * TAB<bridge_ifname>[TAB<create>]
+        * TAB<bridge_ifname>[TAB<create>[TAB<interface_type>]]
         */
        wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
 
@@ -8884,9 +9448,22 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
                if (!extra[0])
                        break;
 
-               if (os_strcmp(extra, "create") == 0)
+               if (os_strcmp(extra, "create") == 0) {
                        create_iface = 1;
-               else {
+                       if (!pos)
+                               break;
+
+                       if (os_strcmp(pos, "sta") == 0) {
+                               type = WPA_IF_STATION;
+                       } else if (os_strcmp(pos, "ap") == 0) {
+                               type = WPA_IF_AP_BSS;
+                       } else {
+                               wpa_printf(MSG_DEBUG,
+                                          "INTERFACE_ADD unsupported interface type: '%s'",
+                                          pos);
+                               return -1;
+                       }
+               } else {
                        wpa_printf(MSG_DEBUG,
                                   "INTERFACE_ADD unsupported extra parameter: '%s'",
                                   extra);
@@ -8899,7 +9476,7 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
                           iface.ifname);
                if (!global->ifaces)
                        return -1;
-               if (wpa_drv_if_add(global->ifaces, WPA_IF_STATION, iface.ifname,
+               if (wpa_drv_if_add(global->ifaces, type, iface.ifname,
                                   NULL, NULL, NULL, mac_addr, NULL) < 0) {
                        wpa_printf(MSG_ERROR,
                                   "CTRL_IFACE interface creation failed");
@@ -9008,18 +9585,31 @@ static int wpa_supplicant_global_iface_list(struct wpa_global *global,
 
 
 static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
+                                                 const char *input,
                                                  char *buf, int len)
 {
        int res;
        char *pos, *end;
        struct wpa_supplicant *wpa_s;
+       int show_ctrl = 0;
+
+       if (input)
+               show_ctrl = !!os_strstr(input, "ctrl");
 
        wpa_s = global->ifaces;
        pos = buf;
        end = buf + len;
 
        while (wpa_s) {
-               res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
+               if (show_ctrl)
+                       res = os_snprintf(pos, end - pos, "%s ctrl_iface=%s\n",
+                                         wpa_s->ifname,
+                                         wpa_s->conf->ctrl_interface ?
+                                         wpa_s->conf->ctrl_interface : "N/A");
+               else
+                       res = os_snprintf(pos, end - pos, "%s\n",
+                                         wpa_s->ifname);
+
                if (os_snprintf_error(end - pos, res)) {
                        *pos = '\0';
                        break;
@@ -9085,6 +9675,7 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
                "P2P_LISTEN ",
                "P2P_GROUP_REMOVE ",
                "P2P_GROUP_ADD ",
+               "P2P_GROUP_MEMBER ",
                "P2P_PROV_DISC ",
                "P2P_SERV_DISC_REQ ",
                "P2P_SERV_DISC_CANCEL_REQ ",
@@ -9408,9 +9999,9 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
        } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
                reply_len = wpa_supplicant_global_iface_list(
                        global, reply, reply_size);
-       } else if (os_strcmp(buf, "INTERFACES") == 0) {
+       } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
                reply_len = wpa_supplicant_global_iface_interfaces(
-                       global, reply, reply_size);
+                       global, buf + 10, reply, reply_size);
 #ifdef CONFIG_FST
        } else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) {
                reply_len = wpas_global_ctrl_iface_fst_attach(global, buf + 11,
@@ -9456,7 +10047,6 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
                                                          reply_size);
 #ifdef CONFIG_MODULE_TESTS
        } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
-               int wpas_module_tests(void);
                if (wpas_module_tests() < 0)
                        reply_len = -1;
 #endif /* CONFIG_MODULE_TESTS */
index 76f69f2..0dc0937 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / UDP socket -based control interface
- * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -48,13 +48,33 @@ struct ctrl_iface_priv {
        u8 cookie[COOKIE_LEN];
 };
 
+struct ctrl_iface_global_priv {
+       int sock;
+       struct wpa_ctrl_dst *ctrl_dst;
+       u8 cookie[COOKIE_LEN];
+};
 
-static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+
+static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
+                                          const char *ifname, int sock,
+                                          struct wpa_ctrl_dst **head,
                                           int level, const char *buf,
                                           size_t len);
 
 
-static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
+static void wpas_ctrl_iface_free_dst(struct wpa_ctrl_dst *dst)
+{
+       struct wpa_ctrl_dst *prev;
+
+       while (dst) {
+               prev = dst;
+               dst = dst->next;
+               os_free(prev);
+       }
+}
+
+
+static int wpa_supplicant_ctrl_iface_attach(struct wpa_ctrl_dst **head,
 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
                                            struct sockaddr_in6 *from,
 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
@@ -73,8 +93,8 @@ static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
        os_memcpy(&dst->addr, from, sizeof(*from));
        dst->addrlen = fromlen;
        dst->debug_level = MSG_INFO;
-       dst->next = priv->ctrl_dst;
-       priv->ctrl_dst = dst;
+       dst->next = *head;
+       *head = dst;
 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
        wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
                   inet_ntop(AF_INET6, &from->sin6_addr, addr, sizeof(*from)),
@@ -87,7 +107,7 @@ static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
 }
 
 
-static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
+static int wpa_supplicant_ctrl_iface_detach(struct wpa_ctrl_dst **head,
 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
                                            struct sockaddr_in6 *from,
 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
@@ -100,7 +120,7 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
        char addr[INET6_ADDRSTRLEN];
 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 
-       dst = priv->ctrl_dst;
+       dst = *head;
        while (dst) {
 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
                if (from->sin6_port == dst->addr.sin6_port &&
@@ -118,7 +138,7 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
                                   ntohs(from->sin_port));
 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                        if (prev == NULL)
-                               priv->ctrl_dst = dst->next;
+                               *head = dst->next;
                        else
                                prev->next = dst->next;
                        os_free(dst);
@@ -282,14 +302,16 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
                pos++;
 
        if (os_strcmp(pos, "ATTACH") == 0) {
-               if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))
+               if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
+                                                    &from, fromlen))
                        reply_len = 1;
                else {
                        new_attached = 1;
                        reply_len = 2;
                }
        } else if (os_strcmp(pos, "DETACH") == 0) {
-               if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen))
+               if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst,
+                                                    &from, fromlen))
                        reply_len = 1;
                else
                        reply_len = 2;
@@ -327,9 +349,28 @@ static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
                                             const char *txt, size_t len)
 {
        struct wpa_supplicant *wpa_s = ctx;
-       if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
+
+       if (!wpa_s)
                return;
-       wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
+
+       if (type != WPA_MSG_NO_GLOBAL && wpa_s->global->ctrl_iface) {
+               struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
+
+               if (priv->ctrl_dst) {
+                       wpa_supplicant_ctrl_iface_send(
+                               wpa_s,
+                               type != WPA_MSG_PER_INTERFACE ?
+                               NULL : wpa_s->ifname,
+                               priv->sock, &priv->ctrl_dst, level, txt, len);
+               }
+       }
+
+       if (type == WPA_MSG_ONLY_GLOBAL || !wpa_s->ctrl_iface)
+               return;
+
+       wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock,
+                                      &wpa_s->ctrl_iface->ctrl_dst,
+                                      level, txt, len);
 }
 
 
@@ -337,7 +378,9 @@ struct ctrl_iface_priv *
 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
 {
        struct ctrl_iface_priv *priv;
+       char port_str[40];
        int port = WPA_CTRL_IFACE_PORT;
+       char *pos;
 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
        struct sockaddr_in6 addr;
        int domain = PF_INET6;
@@ -356,6 +399,17 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
        if (wpa_s->conf->ctrl_interface == NULL)
                return priv;
 
+       pos = os_strstr(wpa_s->conf->ctrl_interface, "udp:");
+       if (pos) {
+               pos += 4;
+               port = atoi(pos);
+               if (port <= 0) {
+                       wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port: %s",
+                                  wpa_s->conf->ctrl_interface);
+                       goto fail;
+               }
+       }
+
        priv->sock = socket(domain, SOCK_DGRAM, 0);
        if (priv->sock < 0) {
                wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
@@ -392,6 +446,15 @@ try_again:
                goto fail;
        }
 
+       /* Update the ctrl_interface value to match the selected port */
+       os_snprintf(port_str, sizeof(port_str), "udp:%d", port);
+       os_free(wpa_s->conf->ctrl_interface);
+       wpa_s->conf->ctrl_interface = os_strdup(port_str);
+       if (!wpa_s->conf->ctrl_interface) {
+               wpa_msg(wpa_s, MSG_ERROR, "Failed to malloc ctrl_interface");
+               goto fail;
+       }
+
 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
        wpa_msg(wpa_s, MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
@@ -412,8 +475,6 @@ fail:
 
 void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
 {
-       struct wpa_ctrl_dst *dst, *prev;
-
        if (priv->sock > -1) {
                eloop_unregister_read_sock(priv->sock);
                if (priv->ctrl_dst) {
@@ -430,22 +491,19 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
                priv->sock = -1;
        }
 
-       dst = priv->ctrl_dst;
-       while (dst) {
-               prev = dst;
-               dst = dst->next;
-               os_free(prev);
-       }
+       wpas_ctrl_iface_free_dst(priv->ctrl_dst);
        os_free(priv);
 }
 
 
-static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
+                                          const char *ifname, int sock,
+                                          struct wpa_ctrl_dst **head,
                                           int level, const char *buf,
                                           size_t len)
 {
        struct wpa_ctrl_dst *dst, *next;
-       char levelstr[10];
+       char levelstr[64];
        int idx;
        char *sbuf;
        int llen;
@@ -453,11 +511,15 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
        char addr[INET6_ADDRSTRLEN];
 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 
-       dst = priv->ctrl_dst;
-       if (priv->sock < 0 || dst == NULL)
+       dst = *head;
+       if (sock < 0 || dst == NULL)
                return;
 
-       os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+       if (ifname)
+               os_snprintf(levelstr, sizeof(levelstr), "IFACE=%s <%d>",
+                           ifname, level);
+       else
+               os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
 
        llen = os_strlen(levelstr);
        sbuf = os_malloc(llen + len);
@@ -481,7 +543,7 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
                                   inet_ntoa(dst->addr.sin_addr),
                                   ntohs(dst->addr.sin_port));
 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
-                       if (sendto(priv->sock, sbuf, llen + len, 0,
+                       if (sendto(sock, sbuf, llen + len, 0,
                                   (struct sockaddr *) &dst->addr,
                                   sizeof(dst->addr)) < 0) {
                                wpa_printf(MSG_ERROR,
@@ -490,7 +552,7 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
                                dst->errors++;
                                if (dst->errors > 10) {
                                        wpa_supplicant_ctrl_iface_detach(
-                                               priv, &dst->addr,
+                                               head, &dst->addr,
                                                dst->addrlen);
                                }
                        } else
@@ -513,12 +575,6 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
 
 /* Global ctrl_iface */
 
-struct ctrl_iface_global_priv {
-       int sock;
-       u8 cookie[COOKIE_LEN];
-};
-
-
 static char *
 wpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv,
                                 size_t *reply_len)
@@ -546,9 +602,13 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
        struct ctrl_iface_global_priv *priv = sock_ctx;
        char buf[256], *pos;
        int res;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       struct sockaddr_in6 from;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        struct sockaddr_in from;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        socklen_t fromlen = sizeof(from);
-       char *reply;
+       char *reply = NULL;
        size_t reply_len;
        u8 cookie[COOKIE_LEN];
 
@@ -561,6 +621,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
        }
 
 #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
+#ifndef 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
@@ -572,6 +633,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
                           "source %s", inet_ntoa(from.sin_addr));
                return;
        }
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
 
        buf[res] = '\0';
@@ -603,17 +665,34 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
        while (*pos == ' ')
                pos++;
 
-       reply = wpa_supplicant_global_ctrl_iface_process(global, pos,
-                                                        &reply_len);
+       if (os_strcmp(pos, "ATTACH") == 0) {
+               if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
+                                                    &from, fromlen))
+                       reply_len = 1;
+               else
+                       reply_len = 2;
+       } else if (os_strcmp(pos, "DETACH") == 0) {
+               if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst,
+                                                    &from, fromlen))
+                       reply_len = 1;
+               else
+                       reply_len = 2;
+       } else {
+               reply = wpa_supplicant_global_ctrl_iface_process(global, pos,
+                                                                &reply_len);
+       }
 
  done:
        if (reply) {
                sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
                       fromlen);
                os_free(reply);
-       } else if (reply_len) {
+       } else if (reply_len == 1) {
                sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
                       fromlen);
+       } else if (reply_len == 2) {
+               sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
+                      fromlen);
        }
 }
 
@@ -623,6 +702,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
 {
        struct ctrl_iface_global_priv *priv;
        struct sockaddr_in addr;
+       char *pos;
        int port = WPA_GLOBAL_CTRL_IFACE_PORT;
 
        priv = os_zalloc(sizeof(*priv));
@@ -637,6 +717,17 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
        wpa_printf(MSG_DEBUG, "Global control interface '%s'",
                   global->params.ctrl_interface);
 
+       pos = os_strstr(global->params.ctrl_interface, "udp:");
+       if (pos) {
+               pos += 4;
+               port = atoi(pos);
+               if (port <= 0) {
+                       wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port %s",
+                                  global->params.ctrl_interface);
+                       goto fail;
+               }
+       }
+
        priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
        if (priv->sock < 0) {
                wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
@@ -655,7 +746,7 @@ try_again:
        if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                port++;
                if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) <
-                   WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT)
+                   WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos)
                        goto try_again;
                wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
                goto fail;
@@ -668,6 +759,7 @@ try_again:
        eloop_register_read_sock(priv->sock,
                                 wpa_supplicant_global_ctrl_iface_receive,
                                 global, priv);
+       wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
 
        return priv;
 
@@ -686,5 +778,7 @@ wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
                eloop_unregister_read_sock(priv->sock);
                close(priv->sock);
        }
+
+       wpas_ctrl_iface_free_dst(priv->ctrl_dst);
        os_free(priv);
 }
index 11f2814..4db712f 100644 (file)
@@ -15,7 +15,6 @@
 #include <fcntl.h>
 #ifdef __linux__
 #include <sys/ioctl.h>
-#include <linux/sockios.h>
 #endif /* __linux__ */
 #ifdef ANDROID
 #include <cutils/sockets.h>
@@ -24,6 +23,7 @@
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "utils/list.h"
+#include "common/ctrl_iface_common.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "config.h"
 #include "wpa_supplicant_i.h"
 
 /* Per-interface ctrl_iface */
 
-/**
- * struct wpa_ctrl_dst - Internal data structure of control interface monitors
- *
- * This structure is used to store information about registered control
- * interface monitors into struct wpa_supplicant. This data is private to
- * ctrl_iface_unix.c and should not be touched directly from other files.
- */
-struct wpa_ctrl_dst {
-       struct dl_list list;
-       struct sockaddr_un addr;
-       socklen_t addrlen;
-       int debug_level;
-       int errors;
-};
-
-
 struct ctrl_iface_priv {
        struct wpa_supplicant *wpa_s;
        int sock;
        struct dl_list ctrl_dst;
        int android_control_socket;
+       struct dl_list msg_queue;
+       unsigned int throttle_count;
 };
 
 
@@ -60,6 +46,17 @@ struct ctrl_iface_global_priv {
        int sock;
        struct dl_list ctrl_dst;
        int android_control_socket;
+       struct dl_list msg_queue;
+       unsigned int throttle_count;
+};
+
+struct ctrl_iface_msg {
+       struct dl_list list;
+       struct wpa_supplicant *wpa_s;
+       int level;
+       enum wpa_msg_type type;
+       const char *txt;
+       size_t len;
 };
 
 
@@ -92,7 +89,7 @@ static void wpas_ctrl_sock_debug(const char *title, int sock, const char *buf,
        if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0)
                sndbuf = -1;
 
-       if (ioctl(sock, SIOCOUTQ, &outq) < 0)
+       if (ioctl(sock, TIOCOUTQ, &outq) < 0)
                outq = -1;
 
        wpa_printf(level,
@@ -103,81 +100,29 @@ static void wpas_ctrl_sock_debug(const char *title, int sock, const char *buf,
 
 
 static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst,
-                                           struct sockaddr_un *from,
+                                           struct sockaddr_storage *from,
                                            socklen_t fromlen, int global)
 {
-       struct wpa_ctrl_dst *dst;
-       char addr_txt[200];
-
-       dst = os_zalloc(sizeof(*dst));
-       if (dst == NULL)
-               return -1;
-       os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
-       dst->addrlen = fromlen;
-       dst->debug_level = MSG_INFO;
-       dl_list_add(ctrl_dst, &dst->list);
-       printf_encode(addr_txt, sizeof(addr_txt),
-                     (u8 *) from->sun_path,
-                     fromlen - offsetof(struct sockaddr_un, sun_path));
-       wpa_printf(MSG_DEBUG, "CTRL_IFACE %smonitor attached %s",
-                  global ? "global " : "", addr_txt);
-       return 0;
+       return ctrl_iface_attach(ctrl_dst, from, fromlen);
 }
 
 
 static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst,
-                                           struct sockaddr_un *from,
+                                           struct sockaddr_storage *from,
                                            socklen_t fromlen)
 {
-       struct wpa_ctrl_dst *dst;
-
-       dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
-               if (fromlen == dst->addrlen &&
-                   os_memcmp(from->sun_path, dst->addr.sun_path,
-                             fromlen - offsetof(struct sockaddr_un, sun_path))
-                   == 0) {
-                       char addr_txt[200];
-                       printf_encode(addr_txt, sizeof(addr_txt),
-                                     (u8 *) from->sun_path,
-                                     fromlen -
-                                     offsetof(struct sockaddr_un, sun_path));
-                       wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s",
-                                  addr_txt);
-                       dl_list_del(&dst->list);
-                       os_free(dst);
-                       return 0;
-               }
-       }
-       return -1;
+       return ctrl_iface_detach(ctrl_dst, from, fromlen);
 }
 
 
 static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
-                                          struct sockaddr_un *from,
+                                          struct sockaddr_storage *from,
                                           socklen_t fromlen,
                                           char *level)
 {
-       struct wpa_ctrl_dst *dst;
-
        wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
 
-       dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) {
-               if (fromlen == dst->addrlen &&
-                   os_memcmp(from->sun_path, dst->addr.sun_path,
-                             fromlen - offsetof(struct sockaddr_un, sun_path))
-                   == 0) {
-                       char addr_txt[200];
-                       dst->debug_level = atoi(level);
-                       printf_encode(addr_txt, sizeof(addr_txt),
-                                     (u8 *) from->sun_path, fromlen -
-                                     offsetof(struct sockaddr_un, sun_path));
-                       wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level to %d for %s",
-                                  dst->debug_level, addr_txt);
-                       return 0;
-               }
-       }
-
-       return -1;
+       return ctrl_iface_level(&priv->ctrl_dst, from, fromlen, level);
 }
 
 
@@ -188,7 +133,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
        struct ctrl_iface_priv *priv = sock_ctx;
        char buf[4096];
        int res;
-       struct sockaddr_un from;
+       struct sockaddr_storage from;
        socklen_t fromlen = sizeof(from);
        char *reply = NULL, *reply_buf = NULL;
        size_t reply_len = 0;
@@ -334,33 +279,209 @@ static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
 }
 
 
+static int wpas_ctrl_iface_throttle(int sock)
+{
+#ifdef __linux__
+       socklen_t optlen;
+       int sndbuf, outq;
+
+       optlen = sizeof(sndbuf);
+       sndbuf = 0;
+       if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0 ||
+           ioctl(sock, TIOCOUTQ, &outq) < 0 ||
+           sndbuf <= 0 || outq < 0)
+               return 0;
+       return outq > sndbuf / 2;
+#else /* __linux__ */
+       return 0;
+#endif /* __linux__ */
+}
+
+
+static void wpas_ctrl_msg_send_pending_global(struct wpa_global *global)
+{
+       struct ctrl_iface_global_priv *gpriv;
+       struct ctrl_iface_msg *msg;
+
+       gpriv = global->ctrl_iface;
+       while (gpriv && !dl_list_empty(&gpriv->msg_queue) &&
+              !wpas_ctrl_iface_throttle(gpriv->sock)) {
+               msg = dl_list_first(&gpriv->msg_queue, struct ctrl_iface_msg,
+                                   list);
+               if (!msg)
+                       break;
+               dl_list_del(&msg->list);
+               wpa_supplicant_ctrl_iface_send(
+                       msg->wpa_s,
+                       msg->type != WPA_MSG_PER_INTERFACE ?
+                       NULL : msg->wpa_s->ifname,
+                       gpriv->sock, &gpriv->ctrl_dst, msg->level,
+                       msg->txt, msg->len, NULL, gpriv);
+               os_free(msg);
+       }
+}
+
+
+static void wpas_ctrl_msg_send_pending_iface(struct wpa_supplicant *wpa_s)
+{
+       struct ctrl_iface_priv *priv;
+       struct ctrl_iface_msg *msg;
+
+       priv = wpa_s->ctrl_iface;
+       while (priv && !dl_list_empty(&priv->msg_queue) &&
+              !wpas_ctrl_iface_throttle(priv->sock)) {
+               msg = dl_list_first(&priv->msg_queue, struct ctrl_iface_msg,
+                                   list);
+               if (!msg)
+                       break;
+               dl_list_del(&msg->list);
+               wpa_supplicant_ctrl_iface_send(wpa_s, NULL, priv->sock,
+                                              &priv->ctrl_dst, msg->level,
+                                              msg->txt, msg->len, priv, NULL);
+               os_free(msg);
+       }
+}
+
+
+static void wpas_ctrl_msg_queue_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       struct ctrl_iface_priv *priv;
+       struct ctrl_iface_global_priv *gpriv;
+       int sock = -1, gsock = -1;
+
+       wpas_ctrl_msg_send_pending_global(wpa_s->global);
+       wpas_ctrl_msg_send_pending_iface(wpa_s);
+
+       priv = wpa_s->ctrl_iface;
+       if (priv && !dl_list_empty(&priv->msg_queue))
+               sock = priv->sock;
+
+       gpriv = wpa_s->global->ctrl_iface;
+       if (gpriv && !dl_list_empty(&gpriv->msg_queue))
+               gsock = gpriv->sock;
+
+       if (sock > -1 || gsock > -1) {
+               /* Continue pending message transmission from a timeout */
+               wpa_printf(MSG_MSGDUMP,
+                          "CTRL: Had to throttle pending event message transmission for (sock %d gsock %d)",
+                          sock, gsock);
+               eloop_register_timeout(0, 20000, wpas_ctrl_msg_queue_timeout,
+                                      wpa_s, NULL);
+       }
+}
+
+
+static void wpas_ctrl_msg_queue(struct dl_list *queue,
+                               struct wpa_supplicant *wpa_s, int level,
+                               enum wpa_msg_type type,
+                               const char *txt, size_t len)
+{
+       struct ctrl_iface_msg *msg;
+
+       msg = os_zalloc(sizeof(*msg) + len);
+       if (!msg)
+               return;
+
+       msg->wpa_s = wpa_s;
+       msg->level = level;
+       msg->type = type;
+       os_memcpy(msg + 1, txt, len);
+       msg->txt = (const char *) (msg + 1);
+       msg->len = len;
+       dl_list_add_tail(queue, &msg->list);
+       eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, wpa_s, NULL);
+       eloop_register_timeout(0, 0, wpas_ctrl_msg_queue_timeout, wpa_s, NULL);
+}
+
+
+static void wpas_ctrl_msg_queue_limit(unsigned int throttle_count,
+                                     struct dl_list *queue)
+{
+       struct ctrl_iface_msg *msg;
+
+       if (throttle_count < 2000)
+               return;
+
+       msg = dl_list_first(queue, struct ctrl_iface_msg, list);
+       if (msg) {
+               wpa_printf(MSG_DEBUG, "CTRL: Dropped oldest pending message");
+               dl_list_del(&msg->list);
+               os_free(msg);
+       }
+}
+
+
 static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
                                             enum wpa_msg_type type,
                                             const char *txt, size_t len)
 {
        struct wpa_supplicant *wpa_s = ctx;
+       struct ctrl_iface_priv *priv;
+       struct ctrl_iface_global_priv *gpriv;
 
        if (wpa_s == NULL)
                return;
 
-       if (type != WPA_MSG_NO_GLOBAL && wpa_s->global->ctrl_iface) {
-               struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
-               if (!dl_list_empty(&priv->ctrl_dst)) {
+       gpriv = wpa_s->global->ctrl_iface;
+
+       if (type != WPA_MSG_NO_GLOBAL && gpriv &&
+           !dl_list_empty(&gpriv->ctrl_dst)) {
+               if (!dl_list_empty(&gpriv->msg_queue) ||
+                   wpas_ctrl_iface_throttle(gpriv->sock)) {
+                       if (gpriv->throttle_count == 0) {
+                               wpa_printf(MSG_MSGDUMP,
+                                          "CTRL: Had to throttle global event message for sock %d",
+                                          gpriv->sock);
+                       }
+                       gpriv->throttle_count++;
+                       wpas_ctrl_msg_queue_limit(gpriv->throttle_count,
+                                                 &gpriv->msg_queue);
+                       wpas_ctrl_msg_queue(&gpriv->msg_queue, wpa_s, level,
+                                           type, txt, len);
+               } else {
+                       if (gpriv->throttle_count) {
+                               wpa_printf(MSG_MSGDUMP,
+                                          "CTRL: Had to throttle %u global event message(s) for sock %d",
+                                          gpriv->throttle_count, gpriv->sock);
+                       }
+                       gpriv->throttle_count = 0;
                        wpa_supplicant_ctrl_iface_send(
                                wpa_s,
                                type != WPA_MSG_PER_INTERFACE ?
                                NULL : wpa_s->ifname,
-                               priv->sock, &priv->ctrl_dst, level, txt, len,
-                               NULL, priv);
+                               gpriv->sock, &gpriv->ctrl_dst, level,
+                               txt, len, NULL, gpriv);
                }
        }
 
-       if (type == WPA_MSG_ONLY_GLOBAL || wpa_s->ctrl_iface == NULL)
-               return;
-       wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock,
-                                      &wpa_s->ctrl_iface->ctrl_dst,
-                                      level, txt, len, wpa_s->ctrl_iface,
-                                      NULL);
+       priv = wpa_s->ctrl_iface;
+
+       if (type != WPA_MSG_ONLY_GLOBAL && priv) {
+               if (!dl_list_empty(&priv->msg_queue) ||
+                   wpas_ctrl_iface_throttle(priv->sock)) {
+                       if (priv->throttle_count == 0) {
+                               wpa_printf(MSG_MSGDUMP,
+                                          "CTRL: Had to throttle event message for sock %d",
+                                          priv->sock);
+                       }
+                       priv->throttle_count++;
+                       wpas_ctrl_msg_queue_limit(priv->throttle_count,
+                                                 &priv->msg_queue);
+                       wpas_ctrl_msg_queue(&priv->msg_queue, wpa_s, level,
+                                           type, txt, len);
+               } else {
+                       if (priv->throttle_count) {
+                               wpa_printf(MSG_MSGDUMP,
+                                          "CTRL: Had to throttle %u event message(s) for sock %d",
+                                          priv->throttle_count, priv->sock);
+                       }
+                       priv->throttle_count = 0;
+                       wpa_supplicant_ctrl_iface_send(wpa_s, NULL, priv->sock,
+                                                      &priv->ctrl_dst, level,
+                                                      txt, len, priv, NULL);
+               }
+       }
 }
 
 
@@ -578,6 +699,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
        if (priv == NULL)
                return NULL;
        dl_list_init(&priv->ctrl_dst);
+       dl_list_init(&priv->msg_queue);
        priv->wpa_s = wpa_s;
        priv->sock = -1;
 
@@ -671,6 +793,8 @@ static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
 void wpa_supplicant_ctrl_iface_deinit(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->sock > -1) {
                char *fname;
@@ -724,8 +848,26 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
 
 free_dst:
        dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst,
-                             list)
+                             list) {
+               dl_list_del(&dst->list);
                os_free(dst);
+       }
+       dl_list_for_each_safe(msg, prev_msg, &priv->msg_queue,
+                             struct ctrl_iface_msg, list) {
+               dl_list_del(&msg->list);
+               os_free(msg);
+       }
+       gpriv = priv->wpa_s->global->ctrl_iface;
+       if (gpriv) {
+               dl_list_for_each_safe(msg, prev_msg, &gpriv->msg_queue,
+                                     struct ctrl_iface_msg, list) {
+                       if (msg->wpa_s == priv->wpa_s) {
+                               dl_list_del(&msg->list);
+                               os_free(msg);
+                       }
+               }
+       }
+       eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, priv->wpa_s, NULL);
        os_free(priv);
 }
 
@@ -785,33 +927,31 @@ static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
 
        dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
                int _errno;
-               char addr_txt[200];
+               char txt[200];
 
                if (level < dst->debug_level)
                        continue;
 
-               printf_encode(addr_txt, sizeof(addr_txt),
-                             (u8 *) dst->addr.sun_path, dst->addrlen -
-                             offsetof(struct sockaddr_un, sun_path));
                msg.msg_name = (void *) &dst->addr;
                msg.msg_namelen = dst->addrlen;
                wpas_ctrl_sock_debug("ctrl_sock-sendmsg", sock, buf, len);
                if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) {
-                       wpa_printf(MSG_MSGDUMP,
-                                  "CTRL_IFACE monitor sent successfully to %s",
-                                  addr_txt);
+                       sockaddr_print(MSG_MSGDUMP,
+                                      "CTRL_IFACE monitor sent successfully to",
+                                      &dst->addr, dst->addrlen);
                        dst->errors = 0;
                        continue;
                }
 
                _errno = errno;
-               wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor[%s]: %d - %s",
-                          addr_txt, errno, strerror(errno));
+               os_snprintf(txt, sizeof(txt), "CTRL_IFACE monitor: %d (%s) for",
+                           _errno, strerror(_errno));
+               sockaddr_print(MSG_DEBUG, txt, &dst->addr, dst->addrlen);
                dst->errors++;
 
                if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) {
-                       wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor %s that cannot receive messages",
-                               addr_txt);
+                       sockaddr_print(MSG_INFO, "CTRL_IFACE: Detach monitor that cannot receive messages:",
+                                      &dst->addr, dst->addrlen);
                        wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr,
                                                         dst->addrlen);
                }
@@ -845,9 +985,12 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
 {
        char buf[256];
        int res;
-       struct sockaddr_un from;
+       struct sockaddr_storage from;
        socklen_t fromlen = sizeof(from);
 
+       if (priv->sock == -1)
+               return;
+
        for (;;) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to "
                           "attach", priv->wpa_s->ifname);
@@ -905,7 +1048,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
        struct ctrl_iface_global_priv *priv = sock_ctx;
        char buf[4096];
        int res;
-       struct sockaddr_un from;
+       struct sockaddr_storage from;
        socklen_t fromlen = sizeof(from);
        char *reply = NULL, *reply_buf = NULL;
        size_t reply_len;
@@ -1155,6 +1298,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
        if (priv == NULL)
                return NULL;
        dl_list_init(&priv->ctrl_dst);
+       dl_list_init(&priv->msg_queue);
        priv->global = global;
        priv->sock = -1;
 
@@ -1204,6 +1348,7 @@ void
 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
 {
        struct wpa_ctrl_dst *dst, *prev;
+       struct ctrl_iface_msg *msg, *prev_msg;
 
        if (priv->sock >= 0) {
                eloop_unregister_read_sock(priv->sock);
@@ -1212,7 +1357,14 @@ wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
        if (priv->global->params.ctrl_interface)
                unlink(priv->global->params.ctrl_interface);
        dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst,
-                             list)
+                             list) {
+               dl_list_del(&dst->list);
                os_free(dst);
+       }
+       dl_list_for_each_safe(msg, prev_msg, &priv->msg_queue,
+                             struct ctrl_iface_msg, list) {
+               dl_list_del(&msg->list);
+               os_free(msg);
+       }
        os_free(priv);
 }
index c091234..382dcb3 100644 (file)
         <policy context="default">
                 <deny own="fi.epitest.hostap.WPASupplicant"/>
                 <deny send_destination="fi.epitest.hostap.WPASupplicant"/>
-                <deny send_interface="fi.epitest.hostap.WPASupplicant"/>
 
                 <deny own="fi.w1.wpa_supplicant1"/>
                 <deny send_destination="fi.w1.wpa_supplicant1"/>
-                <deny send_interface="fi.w1.wpa_supplicant1"/>
                 <deny receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/>
         </policy>
 </busconfig>
index a551ccd..95eb4bc 100644 (file)
@@ -13,6 +13,8 @@
 
 #include <dbus/dbus.h>
 
+struct wpa_dbus_property_desc;
+
 struct wpas_dbus_priv {
        DBusConnection *con;
        int should_dispatch;
@@ -20,9 +22,13 @@ struct wpas_dbus_priv {
        u32 next_objid;
        int dbus_new_initialized;
 
-#if defined(CONFIG_CTRL_IFACE_DBUS_NEW) && defined(CONFIG_AP)
+#if defined(CONFIG_CTRL_IFACE_DBUS_NEW)
+       struct wpa_dbus_property_desc *all_interface_properties;
+       int globals_start;
+#if defined(CONFIG_AP)
        int dbus_noc_refcnt;
-#endif /* CONFIG_CTRL_IFACE_DBUS_NEW && CONFIG_AP */
+#endif /* CONFIG_AP */
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
 };
 
 #endif /* DBUS_COMMON_I_H */
index a0c44eb..e4e9b8d 100644 (file)
@@ -205,24 +205,6 @@ dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
 
 
 /**
- * Add a byte entry to the dict.
- *
- * @param iter_dict A valid DBusMessageIter returned from
- *    wpa_dbus_dict_open_write()
- * @param key The key of the dict item
- * @param value The byte value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict,
-                                     const char *key, const char value)
-{
-       return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_BYTE,
-                                             &value);
-}
-
-
-/**
  * Add a boolean entry to the dict.
  *
  * @param iter_dict A valid DBusMessageIter returned from
@@ -317,62 +299,6 @@ dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
 
 
 /**
- * Add a 64-bit integer entry to the dict.
- *
- * @param iter_dict A valid DBusMessageIter returned from
- *    wpa_dbus_dict_open_write()
- * @param key The key of the dict item
- * @param value The 64-bit integer value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict,
-                                      const char *key,
-                                      const dbus_int64_t value)
-{
-       return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT64,
-                                             &value);
-}
-
-
-/**
- * Add a 64-bit unsigned integer entry to the dict.
- *
- * @param iter_dict A valid DBusMessageIter returned from
- *    wpa_dbus_dict_open_write()
- * @param key The key of the dict item
- * @param value The 64-bit unsigned integer value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
-                                       const char *key,
-                                       const dbus_uint64_t value)
-{
-       return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64,
-                                             &value);
-}
-
-
-/**
- * Add a double-precision floating point entry to the dict.
- *
- * @param iter_dict A valid DBusMessageIter returned from
- *    wpa_dbus_dict_open_write()
- * @param key The key of the dict item
- * @param value The double-precision floating point value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict,
-                                       const char *key, const double value)
-{
-       return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_DOUBLE,
-                                             &value);
-}
-
-
-/**
  * Add a DBus object path entry to the dict.
  *
  * @param iter_dict A valid DBusMessageIter returned from
index b068431..94a0efd 100644 (file)
@@ -26,9 +26,6 @@ const char * wpa_dbus_type_as_string(const int type);
 dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
                                        const char *key, const char *value);
 
-dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict,
-                                     const char *key, const char value);
-
 dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict,
                                      const char *key,
                                      const dbus_bool_t value);
@@ -49,18 +46,6 @@ dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
                                        const char *key,
                                        const dbus_uint32_t value);
 
-dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict,
-                                      const char *key,
-                                      const dbus_int64_t value);
-
-dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
-                                       const char *key,
-                                       const dbus_uint64_t value);
-
-dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict,
-                                       const char *key,
-                                       const double value);
-
 dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict,
                                             const char *key,
                                             const char *value);
index 67d0e28..27b3012 100644 (file)
@@ -1207,7 +1207,7 @@ static int match_group_where_peer_is_client(struct p2p_group *group,
                                         cfg->ssid_len);
        if (wpa_s_go != NULL && wpa_s_go == data->wpa_s) {
                wpas_dbus_signal_peer_groups_changed(
-                       data->wpa_s->parent, data->info->p2p_device_addr);
+                       data->wpa_s->p2pdev, data->info->p2p_device_addr);
                return 0;
        }
 
@@ -1224,7 +1224,7 @@ static void signal_peer_groups_changed(struct p2p_peer_info *info,
        wpa_s_go = wpas_get_p2p_client_iface(data->wpa_s,
                                             info->p2p_device_addr);
        if (wpa_s_go != NULL && wpa_s_go == data->wpa_s) {
-               wpas_dbus_signal_peer_groups_changed(data->wpa_s->parent,
+               wpas_dbus_signal_peer_groups_changed(data->wpa_s->p2pdev,
                                                     info->p2p_device_addr);
                return;
        }
@@ -1254,14 +1254,11 @@ static void peer_groups_changed(struct wpa_supplicant *wpa_s)
  * irrespective of the role (client/GO) of the current device
  *
  * @wpa_s: %wpa_supplicant network interface data
- * @ssid: SSID object
  * @client: this device is P2P client
- * @network_id: network id of the group started, use instead of ssid->id
- *     to account for persistent groups
+ * @persistent: 0 - non persistent group, 1 - persistent group
  */
 void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
-                                       const struct wpa_ssid *ssid,
-                                       int client, int network_id)
+                                       int client, int persistent)
 {
        DBusMessage *msg;
        DBusMessageIter iter, dict_iter;
@@ -1300,6 +1297,7 @@ void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
                                              wpa_s->dbus_new_path) ||
            !wpa_dbus_dict_append_string(&dict_iter, "role",
                                         client ? "client" : "GO") ||
+           !wpa_dbus_dict_append_bool(&dict_iter, "persistent", persistent) ||
            !wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
                                              wpa_s->dbus_groupobj_path) ||
            !wpa_dbus_dict_close_write(&iter, &dict_iter)) {
@@ -1950,6 +1948,7 @@ void wpas_dbus_signal_p2p_invitation_received(struct wpa_supplicant *wpa_s,
        }
 
        dbus_connection_send(iface->con, msg, NULL);
+       dbus_message_unref(msg);
 }
 
 
@@ -2000,6 +1999,10 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
                prop = "DisconnectReason";
                flush = TRUE;
                break;
+       case WPAS_DBUS_PROP_ASSOC_STATUS_CODE:
+               prop = "AssocStatusCode";
+               flush = TRUE;
+               break;
        default:
                wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
                           __func__, property);
@@ -2172,41 +2175,54 @@ static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
                  END_ARGS
          }
        },
+       { "ExpectDisconnect", WPAS_DBUS_NEW_INTERFACE,
+         (WPADBusMethodHandler) wpas_dbus_handler_expect_disconnect,
+         {
+               END_ARGS
+         }
+       },
        { NULL, NULL, NULL, { END_ARGS } }
 };
 
 static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = {
        { "DebugLevel", WPAS_DBUS_NEW_INTERFACE, "s",
          wpas_dbus_getter_debug_level,
-         wpas_dbus_setter_debug_level
+         wpas_dbus_setter_debug_level,
+         NULL
        },
        { "DebugTimestamp", WPAS_DBUS_NEW_INTERFACE, "b",
          wpas_dbus_getter_debug_timestamp,
-         wpas_dbus_setter_debug_timestamp
+         wpas_dbus_setter_debug_timestamp,
+         NULL
        },
        { "DebugShowKeys", WPAS_DBUS_NEW_INTERFACE, "b",
          wpas_dbus_getter_debug_show_keys,
-         wpas_dbus_setter_debug_show_keys
+         wpas_dbus_setter_debug_show_keys,
+         NULL
        },
        { "Interfaces", WPAS_DBUS_NEW_INTERFACE, "ao",
          wpas_dbus_getter_interfaces,
+         NULL,
          NULL
        },
        { "EapMethods", WPAS_DBUS_NEW_INTERFACE, "as",
          wpas_dbus_getter_eap_methods,
+         NULL,
          NULL
        },
        { "Capabilities", WPAS_DBUS_NEW_INTERFACE, "as",
          wpas_dbus_getter_global_capabilities,
+         NULL,
          NULL
        },
 #ifdef CONFIG_WIFI_DISPLAY
        { "WFDIEs", WPAS_DBUS_NEW_INTERFACE, "ay",
          wpas_dbus_getter_global_wfd_ies,
-         wpas_dbus_setter_global_wfd_ies
+         wpas_dbus_setter_global_wfd_ies,
+         NULL
        },
 #endif /* CONFIG_WIFI_DISPLAY */
-       { NULL, NULL, NULL, NULL, NULL }
+       { NULL, NULL, NULL, NULL, NULL, NULL }
 };
 
 static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = {
@@ -2234,12 +2250,50 @@ static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = {
 };
 
 
+static char * uscore_to_dbus(const char *uscore)
+{
+       const char *p = uscore;
+       char *str, *s;
+       dbus_bool_t last_was_uscore = TRUE;
+
+       s = str = os_zalloc(os_strlen(uscore) + 1);
+       if (!str)
+               return NULL;
+       while (p && *p) {
+               if (*p == '_') {
+                       last_was_uscore = TRUE;
+               } else {
+                       *s++ = last_was_uscore ? toupper(*p) : *p;
+                       last_was_uscore = FALSE;
+               }
+               p++;
+       }
+
+       return str;
+}
+
+
+static int wpa_dbus_ctrl_iface_props_init(struct wpas_dbus_priv *priv);
+
+
+static void wpa_dbus_ctrl_iface_props_deinit(struct wpas_dbus_priv *priv)
+{
+       int idx = priv->globals_start;
+
+       /* Free all allocated property values */
+       while (priv->all_interface_properties[idx].dbus_property)
+               os_free((char *)
+                       priv->all_interface_properties[idx++].dbus_property);
+       os_free((char *) priv->all_interface_properties);
+}
+
+
 /**
  * wpas_dbus_ctrl_iface_init - Initialize dbus control interface
  * @global: Pointer to global data from wpa_supplicant_init()
  * Returns: 0 on success or -1 on failure
  *
- * Initialize the dbus control interface for wpa_supplicantand and start
+ * Initialize the dbus control interface for wpa_supplicant and start
  * receiving commands from external programs over the bus.
  */
 int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv)
@@ -2247,11 +2301,18 @@ int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv)
        struct wpa_dbus_object_desc *obj_desc;
        int ret;
 
+       ret = wpa_dbus_ctrl_iface_props_init(priv);
+       if (ret < 0) {
+               wpa_printf(MSG_ERROR,
+                          "dbus: Not enough memory to init interface properties");
+               return -1;
+       }
+
        obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
        if (!obj_desc) {
                wpa_printf(MSG_ERROR,
                           "Not enough memory to create object description");
-               return -1;
+               goto error;
        }
 
        wpas_dbus_register(obj_desc, priv->global, NULL,
@@ -2264,31 +2325,36 @@ int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv)
        ret = wpa_dbus_ctrl_iface_init(priv, WPAS_DBUS_NEW_PATH,
                                       WPAS_DBUS_NEW_SERVICE,
                                       obj_desc);
-       if (ret < 0)
+       if (ret < 0) {
                free_dbus_object_desc(obj_desc);
-       else
-               priv->dbus_new_initialized = 1;
+               goto error;
+       }
 
-       return ret;
+       priv->dbus_new_initialized = 1;
+       return 0;
+
+error:
+       wpa_dbus_ctrl_iface_props_deinit(priv);
+       return -1;
 }
 
 
 /**
  * wpas_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface for
  * wpa_supplicant
- * @iface: Pointer to dbus private data from wpas_dbus_init()
+ * @priv: Pointer to dbus private data from wpas_dbus_init()
  *
  * Deinitialize the dbus control interface that was initialized with
  * wpas_dbus_ctrl_iface_init().
  */
-void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *iface)
+void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *priv)
 {
-       if (!iface->dbus_new_initialized)
+       if (!priv->dbus_new_initialized)
                return;
        wpa_printf(MSG_DEBUG, "dbus: Unregister D-Bus object '%s'",
                   WPAS_DBUS_NEW_PATH);
-       dbus_connection_unregister_object_path(iface->con,
-                                              WPAS_DBUS_NEW_PATH);
+       dbus_connection_unregister_object_path(priv->con, WPAS_DBUS_NEW_PATH);
+       wpa_dbus_ctrl_iface_props_deinit(priv);
 }
 
 
@@ -2301,13 +2367,15 @@ static void wpa_dbus_free(void *ptr)
 static const struct wpa_dbus_property_desc wpas_dbus_network_properties[] = {
        { "Properties", WPAS_DBUS_NEW_IFACE_NETWORK, "a{sv}",
          wpas_dbus_getter_network_properties,
-         wpas_dbus_setter_network_properties
+         wpas_dbus_setter_network_properties,
+         NULL
        },
        { "Enabled", WPAS_DBUS_NEW_IFACE_NETWORK, "b",
          wpas_dbus_getter_enabled,
-         wpas_dbus_setter_enabled
+         wpas_dbus_setter_enabled,
+         NULL
        },
-       { NULL, NULL, NULL, NULL, NULL }
+       { NULL, NULL, NULL, NULL, NULL, NULL }
 };
 
 
@@ -2446,53 +2514,65 @@ int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid)
 static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
        { "SSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
          wpas_dbus_getter_bss_ssid,
+         NULL,
          NULL
        },
        { "BSSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
          wpas_dbus_getter_bss_bssid,
+         NULL,
          NULL
        },
        { "Privacy", WPAS_DBUS_NEW_IFACE_BSS, "b",
          wpas_dbus_getter_bss_privacy,
+         NULL,
          NULL
        },
        { "Mode", WPAS_DBUS_NEW_IFACE_BSS, "s",
          wpas_dbus_getter_bss_mode,
+         NULL,
          NULL
        },
        { "Signal", WPAS_DBUS_NEW_IFACE_BSS, "n",
          wpas_dbus_getter_bss_signal,
+         NULL,
          NULL
        },
        { "Frequency", WPAS_DBUS_NEW_IFACE_BSS, "q",
          wpas_dbus_getter_bss_frequency,
+         NULL,
          NULL
        },
        { "Rates", WPAS_DBUS_NEW_IFACE_BSS, "au",
          wpas_dbus_getter_bss_rates,
+         NULL,
          NULL
        },
        { "WPA", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
          wpas_dbus_getter_bss_wpa,
+         NULL,
          NULL
        },
        { "RSN", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
          wpas_dbus_getter_bss_rsn,
+         NULL,
          NULL
        },
        { "WPS", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
          wpas_dbus_getter_bss_wps,
+         NULL,
          NULL
        },
        { "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay",
          wpas_dbus_getter_bss_ies,
+         NULL,
          NULL
        },
        { "Age", WPAS_DBUS_NEW_IFACE_BSS, "u",
          wpas_dbus_getter_bss_age,
+         NULL,
          NULL
        },
-       { NULL, NULL, NULL, NULL, NULL }
+       { NULL, NULL, NULL, NULL, NULL, NULL }
 };
 
 
@@ -2992,131 +3072,202 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
          }
        },
 #endif /* CONFIG_TDLS */
+       { "VendorElemAdd", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_add,
+         {
+                 { "frame_id", "i", ARG_IN },
+                 { "ielems", "ay", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "VendorElemGet", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_get,
+         {
+                 { "frame_id", "i", ARG_IN },
+                 { "ielems", "ay", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "VendorElemRem", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_remove,
+         {
+                 { "frame_id", "i", ARG_IN },
+                 { "ielems", "ay", ARG_IN },
+                 END_ARGS
+         }
+       },
+#ifndef CONFIG_NO_CONFIG_WRITE
+       { "SaveConfig", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) wpas_dbus_handler_save_config,
+         {
+                 END_ARGS
+         }
+       },
+#endif /* CONFIG_NO_CONFIG_WRITE */
        { NULL, NULL, NULL, { END_ARGS } }
 };
 
 static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
        { "Capabilities", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}",
          wpas_dbus_getter_capabilities,
+         NULL,
          NULL
        },
        { "State", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
          wpas_dbus_getter_state,
+         NULL,
          NULL
        },
        { "Scanning", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
          wpas_dbus_getter_scanning,
+         NULL,
          NULL
        },
        { "ApScan", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
          wpas_dbus_getter_ap_scan,
-         wpas_dbus_setter_ap_scan
+         wpas_dbus_setter_ap_scan,
+         NULL
        },
        { "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
          wpas_dbus_getter_bss_expire_age,
-         wpas_dbus_setter_bss_expire_age
+         wpas_dbus_setter_bss_expire_age,
+         NULL
        },
        { "BSSExpireCount", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
          wpas_dbus_getter_bss_expire_count,
-         wpas_dbus_setter_bss_expire_count
+         wpas_dbus_setter_bss_expire_count,
+         NULL
        },
        { "Country", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
          wpas_dbus_getter_country,
-         wpas_dbus_setter_country
+         wpas_dbus_setter_country,
+         NULL
        },
        { "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
          wpas_dbus_getter_ifname,
+         NULL,
          NULL
        },
        { "Driver", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
          wpas_dbus_getter_driver,
+         NULL,
          NULL
        },
        { "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
          wpas_dbus_getter_bridge_ifname,
+         NULL,
+         NULL
+       },
+       { "ConfigFile", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+         wpas_dbus_getter_config_file,
+         NULL,
          NULL
        },
        { "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
          wpas_dbus_getter_current_bss,
+         NULL,
          NULL
        },
        { "CurrentNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
          wpas_dbus_getter_current_network,
+         NULL,
          NULL
        },
        { "CurrentAuthMode", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
          wpas_dbus_getter_current_auth_mode,
+         NULL,
          NULL
        },
        { "Blobs", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}",
          wpas_dbus_getter_blobs,
+         NULL,
          NULL
        },
        { "BSSs", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
          wpas_dbus_getter_bsss,
+         NULL,
          NULL
        },
        { "Networks", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
          wpas_dbus_getter_networks,
+         NULL,
          NULL
        },
        { "FastReauth", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
          wpas_dbus_getter_fast_reauth,
-         wpas_dbus_setter_fast_reauth
+         wpas_dbus_setter_fast_reauth,
+         NULL
        },
        { "ScanInterval", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
          wpas_dbus_getter_scan_interval,
-         wpas_dbus_setter_scan_interval
+         wpas_dbus_setter_scan_interval,
+         NULL
        },
        { "PKCS11EnginePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
          wpas_dbus_getter_pkcs11_engine_path,
+         NULL,
          NULL
        },
        { "PKCS11ModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
          wpas_dbus_getter_pkcs11_module_path,
+         NULL,
          NULL
        },
 #ifdef CONFIG_WPS
        { "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b",
          wpas_dbus_getter_process_credentials,
-         wpas_dbus_setter_process_credentials
+         wpas_dbus_setter_process_credentials,
+         NULL
        },
        { "ConfigMethods", WPAS_DBUS_NEW_IFACE_WPS, "s",
          wpas_dbus_getter_config_methods,
-         wpas_dbus_setter_config_methods
+         wpas_dbus_setter_config_methods,
+         NULL
        },
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_P2P
        { "P2PDeviceConfig", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
          wpas_dbus_getter_p2p_device_config,
-         wpas_dbus_setter_p2p_device_config
+         wpas_dbus_setter_p2p_device_config,
+         NULL
        },
        { "Peers", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
          wpas_dbus_getter_p2p_peers,
+         NULL,
          NULL
        },
        { "Role", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "s",
          wpas_dbus_getter_p2p_role,
+         NULL,
          NULL
        },
        { "Group", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
          wpas_dbus_getter_p2p_group,
+         NULL,
          NULL
        },
        { "PeerGO", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
          wpas_dbus_getter_p2p_peergo,
+         NULL,
          NULL
        },
        { "PersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
          wpas_dbus_getter_persistent_groups,
+         NULL,
          NULL
        },
 #endif /* CONFIG_P2P */
        { "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
          wpas_dbus_getter_disconnect_reason,
+         NULL,
+         NULL
+       },
+       { "AssocStatusCode", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+         wpas_dbus_getter_assoc_status_code,
+         NULL,
          NULL
        },
-       { NULL, NULL, NULL, NULL, NULL }
+       { NULL, NULL, NULL, NULL, NULL, NULL }
 };
 
 static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
@@ -3206,6 +3357,13 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
                  END_ARGS
          }
        },
+       { "DeviceFoundProperties", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+         {
+                 { "path", "o", ARG_OUT },
+                 { "properties", "a{sv}", ARG_OUT },
+                 END_ARGS
+         }
+       },
        { "DeviceLost", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
          {
                  { "path", "o", ARG_OUT },
@@ -3390,6 +3548,77 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
 };
 
 
+static int wpa_dbus_ctrl_iface_props_init(struct wpas_dbus_priv *priv)
+{
+       size_t all_size;
+       unsigned int i, j, count, num_const, num_globals;
+       const char *global_name;
+       static const char * const ignored_globals[] = {
+               "bss_expiration_age", "bss_expiration_scan_count",
+               "ap_scan", "country", "fast_reauth",
+               "pkcs11_engine_path", "pkcs11_module_path"
+       };
+
+       /* wpas_dbus_interface_properties terminates with a NULL element */
+       num_const = ARRAY_SIZE(wpas_dbus_interface_properties) - 1;
+
+       num_globals = wpa_config_get_num_global_field_names();
+       priv->globals_start = num_const;
+
+       /* allocate enough for all properties + terminating NULL element */
+       all_size = (num_globals + num_const + 1) *
+               sizeof(wpas_dbus_interface_properties[0]);
+       priv->all_interface_properties = os_zalloc(all_size);
+       if (!priv->all_interface_properties) {
+               wpa_printf(MSG_ERROR,
+                          "dbus: Not enough memory for interface properties");
+               return -1;
+       }
+
+       /* Copy constant interface properties to the start of the array */
+       os_memcpy(priv->all_interface_properties,
+                 wpas_dbus_interface_properties,
+                 sizeof(wpas_dbus_interface_properties));
+
+       /* Dynamically construct interface global properties */
+       for (i = 0, count = num_const; i < num_globals; i++) {
+               struct wpa_dbus_property_desc *desc;
+               int no_var = 0;
+
+               /* ignore globals that are actually just methods */
+               global_name = wpa_config_get_global_field_name(i, &no_var);
+               if (no_var)
+                       continue;
+               /* Ignore fields already explicitly exposed */
+               for (j = 0; j < ARRAY_SIZE(ignored_globals); j++) {
+                       if (os_strcmp(global_name, ignored_globals[j]) == 0)
+                               break;
+               }
+               if (j < ARRAY_SIZE(ignored_globals))
+                       continue;
+
+               desc = &priv->all_interface_properties[count++];
+               desc->dbus_property = uscore_to_dbus(global_name);
+               if (!desc->dbus_property) {
+                       wpa_printf(MSG_ERROR,
+                                  "dbus: Not enough memory for D-Bus property name");
+                       goto error;
+               }
+               desc->dbus_interface = WPAS_DBUS_NEW_IFACE_INTERFACE;
+               desc->type = "s";
+               desc->getter = wpas_dbus_getter_iface_global;
+               desc->setter = wpas_dbus_setter_iface_global;
+               desc->data = global_name;
+       }
+
+       return 0;
+
+error:
+       wpa_dbus_ctrl_iface_props_deinit(priv);
+       return -1;
+}
+
+
 /**
  * wpas_dbus_register_interface - Register an interface with D-Bus
  * @wpa_s: wpa_supplicant interface structure
@@ -3397,7 +3626,6 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
  */
 int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
 {
-
        struct wpa_dbus_object_desc *obj_desc = NULL;
        struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
        int next;
@@ -3423,7 +3651,7 @@ int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
        }
 
        wpas_dbus_register(obj_desc, wpa_s, NULL, wpas_dbus_interface_methods,
-                          wpas_dbus_interface_properties,
+                          ctrl_iface->all_interface_properties,
                           wpas_dbus_interface_signals);
 
        wpa_printf(MSG_DEBUG, "dbus: Register interface object '%s'",
@@ -3489,65 +3717,80 @@ int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
 static const struct wpa_dbus_property_desc wpas_dbus_p2p_peer_properties[] = {
        { "DeviceName", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
          wpas_dbus_getter_p2p_peer_device_name,
+         NULL,
          NULL
        },
        { "Manufacturer", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
          wpas_dbus_getter_p2p_peer_manufacturer,
+         NULL,
          NULL
        },
        { "ModelName", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
          wpas_dbus_getter_p2p_peer_modelname,
+         NULL,
          NULL
        },
        { "ModelNumber", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
          wpas_dbus_getter_p2p_peer_modelnumber,
+         NULL,
          NULL
        },
        { "SerialNumber", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
          wpas_dbus_getter_p2p_peer_serialnumber,
+         NULL,
          NULL
        },
        { "PrimaryDeviceType", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
          wpas_dbus_getter_p2p_peer_primary_device_type,
+         NULL,
          NULL
        },
        { "config_method", WPAS_DBUS_NEW_IFACE_P2P_PEER, "q",
          wpas_dbus_getter_p2p_peer_config_method,
+         NULL,
          NULL
        },
        { "level", WPAS_DBUS_NEW_IFACE_P2P_PEER, "i",
          wpas_dbus_getter_p2p_peer_level,
+         NULL,
          NULL
        },
        { "devicecapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
          wpas_dbus_getter_p2p_peer_device_capability,
+         NULL,
          NULL
        },
        { "groupcapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
          wpas_dbus_getter_p2p_peer_group_capability,
+         NULL,
          NULL
        },
        { "SecondaryDeviceTypes", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
          wpas_dbus_getter_p2p_peer_secondary_device_types,
+         NULL,
          NULL
        },
        { "VendorExtension", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
          wpas_dbus_getter_p2p_peer_vendor_extension,
+         NULL,
          NULL
        },
        { "IEs", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
          wpas_dbus_getter_p2p_peer_ies,
+         NULL,
          NULL
        },
        { "DeviceAddress", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
          wpas_dbus_getter_p2p_peer_device_address,
+         NULL,
          NULL
        },
        { "Groups", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ao",
          wpas_dbus_getter_p2p_peer_groups,
+         NULL,
          NULL
        },
-       { NULL, NULL, NULL, NULL, NULL }
+       { NULL, NULL, NULL, NULL, NULL, NULL }
 };
 
 static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = {
@@ -3569,12 +3812,13 @@ static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = {
  *     In case of peer objects, it would be emitted by either
  *     the "interface object" or by "peer objects"
  * @sig_name: signal name - DeviceFound
+ * @properties: Whether to add a second argument with object properties
  *
- * Notify listeners about event related with newly found p2p peer device
+ * Notify listeners about event related with p2p peer device
  */
 static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
                                  const u8 *dev_addr, const char *interface,
-                                 const char *sig_name)
+                                 const char *sig_name, int properties)
 {
        struct wpas_dbus_priv *iface;
        DBusMessage *msg;
@@ -3602,7 +3846,10 @@ static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
        dbus_message_iter_init_append(msg, &iter);
        path = peer_obj_path;
        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-                                           &path))
+                                           &path) ||
+           (properties && !wpa_dbus_get_object_properties(
+                   iface, peer_obj_path, WPAS_DBUS_NEW_IFACE_P2P_PEER,
+                   &iter)))
                wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
        else
                dbus_connection_send(iface->con, msg, NULL);
@@ -3623,7 +3870,11 @@ void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
 {
        wpas_dbus_signal_peer(wpa_s, dev_addr,
                              WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-                             "DeviceFound");
+                             "DeviceFound", FALSE);
+
+       wpas_dbus_signal_peer(wpa_s, dev_addr,
+                             WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+                             "DeviceFoundProperties", TRUE);
 }
 
 /**
@@ -3638,7 +3889,7 @@ void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
 {
        wpas_dbus_signal_peer(wpa_s, dev_addr,
                              WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-                             "DeviceLost");
+                             "DeviceLost", FALSE);
 }
 
 /**
@@ -3805,41 +4056,50 @@ void wpas_dbus_signal_peer_groups_changed(struct wpa_supplicant *wpa_s,
 static const struct wpa_dbus_property_desc wpas_dbus_p2p_group_properties[] = {
        { "Members", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ao",
          wpas_dbus_getter_p2p_group_members,
+         NULL,
          NULL
        },
        { "Group", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "o",
          wpas_dbus_getter_p2p_group,
+         NULL,
          NULL
        },
        { "Role", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
          wpas_dbus_getter_p2p_role,
+         NULL,
          NULL
        },
        { "SSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
          wpas_dbus_getter_p2p_group_ssid,
+         NULL,
          NULL
        },
        { "BSSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
          wpas_dbus_getter_p2p_group_bssid,
+         NULL,
          NULL
        },
        { "Frequency", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "q",
          wpas_dbus_getter_p2p_group_frequency,
+         NULL,
          NULL
        },
        { "Passphrase", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
          wpas_dbus_getter_p2p_group_passphrase,
+         NULL,
          NULL
        },
        { "PSK", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
          wpas_dbus_getter_p2p_group_psk,
+         NULL,
          NULL
        },
        { "WPSVendorExtensions", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "aay",
          wpas_dbus_getter_p2p_group_vendor_ext,
-         wpas_dbus_setter_p2p_group_vendor_ext
+         wpas_dbus_setter_p2p_group_vendor_ext,
+         NULL
        },
-       { NULL, NULL, NULL, NULL, NULL }
+       { NULL, NULL, NULL, NULL, NULL, NULL }
 };
 
 static const struct wpa_dbus_signal_desc wpas_dbus_p2p_group_signals[] = {
@@ -3966,9 +4226,10 @@ static const struct wpa_dbus_property_desc
        wpas_dbus_persistent_group_properties[] = {
        { "Properties", WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, "a{sv}",
          wpas_dbus_getter_persistent_group_properties,
-         wpas_dbus_setter_persistent_group_properties
+         wpas_dbus_setter_persistent_group_properties,
+         NULL
        },
-       { NULL, NULL, NULL, NULL, NULL }
+       { NULL, NULL, NULL, NULL, NULL, NULL }
 };
 
 /* No signals intended for persistent group objects */
index 6d240ff..d64fcee 100644 (file)
@@ -29,6 +29,7 @@ enum wpas_dbus_prop {
        WPAS_DBUS_PROP_CURRENT_AUTH_MODE,
        WPAS_DBUS_PROP_BSSS,
        WPAS_DBUS_PROP_DISCONNECT_REASON,
+       WPAS_DBUS_PROP_ASSOC_STATUS_CODE,
 };
 
 enum wpas_dbus_bss_prop {
@@ -189,8 +190,7 @@ void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
                                     const u8 *src, u16 dev_passwd_id,
                                     u8 go_intent);
 void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
-                                       const struct wpa_ssid *ssid,
-                                       int client, int network_id);
+                                       int client, int persistent);
 void wpas_dbus_signal_p2p_group_formation_failure(struct wpa_supplicant *wpa_s,
                                                  const char *reason);
 void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
@@ -400,8 +400,7 @@ static inline void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
 
 static inline void
 wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
-                                  const struct wpa_ssid *ssid,
-                                  int client, int network_id)
+                                  int client, int persistent)
 {
 }
 
index 67562a5..e11dd36 100644 (file)
@@ -435,7 +435,8 @@ dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
 
        for (i = 0; i < array_len; i++) {
                if (!dbus_message_iter_append_basic(&array_iter, type,
-                                                   array + i * element_size)) {
+                                                   (const char *) array +
+                                                   i * element_size)) {
                        dbus_set_error(error, DBUS_ERROR_FAILED,
                                       "%s: failed to construct message 2.5",
                                       __func__);
@@ -711,9 +712,9 @@ DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
  *
  * Getter for "DebugLevel" property.
  */
-dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
-                                        DBusError *error,
-                                        void *user_data)
+dbus_bool_t wpas_dbus_getter_debug_level(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        const char *str;
        int idx = wpa_debug_level;
@@ -737,9 +738,9 @@ dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
  *
  * Getter for "DebugTimestamp" property.
  */
-dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data)
+dbus_bool_t wpas_dbus_getter_debug_timestamp(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
                                                &wpa_debug_timestamp, error);
@@ -756,9 +757,9 @@ dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
  *
  * Getter for "DebugShowKeys" property.
  */
-dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data)
+dbus_bool_t wpas_dbus_getter_debug_show_keys(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
                                                &wpa_debug_show_keys, error);
@@ -774,8 +775,9 @@ dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
  *
  * Setter for "DebugLevel" property.
  */
-dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
-                                        DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_setter_debug_level(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_global *global = user_data;
        const char *str = NULL;
@@ -812,9 +814,9 @@ dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
  *
  * Setter for "DebugTimestamp" property.
  */
-dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data)
+dbus_bool_t wpas_dbus_setter_debug_timestamp(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_global *global = user_data;
        dbus_bool_t val;
@@ -838,9 +840,9 @@ dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
  *
  * Setter for "DebugShowKeys" property.
  */
-dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data)
+dbus_bool_t wpas_dbus_setter_debug_show_keys(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_global *global = user_data;
        dbus_bool_t val;
@@ -867,9 +869,9 @@ dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
  * by dbus clients to return list of registered interfaces objects
  * paths
  */
-dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
-                                       DBusError *error,
-                                       void *user_data)
+dbus_bool_t wpas_dbus_getter_interfaces(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_global *global = user_data;
        struct wpa_supplicant *wpa_s;
@@ -912,8 +914,9 @@ dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
  * Getter for "EapMethods" property. Handles requests
  * by dbus clients to return list of strings with supported EAP methods
  */
-dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
-                                        DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_eap_methods(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        char **eap_methods;
        size_t num_items = 0;
@@ -948,9 +951,9 @@ dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
  * return a list of strings with supported capabilities like AP, RSN IBSS,
  * and P2P that are determined at compile time.
  */
-dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
-                                                DBusError *error,
-                                                void *user_data)
+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[5] = { NULL, NULL, NULL, NULL, NULL };
        size_t num_items = 0;
@@ -1472,10 +1475,7 @@ DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
                                           struct wpa_supplicant *wpa_s)
 {
        if (wpa_s->current_ssid != NULL) {
-               wpa_s->disconnected = 1;
-               wpa_supplicant_deauthenticate(wpa_s,
-                                             WLAN_REASON_DEAUTH_LEAVING);
-
+               wpas_request_disconnection(wpa_s);
                return NULL;
        }
 
@@ -1504,7 +1504,7 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
        dbus_message_iter_init(message, &iter);
 
        if (wpa_s->dbus_new_path)
-               ssid = wpa_config_add_network(wpa_s->conf);
+               ssid = wpa_supplicant_add_network(wpa_s);
        if (ssid == NULL) {
                wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.",
                           __func__);
@@ -1513,9 +1513,6 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
                        "wpa_supplicant could not add a network on this interface.");
                goto err;
        }
-       wpas_notify_network_added(wpa_s, ssid);
-       ssid->disabled = 1;
-       wpa_config_set_network_defaults(ssid);
 
        dbus_error_init(&error);
        if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
@@ -1580,6 +1577,27 @@ DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
 
 
 /**
+ * wpas_dbus_handler_expect_disconnect - ExpectDisconnect
+ * @message: Pointer to incoming dbus message
+ * @global: %wpa_supplicant global data structure
+ * Returns: NULL
+ *
+ * Handler function for notifying system there will be a expected disconnect.
+ * This will prevent wpa_supplicant from adding blacklists upon next disconnect..
+ */
+DBusMessage * wpas_dbus_handler_expect_disconnect(DBusMessage *message,
+                                                 struct wpa_global *global)
+{
+       struct wpa_supplicant *wpa_s = global->ifaces;
+
+       for (; wpa_s; wpa_s = wpa_s->next)
+               if (wpa_s->wpa_state >= WPA_ASSOCIATED)
+                       wpa_s->own_disconnect_req = 1;
+       return NULL;
+}
+
+
+/**
  * wpas_dbus_handler_reattach - Reattach to current AP
  * @message: Pointer to incoming dbus message
  * @wpa_s: wpa_supplicant structure for a network interface
@@ -1641,8 +1659,7 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
        const char *op;
        char *iface, *net_id;
        int id;
-       struct wpa_ssid *ssid;
-       int was_disabled;
+       int result;
 
        dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
                              DBUS_TYPE_INVALID);
@@ -1665,27 +1682,12 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
                goto out;
        }
 
-       ssid = wpa_config_get_network(wpa_s->conf, id);
-       if (ssid == NULL) {
+       result = wpa_supplicant_remove_network(wpa_s, id);
+       if (result == -1) {
                reply = wpas_dbus_error_network_unknown(message);
                goto out;
        }
-
-       was_disabled = ssid->disabled;
-
-       wpas_notify_network_removed(wpa_s, ssid);
-
-       if (ssid == wpa_s->current_ssid)
-               wpa_supplicant_deauthenticate(wpa_s,
-                                             WLAN_REASON_DEAUTH_LEAVING);
-       else if (!was_disabled && wpa_s->sched_scanning) {
-               wpa_printf(MSG_DEBUG,
-                          "Stop ongoing sched_scan to remove network from filters");
-               wpa_supplicant_cancel_sched_scan(wpa_s);
-               wpa_supplicant_req_scan(wpa_s, 0, 0);
-       }
-
-       if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+       if (result == -2) {
                wpa_printf(MSG_ERROR,
                           "%s[dbus]: error occurred when removing network %d",
                           __func__, id);
@@ -1854,7 +1856,7 @@ out:
        os_free(iface);
        return reply;
 #else /* IEEE8021X_EAPOL */
-       wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
+       wpa_printf(MSG_DEBUG, "dbus: 802.1X not included");
        return wpas_dbus_error_unknown_error(message, "802.1X not included");
 #endif /* IEEE8021X_EAPOL */
 }
@@ -2271,6 +2273,35 @@ DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
 #endif /* CONFIG_TDLS */
 
 
+#ifndef CONFIG_NO_CONFIG_WRITE
+/**
+ * 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
+ *
+ * Handler function for "SaveConfig" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_save_config(DBusMessage *message,
+                                           struct wpa_supplicant *wpa_s)
+{
+       int ret;
+
+       if (!wpa_s->conf->update_config) {
+               return wpas_dbus_error_unknown_error(
+                       message,
+                       "Not allowed to update configuration (update_config=0)");
+       }
+
+       ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
+       if (ret)
+               return wpas_dbus_error_unknown_error(
+                       message, "Failed to update configuration");
+       return NULL;
+}
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+
 /**
  * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
  * @message: Pointer to incoming dbus message
@@ -2338,8 +2369,9 @@ DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
  *
  * Getter for "Capabilities" property of an interface.
  */
-dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
-                                         DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_capabilities(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        struct wpa_driver_capa capa;
@@ -2585,12 +2617,14 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
                                              &iter_array) ||
            !wpa_dbus_dict_string_array_add_element(
                    &iter_array, "infrastructure") ||
-           !wpa_dbus_dict_string_array_add_element(
-                   &iter_array, "ad-hoc") ||
+           (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_IBSS) &&
+            !wpa_dbus_dict_string_array_add_element(
+                    &iter_array, "ad-hoc")) ||
            (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) &&
             !wpa_dbus_dict_string_array_add_element(
                     &iter_array, "ap")) ||
            (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
+            !wpa_s->conf->p2p_disabled &&
             !wpa_dbus_dict_string_array_add_element(
                     &iter_array, "p2p")) ||
            !wpa_dbus_dict_end_string_array(&iter_dict,
@@ -2629,8 +2663,9 @@ nomem:
  *
  * Getter for "State" property.
  */
-dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
-                                  void *user_data)
+dbus_bool_t wpas_dbus_getter_state(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        const char *str_state;
@@ -2669,8 +2704,9 @@ dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
  *
  * Getter for "scanning" property.
  */
-dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
-                                     void *user_data)
+dbus_bool_t wpas_dbus_getter_scanning(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
@@ -2689,8 +2725,9 @@ dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
  *
  * Getter function for "ApScan" property.
  */
-dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data)
+dbus_bool_t wpas_dbus_getter_ap_scan(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        dbus_uint32_t ap_scan = wpa_s->conf->ap_scan;
@@ -2709,8 +2746,9 @@ dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
  *
  * Setter function for "ApScan" property.
  */
-dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data)
+dbus_bool_t wpas_dbus_setter_ap_scan(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        dbus_uint32_t ap_scan;
@@ -2738,9 +2776,9 @@ dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
  *
  * Getter function for "FastReauth" property.
  */
-dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter,
-                                        DBusError *error,
-                                        void *user_data)
+dbus_bool_t wpas_dbus_getter_fast_reauth(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        dbus_bool_t fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE;
@@ -2760,9 +2798,9 @@ dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter,
  *
  * Setter function for "FastReauth" property.
  */
-dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
-                                    DBusError *error,
-                                    void *user_data)
+dbus_bool_t wpas_dbus_setter_fast_reauth(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        dbus_bool_t fast_reauth;
@@ -2786,9 +2824,9 @@ dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
  * Getter for "DisconnectReason" property.  The reason is negative if it is
  * locally generated.
  */
-dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
-                                              DBusError *error,
-                                              void *user_data)
+dbus_bool_t wpas_dbus_getter_disconnect_reason(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        dbus_int32_t reason = wpa_s->disconnect_reason;
@@ -2799,6 +2837,27 @@ dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
 
 
 /**
+ * wpas_dbus_getter_assoc_status_code - Get most recent failed assoc status code
+ * @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
+ *
+ * Getter for "AssocStatusCode" property.
+ */
+dbus_bool_t wpas_dbus_getter_assoc_status_code(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       dbus_int32_t status_code = wpa_s->assoc_status_code;
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
+                                               &status_code, error);
+}
+
+
+/**
  * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
  * @iter: Pointer to incoming dbus message iter
  * @error: Location to store error on failure
@@ -2807,9 +2866,9 @@ dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
  *
  * Getter function for "BSSExpireAge" property.
  */
-dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
-                                           DBusError *error,
-                                           void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_expire_age(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age;
@@ -2828,9 +2887,9 @@ dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
  *
  * Setter function for "BSSExpireAge" property.
  */
-dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
-                                           DBusError *error,
-                                           void *user_data)
+dbus_bool_t wpas_dbus_setter_bss_expire_age(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        dbus_uint32_t expire_age;
@@ -2857,9 +2916,9 @@ dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
  *
  * Getter function for "BSSExpireCount" property.
  */
-dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
-                                             DBusError *error,
-                                             void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_expire_count(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count;
@@ -2878,9 +2937,9 @@ dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
  *
  * Setter function for "BSSExpireCount" property.
  */
-dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
-                                             DBusError *error,
-                                             void *user_data)
+dbus_bool_t wpas_dbus_setter_bss_expire_count(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        dbus_uint32_t expire_count;
@@ -2907,8 +2966,9 @@ dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
  *
  * Getter function for "Country" property.
  */
-dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data)
+dbus_bool_t wpas_dbus_getter_country(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        char country[3];
@@ -2932,8 +2992,9 @@ dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
  *
  * Setter function for "Country" property.
  */
-dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data)
+dbus_bool_t wpas_dbus_setter_country(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        const char *country;
@@ -2970,9 +3031,9 @@ dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
  *
  * Getter function for "ScanInterval" property.
  */
-dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
-                                          DBusError *error,
-                                          void *user_data)
+dbus_bool_t wpas_dbus_getter_scan_interval(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        dbus_int32_t scan_interval = wpa_s->scan_interval;
@@ -2991,9 +3052,9 @@ dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
  *
  * Setter function for "ScanInterval" property.
  */
-dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
-                                          DBusError *error,
-                                          void *user_data)
+dbus_bool_t wpas_dbus_setter_scan_interval(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        dbus_int32_t scan_interval;
@@ -3020,8 +3081,9 @@ dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
  *
  * Getter for "Ifname" property.
  */
-dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
-                                   void *user_data)
+dbus_bool_t wpas_dbus_getter_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 *ifname = wpa_s->ifname;
@@ -3040,8 +3102,9 @@ dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
  *
  * Getter for "Driver" property.
  */
-dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
-                                   void *user_data)
+dbus_bool_t wpas_dbus_getter_driver(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        const char *driver;
@@ -3069,9 +3132,9 @@ dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
  *
  * Getter for "CurrentBSS" property.
  */
-dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
-                                        DBusError *error,
-                                        void *user_data)
+dbus_bool_t wpas_dbus_getter_current_bss(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf;
@@ -3097,9 +3160,9 @@ dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
  *
  * Getter for "CurrentNetwork" property.
  */
-dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data)
+dbus_bool_t wpas_dbus_getter_current_network(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf;
@@ -3125,9 +3188,9 @@ dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
  *
  * Getter for "CurrentAuthMode" property.
  */
-dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
-                                              DBusError *error,
-                                              void *user_data)
+dbus_bool_t wpas_dbus_getter_current_auth_mode(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        const char *eap_mode;
@@ -3143,9 +3206,11 @@ dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
                            "EAP-%s", eap_mode);
                auth_mode = eap_mode_buf;
 
-       } else {
+       } else if (wpa_s->current_ssid) {
                auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt,
                                             wpa_s->current_ssid->proto);
+       } else {
+               auth_mode = "UNKNOWN";
        }
 
        return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
@@ -3162,9 +3227,9 @@ dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
  *
  * Getter for "BridgeIfname" property.
  */
-dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
-                                          DBusError *error,
-                                          void *user_data)
+dbus_bool_t wpas_dbus_getter_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 = wpa_s->bridge_ifname;
@@ -3175,6 +3240,30 @@ dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
 
 
 /**
+ * wpas_dbus_getter_config_file - Get interface configuration file path
+ * @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
+ *
+ * Getter for "ConfigFile" property.
+ */
+dbus_bool_t wpas_dbus_getter_config_file(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       char *confname = "";
+
+       if (wpa_s->confname)
+               confname = wpa_s->confname;
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &confname, error);
+}
+
+
+/**
  * wpas_dbus_getter_bsss - Get array of BSSs objects
  * @iter: Pointer to incoming dbus message iter
  * @error: Location to store error on failure
@@ -3183,8 +3272,9 @@ dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
  *
  * Getter for "BSSs" property.
  */
-dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
-                                 void *user_data)
+dbus_bool_t wpas_dbus_getter_bsss(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        struct wpa_bss *bss;
@@ -3240,8 +3330,9 @@ out:
  *
  * Getter for "Networks" property.
  */
-dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
-                                     void *user_data)
+dbus_bool_t wpas_dbus_getter_networks(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        struct wpa_ssid *ssid;
@@ -3303,9 +3394,9 @@ out:
  *
  * Getter for "PKCS11EnginePath" property.
  */
-dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
-                                               DBusError *error,
-                                               void *user_data)
+dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        const char *pkcs11_engine_path;
@@ -3328,9 +3419,9 @@ dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
  *
  * Getter for "PKCS11ModulePath" property.
  */
-dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
-                                               DBusError *error,
-                                               void *user_data)
+dbus_bool_t wpas_dbus_getter_pkcs11_module_path(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        const char *pkcs11_module_path;
@@ -3353,8 +3444,9 @@ dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
  *
  * Getter for "Blobs" property.
  */
-dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
-                                  void *user_data)
+dbus_bool_t wpas_dbus_getter_blobs(
+       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;
@@ -3406,6 +3498,79 @@ dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
 }
 
 
+dbus_bool_t wpas_dbus_getter_iface_global(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       int ret;
+       char buf[250];
+       char *p = buf;
+
+       if (!property_desc->data) {
+               dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
+                              "Unhandled interface property %s",
+                              property_desc->dbus_property);
+               return FALSE;
+       }
+
+       ret = wpa_config_get_value(property_desc->data, wpa_s->conf, buf,
+                                  sizeof(buf));
+       if (ret < 0)
+               *p = '\0';
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &p,
+                                               error);
+}
+
+
+dbus_bool_t wpas_dbus_setter_iface_global(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       const char *new_value = NULL;
+       char buf[250];
+       size_t combined_len;
+       int ret;
+
+       if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+                                             &new_value))
+               return FALSE;
+
+       combined_len = os_strlen(property_desc->data) + os_strlen(new_value) +
+               3;
+       if (combined_len >= sizeof(buf)) {
+               dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
+                              "Interface property %s value too large",
+                              property_desc->dbus_property);
+               return FALSE;
+       }
+
+       if (!new_value[0])
+               new_value = "NULL";
+
+       ret = os_snprintf(buf, combined_len, "%s=%s", property_desc->data,
+                         new_value);
+       if (os_snprintf_error(combined_len, ret)) {
+               dbus_set_error(error,  WPAS_DBUS_ERROR_UNKNOWN_ERROR,
+                              "Failed to construct new interface property %s",
+                              property_desc->dbus_property);
+               return FALSE;
+       }
+
+       if (wpa_config_process_global(wpa_s->conf, buf, -1)) {
+               dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
+                              "Failed to set interface property %s",
+                              property_desc->dbus_property);
+               return FALSE;
+       }
+
+       wpa_supplicant_update_config(wpa_s);
+       return TRUE;
+}
+
+
 static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
                                       DBusError *error, const char *func_name)
 {
@@ -3432,8 +3597,9 @@ static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
  *
  * Getter for "BSSID" property.
  */
-dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
-                                      void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_bssid(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct bss_handler_args *args = user_data;
        struct wpa_bss *res;
@@ -3457,8 +3623,9 @@ dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
  *
  * Getter for "SSID" property.
  */
-dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
-                                     void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_ssid(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct bss_handler_args *args = user_data;
        struct wpa_bss *res;
@@ -3482,8 +3649,9 @@ dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
  *
  * Getter for "Privacy" property.
  */
-dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
-                                        DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_privacy(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct bss_handler_args *args = user_data;
        struct wpa_bss *res;
@@ -3508,8 +3676,9 @@ dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
  *
  * Getter for "Mode" property.
  */
-dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
-                                     void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_mode(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct bss_handler_args *args = user_data;
        struct wpa_bss *res;
@@ -3549,8 +3718,9 @@ dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
  *
  * Getter for "Level" property.
  */
-dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
-                                       DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_signal(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct bss_handler_args *args = user_data;
        struct wpa_bss *res;
@@ -3575,8 +3745,9 @@ dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
  *
  * Getter for "Frequency" property.
  */
-dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
-                                          DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_frequency(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct bss_handler_args *args = user_data;
        struct wpa_bss *res;
@@ -3607,8 +3778,9 @@ static int cmp_u8s_desc(const void *a, const void *b)
  *
  * Getter for "Rates" property.
  */
-dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
-                                      DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_rates(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct bss_handler_args *args = user_data;
        struct wpa_bss *res;
@@ -3647,9 +3819,9 @@ dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
 }
 
 
-static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
-                                                  struct wpa_ie_data *ie_data,
-                                                  DBusError *error)
+static dbus_bool_t wpas_dbus_get_bss_security_prop(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, struct wpa_ie_data *ie_data, DBusError *error)
 {
        DBusMessageIter iter_dict, variant_iter;
        const char *group;
@@ -3780,8 +3952,9 @@ nomem:
  *
  * Getter for "WPA" property.
  */
-dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_wpa(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct bss_handler_args *args = user_data;
        struct wpa_bss *res;
@@ -3800,7 +3973,7 @@ dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
                return FALSE;
        }
 
-       return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
+       return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error);
 }
 
 
@@ -3813,8 +3986,9 @@ dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
  *
  * Getter for "RSN" property.
  */
-dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_rsn(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct bss_handler_args *args = user_data;
        struct wpa_bss *res;
@@ -3833,7 +4007,7 @@ dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
                return FALSE;
        }
 
-       return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
+       return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error);
 }
 
 
@@ -3846,8 +4020,9 @@ dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
  *
  * Getter for "WPS" property.
  */
-dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_wps(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct bss_handler_args *args = user_data;
        struct wpa_bss *res;
@@ -3902,8 +4077,9 @@ nomem:
  *
  * Getter for "IEs" property.
  */
-dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_ies(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct bss_handler_args *args = user_data;
        struct wpa_bss *res;
@@ -3927,8 +4103,9 @@ dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
  *
  * Getter for BSS age
  */
-dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_age(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct bss_handler_args *args = user_data;
        struct wpa_bss *res;
@@ -3956,8 +4133,9 @@ dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error,
  *
  * Getter for "enabled" property of a configured network.
  */
-dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data)
+dbus_bool_t wpas_dbus_getter_enabled(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct network_handler_args *net = user_data;
        dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE;
@@ -3976,8 +4154,9 @@ dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
  *
  * Setter for "Enabled" property of a configured network.
  */
-dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data)
+dbus_bool_t wpas_dbus_setter_enabled(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct network_handler_args *net = user_data;
        struct wpa_supplicant *wpa_s;
@@ -4009,9 +4188,9 @@ dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
  *
  * Getter for "Properties" property of a configured network.
  */
-dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
-                                               DBusError *error,
-                                               void *user_data)
+dbus_bool_t wpas_dbus_getter_network_properties(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct network_handler_args *net = user_data;
        DBusMessageIter variant_iter, dict_iter;
@@ -4071,9 +4250,9 @@ out:
  *
  * Setter for "Properties" property of a configured network.
  */
-dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
-                                               DBusError *error,
-                                               void *user_data)
+dbus_bool_t wpas_dbus_setter_network_properties(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct network_handler_args *net = user_data;
        struct wpa_ssid *ssid = net->ssid;
@@ -4211,3 +4390,147 @@ out:
 }
 
 #endif /* CONFIG_AP */
+
+
+DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message,
+                                               struct wpa_supplicant *wpa_s)
+{
+       u8 *ielems;
+       int len;
+       struct ieee802_11_elems elems;
+       dbus_int32_t frame_id;
+       DBusMessageIter iter, array;
+
+       dbus_message_iter_init(message, &iter);
+       dbus_message_iter_get_basic(&iter, &frame_id);
+       if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
+               return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                             "Invalid ID");
+       }
+
+       dbus_message_iter_next(&iter);
+       dbus_message_iter_recurse(&iter, &array);
+       dbus_message_iter_get_fixed_array(&array, &ielems, &len);
+       if (!ielems || len == 0) {
+               return dbus_message_new_error(
+                       message, DBUS_ERROR_INVALID_ARGS, "Invalid value");
+       }
+
+       if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) {
+               return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                             "Parse error");
+       }
+
+       wpa_s = wpas_vendor_elem(wpa_s, frame_id);
+       if (!wpa_s->vendor_elem[frame_id]) {
+               wpa_s->vendor_elem[frame_id] = wpabuf_alloc_copy(ielems, len);
+               wpas_vendor_elem_update(wpa_s);
+               return NULL;
+       }
+
+       if (wpabuf_resize(&wpa_s->vendor_elem[frame_id], len) < 0) {
+               return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                             "Resize error");
+       }
+
+       wpabuf_put_data(wpa_s->vendor_elem[frame_id], ielems, len);
+       wpas_vendor_elem_update(wpa_s);
+       return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message,
+                                               struct wpa_supplicant *wpa_s)
+{
+       DBusMessage *reply;
+       DBusMessageIter iter, array_iter;
+       dbus_int32_t frame_id;
+       const u8 *elem;
+       size_t elem_len;
+
+       dbus_message_iter_init(message, &iter);
+       dbus_message_iter_get_basic(&iter, &frame_id);
+
+       if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
+               return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                             "Invalid ID");
+       }
+
+       wpa_s = wpas_vendor_elem(wpa_s, frame_id);
+       if (!wpa_s->vendor_elem[frame_id]) {
+               return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                             "ID value does not exist");
+       }
+
+       reply = dbus_message_new_method_return(message);
+       if (!reply)
+               return wpas_dbus_error_no_memory(message);
+
+       dbus_message_iter_init_append(reply, &iter);
+
+       elem = wpabuf_head_u8(wpa_s->vendor_elem[frame_id]);
+       elem_len = wpabuf_len(wpa_s->vendor_elem[frame_id]);
+
+       if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                                             DBUS_TYPE_BYTE_AS_STRING,
+                                             &array_iter) ||
+           !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
+                                                 &elem, elem_len) ||
+           !dbus_message_iter_close_container(&iter, &array_iter)) {
+               dbus_message_unref(reply);
+               reply = wpas_dbus_error_no_memory(message);
+       }
+
+       return reply;
+}
+
+
+DBusMessage * wpas_dbus_handler_vendor_elem_remove(DBusMessage *message,
+                                                  struct wpa_supplicant *wpa_s)
+{
+       u8 *ielems;
+       int len;
+       struct ieee802_11_elems elems;
+       DBusMessageIter iter, array;
+       dbus_int32_t frame_id;
+
+       dbus_message_iter_init(message, &iter);
+       dbus_message_iter_get_basic(&iter, &frame_id);
+       if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
+               return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                             "Invalid ID");
+       }
+
+       dbus_message_iter_next(&iter);
+       dbus_message_iter_recurse(&iter, &array);
+       dbus_message_iter_get_fixed_array(&array, &ielems, &len);
+       if (!ielems || len == 0) {
+               return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                             "Invalid value");
+       }
+
+       wpa_s = wpas_vendor_elem(wpa_s, frame_id);
+
+       if (len == 1 && *ielems == '*') {
+               wpabuf_free(wpa_s->vendor_elem[frame_id]);
+               wpa_s->vendor_elem[frame_id] = NULL;
+               wpas_vendor_elem_update(wpa_s);
+               return NULL;
+       }
+
+       if (!wpa_s->vendor_elem[frame_id]) {
+               return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                             "ID value does not exist");
+       }
+
+       if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) {
+               return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                             "Parse error");
+       }
+
+       if (wpas_vendor_elem_remove(wpa_s, frame_id, ielems, len) == 0)
+               return NULL;
+
+       return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                     "Not found");
+}
index 50f72ec..1d6235d 100644 (file)
@@ -10,6 +10,8 @@
 #ifndef CTRL_IFACE_DBUS_NEW_HANDLERS_H
 #define CTRL_IFACE_DBUS_NEW_HANDLERS_H
 
+#include "dbus_new_helpers.h"
+
 struct network_handler_args {
        struct wpa_supplicant *wpa_s;
        struct wpa_ssid *ssid;
@@ -50,39 +52,20 @@ DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
 DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
                                              struct wpa_global *global);
 
-dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
-                                        DBusError *error,
-                                        void *user_data);
-
-dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data);
-
-dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data);
-
-dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
-                                        DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data);
-
-dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data);
-
-dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
-                                       DBusError *error,
-                                       void *user_data);
-
-dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
-                                        DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
-                                                DBusError *error,
-                                                void *user_data);
+DBusMessage * wpas_dbus_handler_expect_disconnect(DBusMessage *message,
+                                                 struct wpa_global *global);
+
+DECLARE_ACCESSOR(wpas_dbus_getter_debug_level);
+DECLARE_ACCESSOR(wpas_dbus_getter_debug_timestamp);
+DECLARE_ACCESSOR(wpas_dbus_getter_debug_show_keys);
+DECLARE_ACCESSOR(wpas_dbus_setter_debug_level);
+DECLARE_ACCESSOR(wpas_dbus_setter_debug_timestamp);
+DECLARE_ACCESSOR(wpas_dbus_setter_debug_show_keys);
+DECLARE_ACCESSOR(wpas_dbus_getter_interfaces);
+DECLARE_ACCESSOR(wpas_dbus_getter_eap_methods);
+DECLARE_ACCESSOR(wpas_dbus_getter_global_capabilities);
+DECLARE_ACCESSOR(wpas_dbus_getter_iface_global);
+DECLARE_ACCESSOR(wpas_dbus_setter_iface_global);
 
 DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
                                     struct wpa_supplicant *wpa_s);
@@ -146,150 +129,52 @@ DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
 DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
                                          struct wpa_supplicant *wpa_s);
 
-dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
-                                         DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
-                                  void *user_data);
-
-dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
-                                     void *user_data);
-
-dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data);
-
-dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data);
-
-dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter,
-                                        DBusError *error,
-                                        void *user_data);
-
-dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
-                                        DBusError *error,
-                                        void *user_data);
-
-dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
-                                              DBusError *error,
-                                              void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
-                                           DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
-                                           DBusError *error,
-                                           void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
-                                             DBusError *error,
-                                             void *user_data);
-
-dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
-                                             DBusError *error,
-                                             void *user_data);
-
-dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data);
-
-dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data);
-
-dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
-                                          DBusError *error,
-                                          void *user_data);
-
-dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
-                                          DBusError *error,
-                                          void *user_data);
-
-dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
-                                   void *user_data);
-
-dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
-                                   void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
-                                          DBusError *error,
-                                          void *user_data);
-
-dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
-                                        DBusError *error,
-                                        void *user_data);
-
-dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data);
-
-dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
-                                              DBusError *error,
-                                              void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
-                                 void *user_data);
-
-dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
-                                     void *user_data);
-
-dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
-                                               DBusError *error,
-                                               void *user_data);
-
-dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
-                                               DBusError *error,
-                                               void *user_data);
-
-dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
-                                  void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
-                                      void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
-                                     void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
-                                        DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
-                                     void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
-                                       DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
-                                          DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
-                                      DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data);
-
-dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data);
-
-dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
-                                    void *user_data);
-
-dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
-                                               DBusError *error,
-                                               void *user_data);
-
-dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
-                                               DBusError *error,
-                                               void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_getter_capabilities);
+DECLARE_ACCESSOR(wpas_dbus_getter_state);
+DECLARE_ACCESSOR(wpas_dbus_getter_scanning);
+DECLARE_ACCESSOR(wpas_dbus_getter_ap_scan);
+DECLARE_ACCESSOR(wpas_dbus_setter_ap_scan);
+DECLARE_ACCESSOR(wpas_dbus_getter_fast_reauth);
+DECLARE_ACCESSOR(wpas_dbus_setter_fast_reauth);
+DECLARE_ACCESSOR(wpas_dbus_getter_disconnect_reason);
+DECLARE_ACCESSOR(wpas_dbus_getter_disassociate_reason);
+DECLARE_ACCESSOR(wpas_dbus_getter_assoc_status_code);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_expire_age);
+DECLARE_ACCESSOR(wpas_dbus_setter_bss_expire_age);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_expire_count);
+DECLARE_ACCESSOR(wpas_dbus_setter_bss_expire_count);
+DECLARE_ACCESSOR(wpas_dbus_getter_country);
+DECLARE_ACCESSOR(wpas_dbus_setter_country);
+DECLARE_ACCESSOR(wpas_dbus_getter_scan_interval);
+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_getter_config_file);
+DECLARE_ACCESSOR(wpas_dbus_getter_current_bss);
+DECLARE_ACCESSOR(wpas_dbus_getter_current_network);
+DECLARE_ACCESSOR(wpas_dbus_getter_current_auth_mode);
+DECLARE_ACCESSOR(wpas_dbus_getter_bsss);
+DECLARE_ACCESSOR(wpas_dbus_getter_networks);
+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_bss_bssid);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_ssid);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_privacy);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_mode);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_signal);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_frequency);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_rates);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_wpa);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_rsn);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_wps);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_ies);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_age);
+DECLARE_ACCESSOR(wpas_dbus_getter_enabled);
+DECLARE_ACCESSOR(wpas_dbus_setter_enabled);
+DECLARE_ACCESSOR(wpas_dbus_getter_network_properties);
+DECLARE_ACCESSOR(wpas_dbus_setter_network_properties);
 
 DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
                                          struct wpa_supplicant *wpa_s);
@@ -297,20 +182,10 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
 DBusMessage * wpas_dbus_handler_wps_cancel(DBusMessage *message,
                                           struct wpa_supplicant *wpa_s);
 
-dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter,
-       DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
-                                                DBusError *error,
-                                                void *user_data);
-
-dbus_bool_t wpas_dbus_getter_config_methods(DBusMessageIter *iter,
-                                           DBusError *error,
-                                           void *user_data);
-
-dbus_bool_t wpas_dbus_setter_config_methods(DBusMessageIter *iter,
-                                           DBusError *error,
-                                           void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_getter_process_credentials);
+DECLARE_ACCESSOR(wpas_dbus_setter_process_credentials);
+DECLARE_ACCESSOR(wpas_dbus_getter_config_methods);
+DECLARE_ACCESSOR(wpas_dbus_setter_config_methods);
 
 DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
                                              struct wpa_supplicant *wpa_s);
@@ -321,6 +196,16 @@ DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
 DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
                                              struct wpa_supplicant *wpa_s);
 
+DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message,
+                                               struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message,
+                                               struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_vendor_elem_remove(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_save_config(DBusMessage *message,
+                                           struct wpa_supplicant *wpa_s);
+
 DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
                                           const char *arg);
 DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
index 67c079e..73b9e20 100644 (file)
@@ -364,13 +364,14 @@ 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,
-                                                 NULL, 0, 0)) {
+                                                 0, 0, NULL, 0, 0)) {
                        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))
+       } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0, 0,
+                                     0))
                goto inv_args;
 
 out:
@@ -582,7 +583,7 @@ 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, -1, 0, 0, 0);
+                                  go_intent, freq, 0, -1, 0, 0, 0, 0, NULL, 0);
 
        if (new_pin >= 0) {
                char npin[9];
@@ -733,8 +734,8 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
                if (ssid == NULL || ssid->disabled != 2)
                        goto err;
 
-               if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0) <
-                   0) {
+               if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0, 0,
+                                   0) < 0) {
                        reply = wpas_dbus_error_unknown_error(
                                message,
                                "Failed to reinvoke a persistent group");
@@ -807,9 +808,9 @@ DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
  * P2P Device property accessor methods.
  */
 
-dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter,
-                                              DBusError *error,
-                                              void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_device_config(
+       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;
@@ -916,9 +917,9 @@ err_no_mem:
 }
 
 
-dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
-                                              DBusError *error,
-                                              void *user_data)
+dbus_bool_t wpas_dbus_setter_p2p_device_config(
+       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, iter_dict;
@@ -944,7 +945,8 @@ dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
                if (os_strcmp(entry.key, "DeviceName") == 0) {
                        char *devname;
 
-                       if (entry.type != DBUS_TYPE_STRING)
+                       if (entry.type != DBUS_TYPE_STRING ||
+                           os_strlen(entry.str_value) > WPS_DEV_NAME_MAX_LEN)
                                goto error;
 
                        devname = os_strdup(entry.str_value);
@@ -1087,8 +1089,9 @@ dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
-                                      void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peers(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        struct p2p_data *p2p = wpa_s->global->p2p;
@@ -1201,8 +1204,9 @@ static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
-                                     void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_role(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        char *str;
@@ -1224,8 +1228,9 @@ dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
-                                      void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
@@ -1243,8 +1248,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
-                                       DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peergo(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
@@ -1271,9 +1277,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
  * Peer object properties accessor methods
  */
 
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter,
-                                                 DBusError *error,
-                                                 void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct peer_handler_args *peer_args = user_data;
        const struct p2p_peer_info *info;
@@ -1309,9 +1315,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter,
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(DBusMessageIter *iter,
-                                                  DBusError *error,
-                                                  void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct peer_handler_args *peer_args = user_data;
        const struct p2p_peer_info *info;
@@ -1346,9 +1352,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(DBusMessageIter *iter,
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(DBusMessageIter *iter,
-                                               DBusError *error,
-                                               void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct peer_handler_args *peer_args = user_data;
        const struct p2p_peer_info *info;
@@ -1383,9 +1389,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(DBusMessageIter *iter,
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(DBusMessageIter *iter,
-                                                 DBusError *error,
-                                                 void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct peer_handler_args *peer_args = user_data;
        const struct p2p_peer_info *info;
@@ -1420,9 +1426,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(DBusMessageIter *iter,
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(DBusMessageIter *iter,
-                                                  DBusError *error,
-                                                  void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct peer_handler_args *peer_args = user_data;
        const struct p2p_peer_info *info;
@@ -1458,6 +1464,7 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(DBusMessageIter *iter,
 
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type(
+       const struct wpa_dbus_property_desc *property_desc,
        DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct peer_handler_args *peer_args = user_data;
@@ -1483,9 +1490,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type(
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
-                                                   DBusError *error,
-                                                   void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct peer_handler_args *peer_args = user_data;
        const struct p2p_peer_info *info;
@@ -1508,9 +1515,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
-                                           DBusError *error,
-                                           void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_level(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct peer_handler_args *peer_args = user_data;
        const struct p2p_peer_info *info;
@@ -1533,9 +1540,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
-                                                       DBusError *error,
-                                                       void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct peer_handler_args *peer_args = user_data;
        const struct p2p_peer_info *info;
@@ -1558,9 +1565,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter,
-                                                      DBusError *error,
-                                                      void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct peer_handler_args *peer_args = user_data;
        const struct p2p_peer_info *info;
@@ -1584,6 +1591,7 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter,
 
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
+       const struct wpa_dbus_property_desc *property_desc,
        DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct peer_handler_args *peer_args = user_data;
@@ -1649,9 +1657,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
-                                                      DBusError *error,
-                                                      void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
        unsigned int i, num = 0;
@@ -1684,8 +1692,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
-                                         DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_ies(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct peer_handler_args *peer_args = user_data;
        const struct p2p_peer_info *info;
@@ -1709,9 +1718,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(DBusMessageIter *iter,
-                                                    DBusError *error,
-                                                    void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct peer_handler_args *peer_args = user_data;
        const struct p2p_peer_info *info;
@@ -1774,9 +1783,9 @@ out_of_memory:
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_peer_groups(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_groups(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct peer_handler_args *peer_args = user_data;
        const struct p2p_peer_info *info;
@@ -1842,9 +1851,9 @@ out:
  *
  * Getter for "PersistentGroups" property.
  */
-dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
-                                              DBusError *error,
-                                              void *user_data)
+dbus_bool_t wpas_dbus_getter_persistent_groups(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        struct wpa_ssid *ssid;
@@ -1904,16 +1913,16 @@ out:
  *
  * Getter for "Properties" property of a persistent group.
  */
-dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
-                                                        DBusError *error,
-                                                        void *user_data)
+dbus_bool_t wpas_dbus_getter_persistent_group_properties(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct network_handler_args *net = user_data;
 
        /* Leveraging the fact that persistent group object is still
         * represented in same manner as network within.
         */
-       return wpas_dbus_getter_network_properties(iter, error, net);
+       return wpas_dbus_getter_network_properties(property_desc, iter, error, net);
 }
 
 
@@ -1927,9 +1936,9 @@ dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
  *
  * Setter for "Properties" property of a persistent group.
  */
-dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter,
-                                                        DBusError *error,
-                                                        void *user_data)
+dbus_bool_t wpas_dbus_setter_persistent_group_properties(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct network_handler_args *net = user_data;
        struct wpa_ssid *ssid = net->ssid;
@@ -2142,9 +2151,9 @@ DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
  * Group object properties accessor methods
  */
 
-dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
-                                              DBusError *error,
-                                              void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_members(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        struct wpa_ssid *ssid;
@@ -2211,8 +2220,9 @@ out_of_memory:
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
-                                           DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_ssid(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
 
@@ -2224,9 +2234,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_bssid(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        u8 role = wpas_get_p2p_role(wpa_s);
@@ -2248,9 +2258,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter,
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter,
-                                                DBusError *error,
-                                                void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_frequency(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        u16 op_freq;
@@ -2271,9 +2281,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter,
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter,
-                                                 DBusError *error,
-                                                 void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        char *p_pass;
@@ -2292,8 +2302,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter,
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
-                                          DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_psk(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        u8 *p_psk = NULL;
@@ -2313,9 +2324,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
-                                                 DBusError *error,
-                                                 void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        struct hostapd_data *hapd;
@@ -2348,9 +2359,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
 }
 
 
-dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
-                                                 DBusError *error,
-                                                 void *user_data)
+dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(
+       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, iter_dict, array_iter, sub;
@@ -2876,8 +2887,9 @@ DBusMessage * wpas_dbus_handler_p2p_serv_disc_external(
 
 #ifdef CONFIG_WIFI_DISPLAY
 
-dbus_bool_t wpas_dbus_getter_global_wfd_ies(DBusMessageIter *iter,
-                                           DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_global_wfd_ies(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_global *global = user_data;
        struct wpabuf *ie;
@@ -2898,8 +2910,9 @@ dbus_bool_t wpas_dbus_getter_global_wfd_ies(DBusMessageIter *iter,
 }
 
 
-dbus_bool_t wpas_dbus_setter_global_wfd_ies(DBusMessageIter *iter,
-                                           DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_setter_global_wfd_ies(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_global *global = user_data;
        DBusMessageIter variant, array;
index 2aecbbe..c4c0261 100644 (file)
@@ -89,139 +89,50 @@ DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(
 /*
  * P2P Device property accessor methods.
  */
-dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
-                                              DBusError *error,
-                                              void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter,
-                                              DBusError *error,
-                                              void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
-                                      void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
-                                     void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
-                                      void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
-                                       DBusError *error,
-                                       void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_setter_p2p_device_config);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_device_config);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peers);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_role);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peergo);
 
 /*
  * P2P Peer properties.
  */
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter,
-                                                 DBusError *error,
-                                                 void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(DBusMessageIter *iter,
-                                                  DBusError *error,
-                                                  void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(DBusMessageIter *iter,
-                                               DBusError *error,
-                                               void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(DBusMessageIter *iter,
-                                                 DBusError *error,
-                                                 void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(DBusMessageIter *iter,
-                                                  DBusError *error,
-                                                  void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type(
-       DBusMessageIter *iter, DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
-                                                   DBusError *error,
-                                                   void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
-                                           DBusError *error,
-                                           void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
-                                                       DBusError *error,
-                                                       void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter,
-                                                      DBusError *error,
-                                                      void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
-       DBusMessageIter *iter, DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
-                                                      DBusError *error,
-                                                      void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
-                                         DBusError *error,
-                                         void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(DBusMessageIter *iter,
-                                                    DBusError *error,
-                                                    void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_groups(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_device_name);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_manufacturer);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_modelname);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_modelnumber);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_serialnumber);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_primary_device_type);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_config_method);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_level);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_device_capability);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_group_capability);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_secondary_device_types);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_vendor_extension);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_ies);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_device_address);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_groups);
 
 /*
  * P2P Group properties
  */
-
-dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
-                                              DBusError *error,
-                                              void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
-                                           DBusError *error,
-                                           void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter,
-                                                DBusError *error,
-                                                void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter,
-                                                 DBusError *error,
-                                                 void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
-                                          DBusError *error,
-                                          void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
-                                                 DBusError *error,
-                                                 void *user_data);
-
-dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
-                                                 DBusError *error,
-                                                 void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_members);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_ssid);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_bssid);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_frequency);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_passphrase);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_psk);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_vendor_ext);
+DECLARE_ACCESSOR(wpas_dbus_setter_p2p_group_vendor_ext);
 
 /*
  * P2P Persistent Groups and properties
  */
-
-dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
-                                              DBusError *error,
-                                              void *user_data);
-
-dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
-       DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter,
-                                                        DBusError *error,
-                                                        void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_getter_persistent_groups);
+DECLARE_ACCESSOR(wpas_dbus_getter_persistent_group_properties);
+DECLARE_ACCESSOR(wpas_dbus_setter_persistent_group_properties);
 
 DBusMessage * wpas_dbus_handler_add_persistent_group(
        DBusMessage *message, struct wpa_supplicant *wpa_s);
@@ -233,15 +144,8 @@ DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
        DBusMessage *message, struct wpa_supplicant *wpa_s);
 
 #ifdef CONFIG_WIFI_DISPLAY
-
-dbus_bool_t wpas_dbus_getter_global_wfd_ies(DBusMessageIter *iter,
-                                           DBusError *error,
-                                           void *user_data);
-
-dbus_bool_t wpas_dbus_setter_global_wfd_ies(DBusMessageIter *iter,
-                                           DBusError *error,
-                                           void *user_data);
-
+DECLARE_ACCESSOR(wpas_dbus_getter_global_wfd_ies);
+DECLARE_ACCESSOR(wpas_dbus_setter_global_wfd_ies);
 #endif /* CONFIG_WIFI_DISPLAY */
 
 #endif /* DBUS_NEW_HANDLERS_P2P_H */
index b2251ba..f16e229 100644 (file)
@@ -325,7 +325,7 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
  * @wpa_s: %wpa_supplicant data structure
  * Returns: NULL on success or DBus error on failure
  *
- * Handler for "Cancel" method call. Returns NULL if WPS cancel successfull
+ * Handler for "Cancel" method call. Returns NULL if WPS cancel successful
  * or DBus error on WPS cancel failure
  */
 DBusMessage * wpas_dbus_handler_wps_cancel(DBusMessage *message,
@@ -349,9 +349,9 @@ DBusMessage * wpas_dbus_handler_wps_cancel(DBusMessage *message,
  * true if wps_cred_processing configuration field is not equal to 1 or false
  * if otherwise.
  */
-dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter,
-                                                DBusError *error,
-                                                void *user_data)
+dbus_bool_t wpas_dbus_getter_process_credentials(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        dbus_bool_t process = wpa_s->conf->wps_cred_processing != 1;
@@ -371,9 +371,9 @@ dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter,
  * Setter for "ProcessCredentials" property. Sets credentials_processed on 2
  * if boolean argument is true or on 1 if otherwise.
  */
-dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
-                                                DBusError *error,
-                                                void *user_data)
+dbus_bool_t wpas_dbus_setter_process_credentials(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        dbus_bool_t process_credentials, old_pc;
@@ -407,9 +407,9 @@ dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
  * Getter for "ConfigMethods" property. Returned boolean will be true if
  * providing the relevant string worked, or false otherwise.
  */
-dbus_bool_t wpas_dbus_getter_config_methods(DBusMessageIter *iter,
-                                           DBusError *error,
-                                           void *user_data)
+dbus_bool_t wpas_dbus_getter_config_methods(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        char *methods = wpa_s->conf->config_methods;
@@ -431,9 +431,9 @@ dbus_bool_t wpas_dbus_getter_config_methods(DBusMessageIter *iter,
  * Setter for "ConfigMethods" property. Sets the methods string, apply such
  * change and returns true on success. Returns false otherwise.
  */
-dbus_bool_t wpas_dbus_setter_config_methods(DBusMessageIter *iter,
-                                           DBusError *error,
-                                           void *user_data)
+dbus_bool_t wpas_dbus_setter_config_methods(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        char *methods, *new_methods;
index 45623f3..0115e32 100644 (file)
@@ -46,7 +46,7 @@ static dbus_bool_t fill_dict_with_properties(
                        goto error;
 
                /* An error getting a property fails the request entirely */
-               if (!dsc->getter(&entry_iter, error, user_data)) {
+               if (!dsc->getter(dsc, &entry_iter, error, user_data)) {
                        wpa_printf(MSG_INFO,
                                   "dbus: %s dbus_interface=%s dbus_property=%s getter failed",
                                   __func__, dsc->dbus_interface,
@@ -176,7 +176,7 @@ static DBusMessage * properties_get(DBusMessage *message,
        dbus_message_iter_init_append(reply, &iter);
 
        dbus_error_init(&error);
-       if (dsc->getter(&iter, &error, user_data) == FALSE) {
+       if (dsc->getter(dsc, &iter, &error, user_data) == FALSE) {
                dbus_message_unref(reply);
                reply = wpas_dbus_reply_new_from_error(
                        message, &error, DBUS_ERROR_FAILED,
@@ -213,7 +213,7 @@ static DBusMessage * properties_set(DBusMessage *message,
 
        /* Iter will now point to the property's new value */
        dbus_error_init(&error);
-       if (dsc->setter(&iter, &error, user_data) == TRUE) {
+       if (dsc->setter(dsc, &iter, &error, user_data) == TRUE) {
                /* Success */
                reply = dbus_message_new_method_return(message);
        } else {
@@ -627,7 +627,8 @@ static dbus_bool_t put_changed_properties(
                        return FALSE;
 
                dbus_error_init(&error);
-               if (!dsc->getter(&entry_iter, &error, obj_dsc->user_data)) {
+               if (!dsc->getter(dsc, &entry_iter, &error, obj_dsc->user_data))
+               {
                        if (dbus_error_is_set(&error)) {
                                wpa_printf(MSG_ERROR,
                                           "dbus: %s: Cannot get new value of property %s: (%s) %s",
index 6e2c1f1..7b63b28 100644 (file)
@@ -16,9 +16,13 @@ typedef DBusMessage * (*WPADBusMethodHandler)(DBusMessage *message,
                                              void *user_data);
 typedef void (*WPADBusArgumentFreeFunction)(void *handler_arg);
 
-typedef dbus_bool_t (*WPADBusPropertyAccessor)(DBusMessageIter *iter,
-                                              DBusError *error,
-                                              void *user_data);
+struct wpa_dbus_property_desc;
+typedef dbus_bool_t (*WPADBusPropertyAccessor)(
+       const struct wpa_dbus_property_desc *property_desc,
+       DBusMessageIter *iter, DBusError *error, void *user_data);
+#define DECLARE_ACCESSOR(f) \
+dbus_bool_t f(const struct wpa_dbus_property_desc *property_desc, \
+             DBusMessageIter *iter, DBusError *error, void *user_data)
 
 struct wpa_dbus_object_desc {
        DBusConnection *connection;
@@ -89,6 +93,8 @@ struct wpa_dbus_property_desc {
        WPADBusPropertyAccessor getter;
        /* property setter function */
        WPADBusPropertyAccessor setter;
+       /* other data */
+       const char *data;
 };
 
 
index fba57e6..aee105b 100644 (file)
@@ -38,7 +38,7 @@ static struct interfaces * add_interface(struct dl_list *list,
        if (!iface)
                return NULL;
        iface->dbus_interface = os_strdup(dbus_interface);
-       iface->xml = wpabuf_alloc(6000);
+       iface->xml = wpabuf_alloc(15000);
        if (iface->dbus_interface == NULL || iface->xml == NULL) {
                os_free(iface->dbus_interface);
                wpabuf_free(iface->xml);
@@ -257,7 +257,7 @@ DBusMessage * wpa_dbus_introspect(DBusMessage *message,
        DBusMessage *reply;
        struct wpabuf *xml;
 
-       xml = wpabuf_alloc(15000);
+       xml = wpabuf_alloc(20000);
        if (xml == NULL)
                return NULL;
 
index e8f62ef..e540832 100644 (file)
@@ -717,16 +717,13 @@ DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
        char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
 
        if (wpa_s->dbus_path)
-               ssid = wpa_config_add_network(wpa_s->conf);
+               ssid = wpa_supplicant_add_network(wpa_s);
        if (ssid == NULL) {
                reply = dbus_message_new_error(
                        message, WPAS_ERROR_ADD_NETWORK_ERROR,
                        "wpa_supplicant could not add a network on this interface.");
                goto out;
        }
-       wpas_notify_network_added(wpa_s, ssid);
-       ssid->disabled = 1;
-       wpa_config_set_network_defaults(ssid);
 
        /* Construct the object path for this network. */
        os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
@@ -758,7 +755,7 @@ DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
        const char *op;
        char *iface = NULL, *net_id = NULL;
        int id;
-       struct wpa_ssid *ssid;
+       int result;
 
        if (!dbus_message_get_args(message, NULL,
                                   DBUS_TYPE_OBJECT_PATH, &op,
@@ -781,19 +778,12 @@ DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
        }
 
        id = strtoul(net_id, NULL, 10);
-       ssid = wpa_config_get_network(wpa_s->conf, id);
-       if (ssid == NULL) {
+       result = wpa_supplicant_remove_network(wpa_s, id);
+       if (result == -1) {
                reply = wpas_dbus_new_invalid_network_error(message);
                goto out;
        }
-
-       wpas_notify_network_removed(wpa_s, ssid);
-
-       if (ssid == wpa_s->current_ssid)
-               wpa_supplicant_deauthenticate(wpa_s,
-                                             WLAN_REASON_DEAUTH_LEAVING);
-
-       if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+       if (result == -2) {
                reply = dbus_message_new_error(
                        message, WPAS_ERROR_REMOVE_NETWORK_ERROR,
                        "error removing the specified on this interface.");
@@ -1069,8 +1059,7 @@ out:
 DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
                                         struct wpa_supplicant *wpa_s)
 {
-       wpa_s->disconnected = 1;
-       wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+       wpas_request_disconnection(wpa_s);
 
        return wpas_dbus_new_success_reply(message);
 }
index 01a8c2c..1d05198 100644 (file)
@@ -31,6 +31,9 @@ CONFIG_DRIVER_WEXT=y
 # Driver interface for Linux drivers using the nl80211 kernel interface
 CONFIG_DRIVER_NL80211=y
 
+# QCA vendor extensions to nl80211
+#CONFIG_DRIVER_NL80211_QCA=y
+
 # driver_nl80211.c requires libnl. If you are compiling it yourself
 # you may need to point hostapd to your version of libnl.
 #
@@ -267,6 +270,9 @@ CONFIG_BACKEND=file
 # Should we use epoll instead of select? Select is used by default.
 #CONFIG_ELOOP_EPOLL=y
 
+# Should we use kqueue instead of select? Select is used by default.
+#CONFIG_ELOOP_KQUEUE=y
+
 # Select layer 2 packet implementation
 # linux = Linux packet socket (default)
 # pcap = libpcap/libdnet/WinPcap
@@ -276,6 +282,12 @@ CONFIG_BACKEND=file
 # none = Empty template
 #CONFIG_L2_PACKET=linux
 
+# Disable Linux packet socket workaround applicable for station interface
+# in a bridge for EAPOL frames. This should be uncommented only if the kernel
+# is known to not have the regression issue in packet socket behavior with
+# bridge interfaces (commit 'bridge: respect RFC2863 operational state')').
+#CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
+
 # PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
 CONFIG_PEERKEY=y
 
@@ -455,6 +467,9 @@ CONFIG_PEERKEY=y
 # Hotspot 2.0
 #CONFIG_HS20=y
 
+# Enable interface matching in wpa_supplicant
+#CONFIG_MATCH_IFACE=y
+
 # Disable roaming in wpa_supplicant
 #CONFIG_NO_ROAMING=y
 
@@ -504,3 +519,32 @@ CONFIG_PEERKEY=y
 
 # OS X builds. This is only for building eapol_test.
 #CONFIG_OSX=y
+
+# Automatic Channel Selection
+# This will allow wpa_supplicant to pick the channel automatically when channel
+# is set to "0".
+#
+# TODO: Extend parser to be able to parse "channel=acs_survey" as an alternative
+# to "channel=0". This would enable us to eventually add other ACS algorithms in
+# similar way.
+#
+# Automatic selection is currently only done through initialization, later on
+# we hope to do background checks to keep us moving to more ideal channels as
+# time goes by. ACS is currently only supported through the nl80211 driver and
+# your driver must have survey dump capability that is filled by the driver
+# during scanning.
+#
+# TODO: In analogy to hostapd be able to customize the ACS survey algorithm with
+# a newly to create wpa_supplicant.conf variable acs_num_scans.
+#
+# Supported ACS drivers:
+# * ath9k
+# * ath5k
+# * ath10k
+#
+# For more details refer to:
+# http://wireless.kernel.org/en/users/Documentation/acs
+#CONFIG_ACS=y
+
+# Support Multi Band Operation
+#CONFIG_MBO=y
index e9af6d9..3f22413 100644 (file)
@@ -194,7 +194,7 @@ eapol_test -ctest.conf -a127.0.0.1 -p1812 -ssecret -r1
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2015,
+    <para>wpa_supplicant is copyright (c) 2003-2016,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
index afb8c3b..13c9f45 100644 (file)
@@ -90,7 +90,7 @@
 
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2015,
+    <para>wpa_supplicant is copyright (c) 2003-2016,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
index 47947c1..15400f0 100644 (file)
@@ -345,7 +345,7 @@ CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2015,
+    <para>wpa_supplicant is copyright (c) 2003-2016,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
index 5f7b49d..352d3d2 100644 (file)
@@ -91,7 +91,7 @@
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2015,
+    <para>wpa_supplicant is copyright (c) 2003-2016,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
index b381e40..faf1f27 100644 (file)
@@ -62,7 +62,7 @@
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2015,
+    <para>wpa_supplicant is copyright (c) 2003-2016,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
index d13a5db..403c9b2 100644 (file)
@@ -137,7 +137,7 @@ wpa_supplicant -i ath0 -c wpa_supplicant.conf
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2015,
+    <para>wpa_supplicant is copyright (c) 2003-2016,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
index 46c21b5..11e0e90 100644 (file)
       </varlistentry>
 
       <varlistentry>
-       <term>-t</term>
-       <listitem>
-         <para>Include timestamp in debug messages.</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
        <term>-h</term>
        <listitem>
          <para>Help.  Show a usage message.</para>
@@ -736,7 +729,7 @@ fi
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2015,
+    <para>wpa_supplicant is copyright (c) 2003-2016,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
index 73768c7..220b7ba 100644 (file)
@@ -100,12 +100,10 @@ static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
 }
 
 static inline int wpa_drv_sched_scan(struct wpa_supplicant *wpa_s,
-                                    struct wpa_driver_scan_params *params,
-                                    u32 interval)
+                                    struct wpa_driver_scan_params *params)
 {
        if (wpa_s->driver->sched_scan)
-               return wpa_s->driver->sched_scan(wpa_s->drv_priv,
-                                                params, interval);
+               return wpa_s->driver->sched_scan(wpa_s->drv_priv, params);
        return -1;
 }
 
@@ -160,6 +158,15 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
        return -1;
 }
 
+static inline int wpa_drv_get_seqnum(struct wpa_supplicant *wpa_s,
+                                    const u8 *addr, int idx, u8 *seq)
+{
+       if (wpa_s->driver->get_seqnum)
+               return wpa_s->driver->get_seqnum(wpa_s->ifname, wpa_s->drv_priv,
+                                                addr, idx, seq);
+       return -1;
+}
+
 static inline int wpa_drv_sta_deauth(struct wpa_supplicant *wpa_s,
                                     const u8 *addr, int reason_code)
 {
@@ -292,7 +299,7 @@ static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
        if (wpa_s->driver->send_mlme)
                return wpa_s->driver->send_mlme(wpa_s->drv_priv,
                                                data, data_len, noack,
-                                               freq);
+                                               freq, NULL, 0);
        return -1;
 }
 
@@ -401,7 +408,7 @@ static inline int wpa_drv_if_add(struct wpa_supplicant *wpa_s,
        if (wpa_s->driver->if_add)
                return wpa_s->driver->if_add(wpa_s->drv_priv, type, ifname,
                                             addr, bss_ctx, NULL, force_ifname,
-                                            if_addr, bridge, 0);
+                                            if_addr, bridge, 0, 0);
        return -1;
 }
 
@@ -726,12 +733,11 @@ static inline int wpa_drv_set_replay_protect(struct wpa_supplicant *wpa_s,
 }
 
 static inline int wpa_drv_set_current_cipher_suite(struct wpa_supplicant *wpa_s,
-                                                  const u8 *cs, size_t cs_len)
+                                                  u64 cs)
 {
        if (!wpa_s->driver->set_current_cipher_suite)
                return -1;
-       return wpa_s->driver->set_current_cipher_suite(wpa_s->drv_priv, cs,
-                                                      cs_len);
+       return wpa_s->driver->set_current_cipher_suite(wpa_s->drv_priv, cs);
 }
 
 static inline int wpa_drv_enable_controlled_port(struct wpa_supplicant *wpa_s,
@@ -912,4 +918,62 @@ static inline int wpa_drv_set_prob_oper_freq(struct wpa_supplicant *wpa_s,
        return wpa_s->driver->set_prob_oper_freq(wpa_s->drv_priv, freq);
 }
 
+static inline int wpa_drv_abort_scan(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s->driver->abort_scan)
+               return -1;
+       return wpa_s->driver->abort_scan(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_configure_frame_filters(struct wpa_supplicant *wpa_s,
+                                                 u32 filters)
+{
+       if (!wpa_s->driver->configure_data_frame_filters)
+               return -1;
+       return wpa_s->driver->configure_data_frame_filters(wpa_s->drv_priv,
+                                                          filters);
+}
+
+static inline int wpa_drv_get_ext_capa(struct wpa_supplicant *wpa_s,
+                                      enum wpa_driver_if_type type)
+{
+       if (!wpa_s->driver->get_ext_capab)
+               return -1;
+       return wpa_s->driver->get_ext_capab(wpa_s->drv_priv, type,
+                                           &wpa_s->extended_capa,
+                                           &wpa_s->extended_capa_mask,
+                                           &wpa_s->extended_capa_len);
+}
+
+static inline int wpa_drv_p2p_lo_start(struct wpa_supplicant *wpa_s,
+                                      unsigned int channel,
+                                      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)
+{
+       if (!wpa_s->driver->p2p_lo_start)
+               return -1;
+       return wpa_s->driver->p2p_lo_start(wpa_s->drv_priv, channel, period,
+                                          interval, count, device_types,
+                                          dev_types_len, ies, ies_len);
+}
+
+static inline int wpa_drv_p2p_lo_stop(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s->driver->p2p_lo_stop)
+               return -1;
+       return wpa_s->driver->p2p_lo_stop(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_set_default_scan_ies(struct wpa_supplicant *wpa_s,
+                                              const u8 *ies, size_t len)
+{
+       if (!wpa_s->driver->set_default_scan_ies)
+               return -1;
+       return wpa_s->driver->set_default_scan_ies(wpa_s->drv_priv, ies, len);
+}
+
 #endif /* DRIVER_I_H */
index dce7d1f..6548bd1 100644 (file)
@@ -14,6 +14,7 @@
 
 #include "common.h"
 #include "utils/ext_password.h"
+#include "common/version.h"
 #include "config.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "eap_peer/eap.h"
@@ -192,7 +193,7 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
                return;
        }
 
-       radius_msg_make_authenticator(msg, (u8 *) e, sizeof(*e));
+       radius_msg_make_authenticator(msg);
 
        hdr = (const struct eap_hdr *) eap;
        pos = (const u8 *) (hdr + 1);
@@ -257,6 +258,13 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
                goto fail;
        }
 
+       if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_SERVICE_TYPE) &&
+           !radius_msg_add_attr_int32(msg, RADIUS_ATTR_SERVICE_TYPE,
+                                      RADIUS_SERVICE_TYPE_FRAMED)) {
+               printf("Could not add Service-Type\n");
+               goto fail;
+       }
+
        os_snprintf(buf, sizeof(buf), "%s", e->connect_info);
        if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CONNECT_INFO) &&
            !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
@@ -1239,7 +1247,7 @@ static void eapol_test_terminate(int sig, void *signal_ctx)
 static void usage(void)
 {
        printf("usage:\n"
-              "eapol_test [-enWS] -c<conf> [-a<AS IP>] [-p<AS port>] "
+              "eapol_test [-enWSv] -c<conf> [-a<AS IP>] [-p<AS port>] "
               "[-s<AS secret>]\\\n"
               "           [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n"
               "           [-M<client MAC address>] [-o<server cert file] \\\n"
@@ -1264,6 +1272,7 @@ static void usage(void)
               "  -W = wait for a control interface monitor before starting\n"
               "  -S = save configuration after authentication\n"
               "  -n = no MPPE keys expected\n"
+              "  -v = show version\n"
               "  -t<timeout> = sets timeout in seconds (default: 30 s)\n"
               "  -C<Connect-Info> = RADIUS Connect-Info (default: "
               "CONNECT 11Mbps 802.11b)\n"
@@ -1317,7 +1326,7 @@ int main(int argc, char *argv[])
        wpa_debug_show_keys = 1;
 
        for (;;) {
-               c = getopt(argc, argv, "a:A:c:C:ei:M:nN:o:p:P:r:R:s:St:T:W");
+               c = getopt(argc, argv, "a:A:c:C:ei:M:nN:o:p:P:r:R:s:St:T:vW");
                if (c < 0)
                        break;
                switch (c) {
@@ -1383,6 +1392,9 @@ int main(int argc, char *argv[])
                        ctrl_iface = optarg;
                        eapol_test.ctrl_iface = 1;
                        break;
+               case 'v':
+                       printf("eapol_test v" VERSION_STR "\n");
+                       return 0;
                case 'W':
                        wait_for_monitor++;
                        break;
index 3af1c7d..abe3b47 100644 (file)
@@ -72,6 +72,7 @@ static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
 }
 
 
+#ifndef CONFIG_NO_SCAN_PROCESSING
 /**
  * wpas_reenabled_network_time - Time until first network is re-enabled
  * @wpa_s: Pointer to wpa_supplicant data
@@ -107,6 +108,7 @@ static int wpas_reenabled_network_time(struct wpa_supplicant *wpa_s)
 
        return res;
 }
+#endif /* CONFIG_NO_SCAN_PROCESSING */
 
 
 void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx)
@@ -279,6 +281,11 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
        wpa_supplicant_ap_deinit(wpa_s);
 #endif /* CONFIG_AP */
 
+#ifdef CONFIG_HS20
+       /* Clear possibly configured frame filters */
+       wpa_drv_configure_frame_filters(wpa_s, 0);
+#endif /* CONFIG_HS20 */
+
        if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
                return;
 
@@ -303,6 +310,7 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
        wpa_s->key_mgmt = 0;
 
        wpas_rrm_reset(wpa_s);
+       wpa_s->wnmsleep_used = 0;
 }
 
 
@@ -564,11 +572,36 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
                        break;
                }
 #endif /* CONFIG_IEEE80211W */
+               if ((ie.capabilities & WPA_CAPABILITY_MFPR) &&
+                   wpas_get_ssid_pmf(wpa_s, ssid) ==
+                   NO_MGMT_FRAME_PROTECTION) {
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "   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) {
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "   skip RSN IE - no mgmt frame protection enabled on MBO AP");
+                       break;
+               }
+#endif /* CONFIG_MBO */
 
                wpa_dbg(wpa_s, MSG_DEBUG, "   selected based on RSN IE");
                return 1;
        }
 
+#ifdef CONFIG_IEEE80211W
+       if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "   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) {
                proto_match++;
@@ -806,10 +839,10 @@ static int addr_in_list(const u8 *addr, const u8 *list, size_t num)
 }
 
 
-static 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)
+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)
 {
        u8 wpa_ie_len, rsn_ie_len;
        int wpa;
@@ -817,6 +850,9 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
        const u8 *ie;
        struct wpa_ssid *ssid;
        int osen;
+#ifdef CONFIG_MBO
+       const u8 *assoc_disallow;
+#endif /* CONFIG_MBO */
 
        ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
        wpa_ie_len = ie ? ie[1] : 0;
@@ -978,8 +1014,16 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                        continue;
                }
 
-               if (!bss_is_ess(bss)) {
-                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip - not ESS network");
+               if (ssid->mode != IEEE80211_MODE_MESH && !bss_is_ess(bss) &&
+                   !bss_is_pbss(bss)) {
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "   skip - not ESS, PBSS, or MBSS");
+                       continue;
+               }
+
+               if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip - PBSS mismatch (ssid %d bss %d)",
+                               ssid->pbss, bss_is_pbss(bss));
                        continue;
                }
 
@@ -989,6 +1033,14 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                        continue;
                }
 
+#ifdef CONFIG_MESH
+               if (ssid->mode == IEEE80211_MODE_MESH && ssid->frequency > 0 &&
+                   ssid->frequency != bss->freq) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "   skip - frequency not allowed (mesh)");
+                       continue;
+               }
+#endif /* CONFIG_MESH */
+
                if (!rate_match(wpa_s, bss)) {
                        wpa_dbg(wpa_s, MSG_DEBUG, "   skip - rate sets do "
                                "not match");
@@ -1048,6 +1100,29 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                                (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) {
+                       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->bssid)) {
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "   skip - MBO retry delay has not passed yet");
+                       continue;
+               }
+#ifdef CONFIG_TESTING_OPTIONS
+       skip_assoc_disallow:
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_MBO */
 
                /* Matching configuration found */
                return ssid;
@@ -1301,6 +1376,7 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
        struct wpa_bss *current_bss = NULL;
 #ifndef CONFIG_NO_ROAMING
        int min_diff;
+       int to_5ghz;
 #endif /* CONFIG_NO_ROAMING */
 
        if (wpa_s->reassociate)
@@ -1356,7 +1432,10 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
                return 1;
        }
 
-       if (current_bss->level < 0 && current_bss->level > selected->level) {
+       to_5ghz = selected->freq > 4000 && current_bss->freq < 4000;
+
+       if (current_bss->level < 0 &&
+           current_bss->level > selected->level + to_5ghz * 2) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
                        "signal level");
                return 0;
@@ -1375,6 +1454,13 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
                else
                        min_diff = 5;
        }
+       if (to_5ghz) {
+               /* Make it easier to move to 5 GHz band */
+               if (min_diff > 2)
+                       min_diff -= 2;
+               else
+                       min_diff = 0;
+       }
        if (abs(current_bss->level - selected->level) < min_diff) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - too small difference "
                        "in signal level");
@@ -1417,6 +1503,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
                        return -1;
                if (!own_request)
                        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);
@@ -1441,7 +1529,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_NO_RANDOM_POOL */
 
        if (own_request && wpa_s->scan_res_handler &&
-           (wpa_s->own_scan_running || !wpa_s->radio->external_scan_running)) {
+           !(data && data->scan_info.external_scan)) {
                void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
                                         struct wpa_scan_results *scan_res);
 
@@ -1462,9 +1550,11 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
        }
 
        wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)",
-               wpa_s->own_scan_running, wpa_s->radio->external_scan_running);
+               wpa_s->own_scan_running,
+               data ? data->scan_info.external_scan : 0);
        if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
-           wpa_s->manual_scan_use_id && wpa_s->own_scan_running) {
+           wpa_s->manual_scan_use_id && wpa_s->own_scan_running &&
+           own_request && !(data && data->scan_info.external_scan)) {
                wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u",
                             wpa_s->manual_scan_id);
                wpa_s->manual_scan_use_id = 0;
@@ -1475,7 +1565,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 
        wpas_notify_scan_done(wpa_s, 1);
 
-       if (!wpa_s->own_scan_running && wpa_s->radio->external_scan_running) {
+       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);
                return 0;
@@ -1504,9 +1594,13 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 
        wpas_wps_update_ap_info(wpa_s, scan_res);
 
+       if (wpa_s->wpa_state >= WPA_AUTHENTICATING &&
+           wpa_s->wpa_state < WPA_COMPLETED)
+               goto scan_work_done;
+
        wpa_scan_results_free(scan_res);
 
-       if (wpa_s->scan_work) {
+       if (own_request && wpa_s->scan_work) {
                struct wpa_radio_work *work = wpa_s->scan_work;
                wpa_s->scan_work = NULL;
                radio_work_done(work);
@@ -1516,7 +1610,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 
 scan_work_done:
        wpa_scan_results_free(scan_res);
-       if (wpa_s->scan_work) {
+       if (own_request && wpa_s->scan_work) {
                struct wpa_radio_work *work = wpa_s->scan_work;
                wpa_s->scan_work = NULL;
                radio_work_done(work);
@@ -1547,6 +1641,14 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
 
        selected = wpa_supplicant_pick_network(wpa_s, &ssid);
 
+#ifdef CONFIG_MESH
+       if (wpa_s->ifmsh) {
+               wpa_msg(wpa_s, MSG_INFO,
+                       "Avoiding join because we already joined a mesh group");
+               return 0;
+       }
+#endif /* CONFIG_MESH */
+
        if (selected) {
                int skip;
                skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid);
@@ -1556,6 +1658,13 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
                        return 0;
                }
 
+               if (ssid != wpa_s->current_ssid &&
+                   wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+                       wpa_s->own_disconnect_req = 1;
+                       wpa_supplicant_deauthenticate(
+                               wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+               }
+
                if (wpa_supplicant_connect(wpa_s, selected, ssid) < 0) {
                        wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed");
                        return -1;
@@ -1568,13 +1677,6 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
                 */
                return 1;
        } else {
-#ifdef CONFIG_MESH
-               if (wpa_s->ifmsh) {
-                       wpa_msg(wpa_s, MSG_INFO,
-                               "Avoiding join because we already joined a mesh group");
-                       return 0;
-               }
-#endif /* CONFIG_MESH */
                wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
                ssid = wpa_supplicant_pick_new_network(wpa_s);
                if (ssid) {
@@ -1830,6 +1932,50 @@ static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_INTERWORKING */
 
 
+#ifdef CONFIG_FST
+static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
+                               const u8 *ie, size_t ie_len)
+{
+       struct mb_ies_info mb_ies;
+
+       if (!ie || !ie_len || !wpa_s->fst)
+           return -ENOENT;
+
+       os_memset(&mb_ies, 0, sizeof(mb_ies));
+
+       while (ie_len >= 2 && mb_ies.nof_ies < MAX_NOF_MB_IES_SUPPORTED) {
+               size_t len;
+
+               len = 2 + ie[1];
+               if (len > ie_len) {
+                       wpa_hexdump(MSG_DEBUG, "FST: Truncated IE found",
+                                   ie, ie_len);
+                       break;
+               }
+
+               if (ie[0] == WLAN_EID_MULTI_BAND) {
+                       wpa_printf(MSG_DEBUG, "MB IE of %u bytes found",
+                                  (unsigned int) len);
+                       mb_ies.ies[mb_ies.nof_ies].ie = ie + 2;
+                       mb_ies.ies[mb_ies.nof_ies].ie_len = len - 2;
+                       mb_ies.nof_ies++;
+               }
+
+               ie_len -= len;
+               ie += len;
+       }
+
+       if (mb_ies.nof_ies > 0) {
+               wpabuf_free(wpa_s->received_mb_ies);
+               wpa_s->received_mb_ies = mb_ies_by_info(&mb_ies);
+               return 0;
+       }
+
+       return -ENOENT;
+}
+#endif /* CONFIG_FST */
+
+
 static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
                                          union wpa_event_data *data)
 {
@@ -1880,6 +2026,8 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
                }
                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 (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
                                break;
@@ -2012,19 +2160,6 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
        if (wpa_found || rsn_found)
                wpa_s->ap_ies_from_associnfo = 1;
 
-#ifdef CONFIG_FST
-       wpabuf_free(wpa_s->received_mb_ies);
-       wpa_s->received_mb_ies = NULL;
-       if (wpa_s->fst) {
-               struct mb_ies_info mb_ies;
-
-               wpa_printf(MSG_DEBUG, "Looking for MB IE");
-               if (!mb_ies_info_by_ies(&mb_ies, data->assoc_info.resp_ies,
-                                       data->assoc_info.resp_ies_len))
-                       wpa_s->received_mb_ies = mb_ies_by_info(&mb_ies);
-       }
-#endif /* CONFIG_FST */
-
        if (wpa_s->assoc_freq && data->assoc_info.freq &&
            wpa_s->assoc_freq != data->assoc_info.freq) {
                wpa_printf(MSG_DEBUG, "Operating frequency changed from "
@@ -2063,11 +2198,50 @@ static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
 }
 
 
+static void wpas_fst_update_mb_assoc(struct wpa_supplicant *wpa_s,
+                                    union wpa_event_data *data)
+{
+#ifdef CONFIG_FST
+       struct assoc_info *ai = data ? &data->assoc_info : NULL;
+       struct wpa_bss *bss = wpa_s->current_bss;
+       const u8 *ieprb, *iebcn;
+
+       wpabuf_free(wpa_s->received_mb_ies);
+       wpa_s->received_mb_ies = NULL;
+
+       if (ai &&
+           !wpas_fst_update_mbie(wpa_s, ai->resp_ies, ai->resp_ies_len)) {
+               wpa_printf(MSG_DEBUG,
+                          "FST: MB IEs updated from Association Response frame");
+               return;
+       }
+
+       if (ai &&
+           !wpas_fst_update_mbie(wpa_s, ai->beacon_ies, ai->beacon_ies_len)) {
+               wpa_printf(MSG_DEBUG,
+                          "FST: MB IEs updated from association event Beacon IEs");
+               return;
+       }
+
+       if (!bss)
+               return;
+
+       ieprb = (const u8 *) (bss + 1);
+       iebcn = ieprb + bss->ie_len;
+
+       if (!wpas_fst_update_mbie(wpa_s, ieprb, bss->ie_len))
+               wpa_printf(MSG_DEBUG, "FST: MB IEs updated from bss IE");
+       else if (!wpas_fst_update_mbie(wpa_s, iebcn, bss->beacon_ie_len))
+               wpa_printf(MSG_DEBUG, "FST: MB IEs updated from bss beacon IE");
+#endif /* CONFIG_FST */
+}
+
+
 static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                                       union wpa_event_data *data)
 {
        u8 bssid[ETH_ALEN];
-       int ft_completed;
+       int ft_completed, already_authorized;
        int new_bss = 0;
 
 #ifdef CONFIG_AP
@@ -2123,6 +2297,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                                "WPA/RSN IEs not updated");
        }
 
+       wpas_fst_update_mb_assoc(wpa_s, data);
+
 #ifdef CONFIG_SME
        os_memcpy(wpa_s->sme.prev_bssid, bssid, ETH_ALEN);
        wpa_s->sme.prev_bssid_set = 1;
@@ -2141,6 +2317,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
        if (wpa_s->l2)
                l2_packet_notify_auth_start(wpa_s->l2);
 
+       already_authorized = data && data->assoc_info.authorized;
+
        /*
         * Set portEnabled first to FALSE in order to get EAP state machine out
         * of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE
@@ -2149,11 +2327,12 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
         * AUTHENTICATED without ever giving chance to EAP state machine to
         * reset the state.
         */
-       if (!ft_completed) {
+       if (!ft_completed && !already_authorized) {
                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) || ft_completed)
+       if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || ft_completed ||
+           already_authorized)
                eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
        /* 802.1X::portControl = Auto */
        eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
@@ -2245,7 +2424,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
            wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
            wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE &&
            wpa_s->ibss_rsn == NULL) {
-               wpa_s->ibss_rsn = ibss_rsn_init(wpa_s);
+               wpa_s->ibss_rsn = ibss_rsn_init(wpa_s, wpa_s->current_ssid);
                if (!wpa_s->ibss_rsn) {
                        wpa_msg(wpa_s, MSG_INFO, "Failed to init IBSS RSN");
                        wpa_supplicant_deauthenticate(
@@ -2339,6 +2518,7 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
        struct wpa_bss *fast_reconnect = NULL;
        struct wpa_ssid *fast_reconnect_ssid = NULL;
        struct wpa_ssid *last_ssid;
+       struct wpa_bss *curr = NULL;
 
        authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING;
        os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN);
@@ -2354,6 +2534,19 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
                return;
        }
 
+       if (!wpa_s->disconnected && wpa_s->wpa_state >= WPA_AUTHENTICATING &&
+           reason_code == WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY &&
+           locally_generated)
+               /*
+                * Remove the inactive AP (which is probably out of range) from
+                * the BSS list after marking disassociation. In particular
+                * mac80211-based drivers use the
+                * WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY reason code in
+                * locally generated disconnection events for cases where the
+                * AP does not reply anymore.
+                */
+               curr = wpa_s->current_bss;
+
        if (could_be_psk_mismatch(wpa_s, reason_code, locally_generated)) {
                wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
                        "pre-shared key may be incorrect");
@@ -2364,7 +2557,8 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
        if (!wpa_s->disconnected &&
            (!wpa_s->auto_reconnect_disabled ||
             wpa_s->key_mgmt == WPA_KEY_MGMT_WPS ||
-            wpas_wps_searching(wpa_s))) {
+            wpas_wps_searching(wpa_s) ||
+            wpas_wps_reenable_networks_pending(wpa_s))) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect enabled: try to "
                        "reconnect (wps=%d/%d wpa_state=%d)",
                        wpa_s->key_mgmt == WPA_KEY_MGMT_WPS,
@@ -2414,6 +2608,9 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
        last_ssid = wpa_s->current_ssid;
        wpa_supplicant_mark_disassoc(wpa_s);
 
+       if (curr)
+               wpa_bss_remove(wpa_s, curr, "Connection to AP lost");
+
        if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) {
                sme_disassoc_while_authenticating(wpa_s, prev_pending_bssid);
                wpa_s->current_ssid = last_ssid;
@@ -2424,7 +2621,8 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
            !disallowed_bssid(wpa_s, fast_reconnect->bssid) &&
            !disallowed_ssid(wpa_s, fast_reconnect->ssid,
                             fast_reconnect->ssid_len) &&
-           !wpas_temp_disabled(wpa_s, fast_reconnect_ssid)) {
+           !wpas_temp_disabled(wpa_s, fast_reconnect_ssid) &&
+           !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect->bssid)) {
 #ifndef CONFIG_NO_SCAN_PROCESSING
                wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS");
                if (wpa_supplicant_connect(wpa_s, fast_reconnect,
@@ -2622,6 +2820,13 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
                }
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_MATCH_IFACE
+               if (wpa_s->matched) {
+                       wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
+                       break;
+               }
+#endif /* CONFIG_MATCH_IFACE */
+
 #ifdef CONFIG_TERMINATE_ONLASTIF
                /* check if last interface */
                if (!any_interfaces(wpa_s->global->ifaces))
@@ -3007,7 +3212,16 @@ static void wpa_supplicant_update_channel_list(
 {
        struct wpa_supplicant *ifs;
 
-       wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s",
+       /*
+        * To allow backwards compatibility with higher level layers that
+        * assumed the REGDOM_CHANGE event is sent over the initially added
+        * interface. Find the highest parent of this interface and use it to
+        * send the event.
+        */
+       for (ifs = wpa_s; ifs->parent && ifs != ifs->parent; ifs = ifs->parent)
+               ;
+
+       wpa_msg(ifs, MSG_INFO, WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s",
                reg_init_str(info->initiator), reg_type_str(info->type),
                info->alpha2[0] ? " alpha2=" : "",
                info->alpha2[0] ? info->alpha2 : "");
@@ -3022,14 +3236,16 @@ static void wpa_supplicant_update_channel_list(
                free_hw_features(ifs);
                ifs->hw.modes = wpa_drv_get_hw_feature_data(
                        ifs, &ifs->hw.num_modes, &ifs->hw.flags);
-       }
 
-       /* Restart sched_scan with updated channel list */
-       if (wpa_s->sched_scanning) {
-               wpa_dbg(wpa_s, MSG_DEBUG,
-                       "Channel list changed restart sched scan.");
-               wpa_supplicant_cancel_sched_scan(wpa_s);
-               wpa_supplicant_req_scan(wpa_s, 0, 0);
+               /* Restart PNO/sched_scan with updated channel list */
+               if (ifs->pno) {
+                       wpas_stop_pno(ifs);
+                       wpas_start_pno(ifs);
+               } else if (ifs->sched_scanning && !ifs->pno_sched_pending) {
+                       wpa_dbg(ifs, MSG_DEBUG,
+                               "Channel list changed - restart sched_scan");
+                       wpas_scan_restart_sched_scan(ifs);
+               }
        }
 
        wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_DRIVER);
@@ -3120,6 +3336,14 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_INTERWORKING */
 
        if (category == WLAN_ACTION_RADIO_MEASUREMENT &&
+           payload[0] == WLAN_RRM_RADIO_MEASUREMENT_REQUEST) {
+               wpas_rrm_handle_radio_measurement_request(wpa_s, mgmt->sa,
+                                                         payload + 1,
+                                                         plen - 1);
+               return;
+       }
+
+       if (category == WLAN_ACTION_RADIO_MEASUREMENT &&
            payload[0] == WLAN_RRM_NEIGHBOR_REPORT_RESPONSE) {
                wpas_rrm_process_neighbor_rep(wpa_s, payload + 1, plen - 1);
                return;
@@ -3209,6 +3433,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
        if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
            event != EVENT_INTERFACE_ENABLED &&
            event != EVENT_INTERFACE_STATUS &&
+           event != EVENT_SCAN_RESULTS &&
            event != EVENT_SCHED_SCAN_STOPPED) {
                wpa_dbg(wpa_s, MSG_DEBUG,
                        "Ignore event %s (%d) while interface is disabled",
@@ -3237,18 +3462,43 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 
        switch (event) {
        case EVENT_AUTH:
+#ifdef CONFIG_FST
+               if (!wpas_fst_update_mbie(wpa_s, data->auth.ies,
+                                         data->auth.ies_len))
+                       wpa_printf(MSG_DEBUG,
+                                  "FST: MB IEs updated from auth IE");
+#endif /* CONFIG_FST */
                sme_event_auth(wpa_s, data);
                break;
        case EVENT_ASSOC:
+#ifdef CONFIG_TESTING_OPTIONS
+               if (wpa_s->ignore_auth_resp) {
+                       wpa_printf(MSG_INFO,
+                                  "EVENT_ASSOC - ignore_auth_resp active!");
+                       break;
+               }
+#endif /* CONFIG_TESTING_OPTIONS */
                wpa_supplicant_event_assoc(wpa_s, data);
                if (data && data->assoc_info.authorized)
                        wpa_supplicant_event_assoc_auth(wpa_s, data);
+               if (data) {
+                       wpa_msg(wpa_s, MSG_INFO,
+                               WPA_EVENT_SUBNET_STATUS_UPDATE "status=%u",
+                               data->assoc_info.subnet_status);
+               }
                break;
        case EVENT_DISASSOC:
                wpas_event_disassoc(wpa_s,
                                    data ? &data->disassoc_info : NULL);
                break;
        case EVENT_DEAUTH:
+#ifdef CONFIG_TESTING_OPTIONS
+               if (wpa_s->ignore_auth_resp) {
+                       wpa_printf(MSG_INFO,
+                                  "EVENT_DEAUTH - ignore_auth_resp active!");
+                       break;
+               }
+#endif /* CONFIG_TESTING_OPTIONS */
                wpas_event_deauth(wpa_s,
                                  data ? &data->deauth_info : NULL);
                break;
@@ -3257,10 +3507,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                break;
 #ifndef CONFIG_NO_SCAN_PROCESSING
        case EVENT_SCAN_STARTED:
-               os_get_reltime(&wpa_s->scan_start_time);
-               if (wpa_s->own_scan_requested) {
+               if (wpa_s->own_scan_requested ||
+                   (data && !data->scan_info.external_scan)) {
                        struct os_reltime diff;
 
+                       os_get_reltime(&wpa_s->scan_start_time);
                        os_reltime_sub(&wpa_s->scan_start_time,
                                       &wpa_s->scan_trigger_time, &diff);
                        wpa_dbg(wpa_s, MSG_DEBUG, "Own scan request started a scan in %ld.%06ld seconds",
@@ -3283,7 +3534,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                }
                break;
        case EVENT_SCAN_RESULTS:
-               if (os_reltime_initialized(&wpa_s->scan_start_time)) {
+               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->last_scan_req = NORMAL_SCAN_REQ;
+                       break;
+               }
+
+               if (!(data && data->scan_info.external_scan) &&
+                   os_reltime_initialized(&wpa_s->scan_start_time)) {
                        struct os_reltime now, diff;
                        os_get_reltime(&now);
                        os_reltime_sub(&now, &wpa_s->scan_start_time, &diff);
@@ -3294,8 +3554,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                }
                if (wpa_supplicant_event_scan_results(wpa_s, data))
                        break; /* interface may have been removed */
-               wpa_s->own_scan_running = 0;
-               wpa_s->radio->external_scan_running = 0;
+               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;
                radio_work_check_next(wpa_s);
                break;
 #endif /* CONFIG_NO_SCAN_PROCESSING */
@@ -3336,13 +3598,17 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
        case EVENT_ASSOC_REJECT:
                if (data->assoc_reject.bssid)
                        wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
-                               "bssid=" MACSTR " status_code=%u",
+                               "bssid=" MACSTR " status_code=%u%s",
                                MAC2STR(data->assoc_reject.bssid),
-                               data->assoc_reject.status_code);
+                               data->assoc_reject.status_code,
+                               data->assoc_reject.timed_out ? " timeout" : "");
                else
                        wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
-                               "status_code=%u",
-                               data->assoc_reject.status_code);
+                               "status_code=%u%s",
+                               data->assoc_reject.status_code,
+                               data->assoc_reject.timed_out ? " timeout" : "");
+               wpa_s->assoc_status_code = data->assoc_reject.status_code;
+               wpas_notify_assoc_status_code(wpa_s);
                if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
                        sme_event_assoc_reject(wpa_s, data);
                else {
@@ -3398,17 +3664,20 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 #endif /* CONFIG_AP */
 #ifdef CONFIG_OFFCHANNEL
                wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS pending_dst="
-                       MACSTR, MAC2STR(wpa_s->parent->pending_action_dst));
+                       MACSTR, MAC2STR(wpa_s->p2pdev->pending_action_dst));
                /*
                 * Catch TX status events for Action frames we sent via group
-                * interface in GO mode.
+                * interface in GO mode, or via standalone AP interface.
+                * Note, wpa_s->p2pdev will be the same as wpa_s->parent,
+                * except when the primary interface is used as a GO interface
+                * (for drivers which do not have group interface concurrency)
                 */
                if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
                    data->tx_status.stype == WLAN_FC_STYPE_ACTION &&
-                   os_memcmp(wpa_s->parent->pending_action_dst,
+                   os_memcmp(wpa_s->p2pdev->pending_action_dst,
                              data->tx_status.dst, ETH_ALEN) == 0) {
                        offchannel_send_action_tx_status(
-                               wpa_s->parent, data->tx_status.dst,
+                               wpa_s->p2pdev, data->tx_status.dst,
                                data->tx_status.data,
                                data->tx_status.data_len,
                                data->tx_status.ack ?
@@ -3451,20 +3720,34 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                       data->rx_from_unknown.wds);
                break;
        case EVENT_CH_SWITCH:
-               if (!data)
-                       break;
-               if (!wpa_s->ap_iface) {
-                       wpa_dbg(wpa_s, MSG_DEBUG, "AP: Ignore channel switch "
-                               "event in non-AP mode");
+               if (!data || !wpa_s->current_ssid)
                        break;
+
+               wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CHANNEL_SWITCH
+                       "freq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d",
+                       data->ch_switch.freq,
+                       data->ch_switch.ht_enabled,
+                       data->ch_switch.ch_offset,
+                       channel_width_to_string(data->ch_switch.ch_width),
+                       data->ch_switch.cf1,
+                       data->ch_switch.cf2);
+
+               wpa_s->assoc_freq = data->ch_switch.freq;
+               wpa_s->current_ssid->frequency = data->ch_switch.freq;
+
+               if (wpa_s->current_ssid->mode == WPAS_MODE_AP ||
+                   wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO ||
+                   wpa_s->current_ssid->mode ==
+                   WPAS_MODE_P2P_GROUP_FORMATION) {
+                       wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
+                                         data->ch_switch.ht_enabled,
+                                         data->ch_switch.ch_offset,
+                                         data->ch_switch.ch_width,
+                                         data->ch_switch.cf1,
+                                         data->ch_switch.cf2);
                }
 
-               wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
-                                 data->ch_switch.ht_enabled,
-                                 data->ch_switch.ch_offset,
-                                 data->ch_switch.ch_width,
-                                 data->ch_switch.cf1,
-                                 data->ch_switch.cf2);
+               wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS);
                break;
 #ifdef NEED_AP_MLME
        case EVENT_DFS_RADAR_DETECTED:
@@ -3521,12 +3804,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 #endif /* CONFIG_AP */
 #ifdef CONFIG_P2P
                        if (stype == WLAN_FC_STYPE_PROBE_REQ &&
-                           data->rx_mgmt.frame_len > 24) {
+                           data->rx_mgmt.frame_len > IEEE80211_HDRLEN) {
                                const u8 *src = mgmt->sa;
-                               const u8 *ie = mgmt->u.probe_req.variable;
-                               size_t ie_len = data->rx_mgmt.frame_len -
-                                       (mgmt->u.probe_req.variable -
-                                        data->rx_mgmt.frame);
+                               const u8 *ie;
+                               size_t ie_len;
+
+                               ie = data->rx_mgmt.frame + IEEE80211_HDRLEN;
+                               ie_len = data->rx_mgmt.frame_len -
+                                       IEEE80211_HDRLEN;
                                wpas_p2p_probe_req_rx(
                                        wpa_s, src, mgmt->da,
                                        mgmt->bssid, ie, ie_len,
@@ -3566,11 +3851,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                }
 
                if (stype == WLAN_FC_STYPE_PROBE_REQ &&
-                   data->rx_mgmt.frame_len > 24) {
-                       const u8 *ie = mgmt->u.probe_req.variable;
-                       size_t ie_len = data->rx_mgmt.frame_len -
-                               (mgmt->u.probe_req.variable -
-                                data->rx_mgmt.frame);
+                   data->rx_mgmt.frame_len > IEEE80211_HDRLEN) {
+                       const u8 *ie;
+                       size_t ie_len;
+
+                       ie = data->rx_mgmt.frame + IEEE80211_HDRLEN;
+                       ie_len = data->rx_mgmt.frame_len - IEEE80211_HDRLEN;
 
                        wpas_notify_preq(wpa_s, mgmt->sa, mgmt->da,
                                         mgmt->bssid, ie, ie_len,
@@ -3713,6 +3999,7 @@ 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);
                radio_remove_works(wpa_s, NULL, 0);
 
                wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
@@ -3771,15 +4058,28 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                         data->driver_gtk_rekey.replay_ctr);
                break;
        case EVENT_SCHED_SCAN_STOPPED:
-               wpa_s->pno = 0;
                wpa_s->sched_scanning = 0;
-               resched = wpa_s->scanning;
+               resched = wpa_s->scanning && wpas_scan_scheduled(wpa_s);
                wpa_supplicant_notify_scanning(wpa_s, 0);
 
                if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
                        break;
 
                /*
+                * If the driver stopped scanning without being requested to,
+                * request a new scan to continue scanning for networks.
+                */
+               if (!wpa_s->sched_scan_stop_req &&
+                   wpa_s->wpa_state == WPA_SCANNING) {
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "Restart scanning after unexpected sched_scan stop event");
+                       wpa_supplicant_req_scan(wpa_s, 1, 0);
+                       break;
+               }
+
+               wpa_s->sched_scan_stop_req = 0;
+
+               /*
                 * Start a new sched scan to continue searching for more SSIDs
                 * either if timed out or PNO schedule scan is pending.
                 */
@@ -3820,8 +4120,72 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                     data->mesh_peer.ie_len);
 #endif /* CONFIG_MESH */
                break;
+       case EVENT_SURVEY:
+#ifdef CONFIG_AP
+               if (!wpa_s->ap_iface)
+                       break;
+               hostapd_event_get_survey(wpa_s->ap_iface,
+                                        &data->survey_results);
+#endif /* CONFIG_AP */
+               break;
+       case EVENT_ACS_CHANNEL_SELECTED:
+#ifdef CONFIG_ACS
+               if (!wpa_s->ap_iface)
+                       break;
+               hostapd_acs_channel_selected(wpa_s->ap_iface->bss[0],
+                                            &data->acs_selected_channels);
+#endif /* CONFIG_ACS */
+               break;
+       case EVENT_P2P_LO_STOP:
+#ifdef CONFIG_P2P
+               wpa_s->p2p_lo_started = 0;
+               wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_LISTEN_OFFLOAD_STOP
+                       P2P_LISTEN_OFFLOAD_STOP_REASON "reason=%d",
+                       data->p2p_lo_stop.reason_code);
+#endif /* CONFIG_P2P */
+               break;
        default:
                wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
                break;
        }
 }
+
+
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+                                union wpa_event_data *data)
+{
+       struct wpa_supplicant *wpa_s;
+
+       if (event != EVENT_INTERFACE_STATUS)
+               return;
+
+       wpa_s = wpa_supplicant_get_iface(ctx, data->interface_status.ifname);
+       if (wpa_s && wpa_s->driver->get_ifindex) {
+               unsigned int ifindex;
+
+               ifindex = wpa_s->driver->get_ifindex(wpa_s->drv_priv);
+               if (ifindex != data->interface_status.ifindex) {
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "interface status ifindex %d mismatch (%d)",
+                               ifindex, data->interface_status.ifindex);
+                       return;
+               }
+       }
+#ifdef CONFIG_MATCH_IFACE
+       else if (data->interface_status.ievent == EVENT_INTERFACE_ADDED) {
+               struct wpa_interface *wpa_i;
+
+               wpa_i = wpa_supplicant_match_iface(
+                       ctx, data->interface_status.ifname);
+               if (!wpa_i)
+                       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 */
+
+       if (wpa_s)
+               wpa_supplicant_event(wpa_s, event, data);
+}
index 10ecce7..691de03 100644 (file)
@@ -17,6 +17,7 @@
 #include "common/wpa_ctrl.h"
 #include "rsn_supp/wpa.h"
 #include "wpa_supplicant_i.h"
+#include "config.h"
 #include "driver_i.h"
 #include "offchannel.h"
 #include "gas_query.h"
@@ -25,6 +26,9 @@
 /** GAS query timeout in seconds */
 #define GAS_QUERY_TIMEOUT_PERIOD 2
 
+/* GAS query wait-time / duration in ms */
+#define GAS_QUERY_WAIT_TIME_INITIAL 1000
+#define GAS_QUERY_WAIT_TIME_COMEBACK 150
 
 /**
  * struct gas_query_pending - Pending GAS query
@@ -37,6 +41,7 @@ struct gas_query_pending {
        u8 next_frag_id;
        unsigned int wait_comeback:1;
        unsigned int offchannel_tx_started:1;
+       unsigned int retry:1;
        int freq;
        u16 status_code;
        struct wpabuf *req;
@@ -63,6 +68,10 @@ struct gas_query {
 
 static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx);
 static void gas_query_timeout(void *eloop_data, void *user_ctx);
+static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx);
+static void gas_query_tx_initial_req(struct gas_query *gas,
+                                    struct gas_query_pending *query);
+static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst);
 
 
 static int ms_from_time(struct os_reltime *last)
@@ -108,8 +117,6 @@ static const char * gas_result_txt(enum gas_query_result result)
                return "PEER_ERROR";
        case GAS_QUERY_INTERNAL_ERROR:
                return "INTERNAL_ERROR";
-       case GAS_QUERY_CANCELLED:
-               return "CANCELLED";
        case GAS_QUERY_DELETED_AT_DEINIT:
                return "DELETED_AT_DEINIT";
        }
@@ -151,6 +158,7 @@ static void gas_query_done(struct gas_query *gas,
                offchannel_send_action_done(gas->wpa_s);
        eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
        eloop_cancel_timeout(gas_query_timeout, gas, query);
+       eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query);
        dl_list_del(&query->list);
        query->cb(query->ctx, query->addr, query->dialog_token, result,
                  query->adv_proto, query->resp, query->status_code);
@@ -235,6 +243,13 @@ static void gas_query_tx_status(struct wpa_supplicant *wpa_s,
                eloop_cancel_timeout(gas_query_timeout, gas, query);
                eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
                                       gas_query_timeout, gas, query);
+               if (query->wait_comeback && !query->retry) {
+                       eloop_cancel_timeout(gas_query_rx_comeback_timeout,
+                                            gas, query);
+                       eloop_register_timeout(
+                               0, (GAS_QUERY_WAIT_TIME_COMEBACK + 10) * 1000,
+                               gas_query_rx_comeback_timeout, gas, query);
+               }
        }
        if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
                eloop_cancel_timeout(gas_query_timeout, gas, query);
@@ -254,10 +269,13 @@ static int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
 
 
 static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
-                       struct wpabuf *req)
+                       struct wpabuf *req, unsigned int wait_time)
 {
-       unsigned int wait_time;
        int res, prot = pmf_in_use(gas->wpa_s, query->addr);
+       const u8 *bssid;
+       const u8 wildcard_bssid[ETH_ALEN] = {
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+       };
 
        wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
                   "freq=%d prot=%d", MAC2STR(query->addr),
@@ -267,12 +285,18 @@ static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
                *categ = WLAN_ACTION_PROTECTED_DUAL;
        }
        os_get_reltime(&query->last_oper);
-       wait_time = 1000;
        if (gas->wpa_s->max_remain_on_chan &&
            wait_time > gas->wpa_s->max_remain_on_chan)
                wait_time = gas->wpa_s->max_remain_on_chan;
+       if (!gas->wpa_s->conf->gas_address3 ||
+           (gas->wpa_s->current_ssid &&
+            gas->wpa_s->wpa_state >= WPA_ASSOCIATED &&
+            os_memcmp(query->addr, gas->wpa_s->bssid, ETH_ALEN) == 0))
+               bssid = query->addr;
+       else
+               bssid = wildcard_bssid;
        res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
-                                    gas->wpa_s->own_addr, query->addr,
+                                    gas->wpa_s->own_addr, bssid,
                                     wpabuf_head(req), wpabuf_len(req),
                                     wait_time, gas_query_tx_status, 0);
        if (res == 0)
@@ -285,6 +309,7 @@ static void gas_query_tx_comeback_req(struct gas_query *gas,
                                      struct gas_query_pending *query)
 {
        struct wpabuf *req;
+       unsigned int wait_time;
 
        req = gas_build_comeback_req(query->dialog_token);
        if (req == NULL) {
@@ -292,7 +317,10 @@ static void gas_query_tx_comeback_req(struct gas_query *gas,
                return;
        }
 
-       if (gas_query_tx(gas, query, req) < 0) {
+       wait_time = (query->retry || !query->offchannel_tx_started) ?
+               GAS_QUERY_WAIT_TIME_INITIAL : GAS_QUERY_WAIT_TIME_COMEBACK;
+
+       if (gas_query_tx(gas, query, req, wait_time) < 0) {
                wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
                           MACSTR, MAC2STR(query->addr));
                gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
@@ -302,6 +330,35 @@ static void gas_query_tx_comeback_req(struct gas_query *gas,
 }
 
 
+static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx)
+{
+       struct gas_query *gas = eloop_data;
+       struct gas_query_pending *query = user_ctx;
+       int dialog_token;
+
+       wpa_printf(MSG_DEBUG,
+                  "GAS: No response to comeback request received (retry=%u)",
+                  query->retry);
+       if (gas->current != query || query->retry)
+               return;
+       dialog_token = gas_query_new_dialog_token(gas, query->addr);
+       if (dialog_token < 0)
+               return;
+       wpa_printf(MSG_DEBUG,
+                  "GAS: Retry GAS query due to comeback response timeout");
+       query->retry = 1;
+       query->dialog_token = dialog_token;
+       *(wpabuf_mhead_u8(query->req) + 2) = dialog_token;
+       query->wait_comeback = 0;
+       query->next_frag_id = 0;
+       wpabuf_free(query->adv_proto);
+       query->adv_proto = NULL;
+       eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
+       eloop_cancel_timeout(gas_query_timeout, gas, query);
+       gas_query_tx_initial_req(gas, query);
+}
+
+
 static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx)
 {
        struct gas_query *gas = eloop_data;
@@ -319,6 +376,11 @@ static void gas_query_tx_comeback_req_delay(struct gas_query *gas,
 {
        unsigned int secs, usecs;
 
+       if (comeback_delay > 1 && query->offchannel_tx_started) {
+               offchannel_send_action_done(gas->wpa_s);
+               query->offchannel_tx_started = 0;
+       }
+
        secs = (comeback_delay * 1024) / 1000000;
        usecs = comeback_delay * 1024 - secs * 1000000;
        wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR
@@ -371,6 +433,7 @@ static void gas_query_rx_comeback(struct gas_query *gas,
                   "comeback_delay=%u)",
                   MAC2STR(query->addr), query->dialog_token, frag_id,
                   more_frags, comeback_delay);
+       eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query);
 
        if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) ||
            os_memcmp(adv_proto, wpabuf_head(query->adv_proto),
@@ -447,8 +510,16 @@ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
        if (gas == NULL || len < 4)
                return -1;
 
+       pos = data;
+       action = *pos++;
+       dialog_token = *pos++;
+
+       if (action != WLAN_PA_GAS_INITIAL_RESP &&
+           action != WLAN_PA_GAS_COMEBACK_RESP)
+               return -1; /* Not a GAS response */
+
        prot = categ == WLAN_ACTION_PROTECTED_DUAL;
-       pmf = pmf_in_use(gas->wpa_s, bssid);
+       pmf = pmf_in_use(gas->wpa_s, sa);
        if (prot && !pmf) {
                wpa_printf(MSG_DEBUG, "GAS: Drop unexpected protected GAS frame when PMF is disabled");
                return 0;
@@ -458,14 +529,6 @@ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
                return 0;
        }
 
-       pos = data;
-       action = *pos++;
-       dialog_token = *pos++;
-
-       if (action != WLAN_PA_GAS_INITIAL_RESP &&
-           action != WLAN_PA_GAS_COMEBACK_RESP)
-               return -1; /* Not a GAS response */
-
        query = gas_query_get_pending(gas, sa, dialog_token);
        if (query == NULL) {
                wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR
@@ -620,11 +683,18 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
        }
 
        gas->work = work;
+       gas_query_tx_initial_req(gas, query);
+}
 
-       if (gas_query_tx(gas, query, query->req) < 0) {
+
+static void gas_query_tx_initial_req(struct gas_query *gas,
+                                    struct gas_query_pending *query)
+{
+       if (gas_query_tx(gas, query, query->req,
+                        GAS_QUERY_WAIT_TIME_INITIAL) < 0) {
                wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
                           MACSTR, MAC2STR(query->addr));
-               gas_query_free(query, 1);
+               gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
                return;
        }
        gas->current = query;
@@ -633,7 +703,24 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
                   query->dialog_token);
        eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
                               gas_query_timeout, gas, query);
+}
+
+
+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))
+                       break;
+       }
+       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;
 }
 
 
@@ -658,20 +745,13 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
 {
        struct gas_query_pending *query;
        int dialog_token;
-       static int next_start = 0;
 
        if (wpabuf_len(req) < 3)
                return -1;
 
-       for (dialog_token = 0; dialog_token < 256; dialog_token++) {
-               if (gas_query_dialog_token_available(
-                           gas, dst, (next_start + dialog_token) % 256))
-                       break;
-       }
-       if (dialog_token == 256)
-               return -1; /* Too many pending queries */
-       dialog_token = (next_start + dialog_token) % 256;
-       next_start = (dialog_token + 1) % 256;
+       dialog_token = gas_query_new_dialog_token(gas, dst);
+       if (dialog_token < 0)
+               return -1;
 
        query = os_zalloc(sizeof(*query));
        if (query == NULL)
@@ -694,26 +774,10 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
 
        if (radio_add_work(gas->wpa_s, freq, "gas-query", 0, gas_query_start_cb,
                           query) < 0) {
+               query->req = NULL; /* caller will free this in error case */
                gas_query_free(query, 1);
                return -1;
        }
 
        return dialog_token;
 }
-
-
-/**
- * gas_query_cancel - Cancel a pending GAS query
- * @gas: GAS query data from gas_query_init()
- * @dst: Destination MAC address for the query
- * @dialog_token: Dialog token from gas_query_req()
- */
-void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token)
-{
-       struct gas_query_pending *query;
-
-       query = gas_query_get_pending(gas, dst, dialog_token);
-       if (query)
-               gas_query_done(gas, query, GAS_QUERY_CANCELLED);
-
-}
index ad13490..ef82097 100644 (file)
@@ -29,7 +29,6 @@ enum gas_query_result {
        GAS_QUERY_TIMEOUT,
        GAS_QUERY_PEER_ERROR,
        GAS_QUERY_INTERNAL_ERROR,
-       GAS_QUERY_CANCELLED,
        GAS_QUERY_DELETED_AT_DEINIT
 };
 
@@ -40,7 +39,6 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
                             const struct wpabuf *adv_proto,
                             const struct wpabuf *resp, u16 status_code),
                  void *ctx);
-void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token);
 
 #else /* CONFIG_GAS */
 
index a1afc85..e88f147 100644 (file)
@@ -25,6 +25,7 @@
 #include "gas_query.h"
 #include "interworking.h"
 #include "hs20_supplicant.h"
+#include "base64.h"
 
 
 #define OSU_MAX_ITEMS 10
@@ -60,6 +61,46 @@ struct osu_provider {
 };
 
 
+void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_bss *bss = wpa_s->current_bss;
+       u8 *bssid = wpa_s->bssid;
+       const u8 *ie;
+       const u8 *ext_capa;
+       u32 filter = 0;
+
+       if (!bss || !is_hs20_network(wpa_s, wpa_s->current_ssid, bss)) {
+               wpa_printf(MSG_DEBUG,
+                          "Not configuring frame filtering - BSS " MACSTR
+                          " is not a Hotspot 2.0 network", MAC2STR(bssid));
+               return;
+       }
+
+       ie = wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE);
+
+       /* Check if DGAF disabled bit is zero (5th byte in the IE) */
+       if (!ie || ie[1] < 5)
+               wpa_printf(MSG_DEBUG,
+                          "Not configuring frame filtering - Can't extract DGAF bit");
+       else if (!(ie[6] & HS20_DGAF_DISABLED))
+               filter |= WPA_DATA_FRAME_FILTER_FLAG_GTK;
+
+       ext_capa = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
+       if (!ext_capa || ext_capa[1] < 2) {
+               wpa_printf(MSG_DEBUG,
+                          "Not configuring frame filtering - Can't extract Proxy ARP bit");
+               return;
+       }
+
+       /* Check if Proxy ARP is enabled (2nd byte in the IE) */
+       if (ext_capa[3] & BIT(4))
+               filter |= WPA_DATA_FRAME_FILTER_FLAG_ARP |
+                       WPA_DATA_FRAME_FILTER_FLAG_NA;
+
+       wpa_drv_configure_frame_filters(wpa_s, filter);
+}
+
+
 void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id)
 {
        u8 conf;
@@ -164,8 +205,8 @@ void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
 }
 
 
-struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
-                                   size_t payload_len)
+static struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
+                                          size_t payload_len)
 {
        struct wpabuf *buf;
 
@@ -180,13 +221,14 @@ struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
 
 
 int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
-                      const u8 *payload, size_t payload_len)
+                      const u8 *payload, size_t payload_len, int inmem)
 {
        struct wpabuf *buf;
        int ret = 0;
        int freq;
        struct wpa_bss *bss;
        int res;
+       struct icon_entry *icon_entry;
 
        bss = wpa_bss_get_bssid(wpa_s, dst);
        if (!bss) {
@@ -210,15 +252,127 @@ int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
        if (res < 0) {
                wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
                wpabuf_free(buf);
-               ret = -1;
+               return -1;
        } else
                wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
                           "%u", res);
 
+       if (inmem) {
+               icon_entry = os_zalloc(sizeof(struct icon_entry));
+               if (!icon_entry)
+                       return -1;
+               os_memcpy(icon_entry->bssid, dst, ETH_ALEN);
+               icon_entry->file_name = os_malloc(payload_len + 1);
+               if (!icon_entry->file_name) {
+                       os_free(icon_entry);
+                       return -1;
+               }
+               os_memcpy(icon_entry->file_name, payload, payload_len);
+               icon_entry->file_name[payload_len] = '\0';
+               icon_entry->dialog_token = res;
+
+               dl_list_add(&wpa_s->icon_head, &icon_entry->list);
+       }
+
        return ret;
 }
 
 
+static struct icon_entry * hs20_find_icon(struct wpa_supplicant *wpa_s,
+                                         const u8 *bssid,
+                                         const char *file_name)
+{
+       struct icon_entry *icon;
+
+       dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) {
+               if (os_memcmp(icon->bssid, bssid, ETH_ALEN) == 0 &&
+                   os_strcmp(icon->file_name, file_name) == 0 && icon->image)
+                       return icon;
+       }
+
+       return NULL;
+}
+
+
+int hs20_get_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                 const char *file_name, size_t offset, size_t size,
+                 char *reply, size_t buf_len)
+{
+       struct icon_entry *icon;
+       size_t out_size;
+       unsigned char *b64;
+       size_t b64_size;
+       int reply_size;
+
+       wpa_printf(MSG_DEBUG, "HS20: Get icon " MACSTR " %s @ %u +%u (%u)",
+                  MAC2STR(bssid), file_name, (unsigned int) offset,
+                  (unsigned int) size, (unsigned int) buf_len);
+
+       icon = hs20_find_icon(wpa_s, bssid, file_name);
+       if (!icon || !icon->image || offset >= icon->image_len)
+               return -1;
+       if (size > icon->image_len - offset)
+               size = icon->image_len - offset;
+       out_size = buf_len - 3 /* max base64 padding */;
+       if (size * 4 > out_size * 3)
+               size = out_size * 3 / 4;
+       if (size == 0)
+               return -1;
+
+       b64 = base64_encode(&icon->image[offset], size, &b64_size);
+       if (b64 && buf_len >= b64_size) {
+               os_memcpy(reply, b64, b64_size);
+               reply_size = b64_size;
+       } else {
+               reply_size = -1;
+       }
+       os_free(b64);
+       return reply_size;
+}
+
+
+static void hs20_free_icon_entry(struct icon_entry *icon)
+{
+       wpa_printf(MSG_DEBUG, "HS20: Free stored icon from " MACSTR
+                  " dialog_token=%u file_name=%s image_len=%u",
+                  MAC2STR(icon->bssid), icon->dialog_token,
+                  icon->file_name ? icon->file_name : "N/A",
+                  (unsigned int) icon->image_len);
+       os_free(icon->file_name);
+       os_free(icon->image);
+       os_free(icon);
+}
+
+
+int hs20_del_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                 const char *file_name)
+{
+       struct icon_entry *icon, *tmp;
+       int count = 0;
+
+       if (!bssid)
+               wpa_printf(MSG_DEBUG, "HS20: Delete all stored icons");
+       else if (!file_name)
+               wpa_printf(MSG_DEBUG, "HS20: Delete all stored icons for "
+                          MACSTR, MAC2STR(bssid));
+       else
+               wpa_printf(MSG_DEBUG, "HS20: Delete stored icons for "
+                          MACSTR " file name %s", MAC2STR(bssid), file_name);
+
+       dl_list_for_each_safe(icon, tmp, &wpa_s->icon_head, struct icon_entry,
+                             list) {
+               if ((!bssid || os_memcmp(icon->bssid, bssid, ETH_ALEN) == 0) &&
+                   (!file_name ||
+                    os_strcmp(icon->file_name, file_name) == 0)) {
+                       dl_list_del(&icon->list);
+                       hs20_free_icon_entry(icon);
+                       count++;
+               }
+       }
+       return count == 0 ? -1 : 0;
+}
+
+
 static void hs20_set_osu_access_permission(const char *osu_dir,
                                           const char *fname)
 {
@@ -243,16 +397,53 @@ static void hs20_set_osu_access_permission(const char *osu_dir,
        }
 }
 
+
+static void hs20_remove_duplicate_icons(struct wpa_supplicant *wpa_s,
+                                       struct icon_entry *new_icon)
+{
+       struct icon_entry *icon, *tmp;
+
+       dl_list_for_each_safe(icon, tmp, &wpa_s->icon_head, struct icon_entry,
+                             list) {
+               if (icon == new_icon)
+                       continue;
+               if (os_memcmp(icon->bssid, new_icon->bssid, ETH_ALEN) == 0 &&
+                   os_strcmp(icon->file_name, new_icon->file_name) == 0) {
+                       dl_list_del(&icon->list);
+                       hs20_free_icon_entry(icon);
+               }
+       }
+}
+
+
 static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s,
                                         const u8 *sa, const u8 *pos,
-                                        size_t slen)
+                                        size_t slen, u8 dialog_token)
 {
        char fname[256];
        int png;
        FILE *f;
        u16 data_len;
+       struct icon_entry *icon;
+
+       dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) {
+               if (icon->dialog_token == dialog_token && !icon->image &&
+                   os_memcmp(icon->bssid, sa, ETH_ALEN) == 0) {
+                       icon->image = os_malloc(slen);
+                       if (!icon->image)
+                               return -1;
+                       os_memcpy(icon->image, pos, slen);
+                       icon->image_len = slen;
+                       hs20_remove_duplicate_icons(wpa_s, icon);
+                       wpa_msg(wpa_s, MSG_INFO,
+                               RX_HS20_ICON MACSTR " %s %u",
+                               MAC2STR(sa), icon->file_name,
+                               (unsigned int) icon->image_len);
+                       return 0;
+               }
+       }
 
-       wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " Icon Binary File",
+       wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Icon Binary File",
                MAC2STR(sa));
 
        if (slen < 4) {
@@ -315,7 +506,7 @@ static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s,
        }
        fclose(f);
 
-       wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP-ICON %s", fname);
+       wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP_ICON "%s", fname);
        return 0;
 }
 
@@ -358,7 +549,7 @@ static void hs20_osu_icon_fetch_result(struct wpa_supplicant *wpa_s, int res)
 
 void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                                  struct wpa_bss *bss, const u8 *sa,
-                                 const u8 *data, size_t slen)
+                                 const u8 *data, size_t slen, u8 dialog_token)
 {
        const u8 *pos = data;
        u8 subtype;
@@ -379,7 +570,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
 
        switch (subtype) {
        case HS20_STYPE_CAPABILITY_LIST:
-               wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
                        " HS Capability List", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen);
                if (anqp) {
@@ -389,7 +580,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                }
                break;
        case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
-               wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
                        " Operator Friendly Name", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen);
                if (anqp) {
@@ -405,7 +596,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                                "Metrics value from " MACSTR, MAC2STR(sa));
                        break;
                }
-               wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
                        " WAN Metrics %02x:%u:%u:%u:%u:%u", MAC2STR(sa),
                        pos[0], WPA_GET_LE32(pos + 1), WPA_GET_LE32(pos + 5),
                        pos[9], pos[10], WPA_GET_LE16(pos + 11));
@@ -415,7 +606,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                }
                break;
        case HS20_STYPE_CONNECTION_CAPABILITY:
-               wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
                        " Connection Capability", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen);
                if (anqp) {
@@ -425,7 +616,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                }
                break;
        case HS20_STYPE_OPERATING_CLASS:
-               wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
                        " Operating Class", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen);
                if (anqp) {
@@ -435,7 +626,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                }
                break;
        case HS20_STYPE_OSU_PROVIDERS_LIST:
-               wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
                        " OSU Providers list", MAC2STR(sa));
                wpa_s->num_prov_found++;
                if (anqp) {
@@ -445,7 +636,8 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                }
                break;
        case HS20_STYPE_ICON_BINARY_FILE:
-               ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen);
+               ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen,
+                                                   dialog_token);
                if (wpa_s->fetch_osu_icon_in_progress) {
                        hs20_osu_icon_fetch_result(wpa_s, ret);
                        eloop_cancel_timeout(hs20_continue_icon_fetch,
@@ -511,7 +703,10 @@ static void hs20_osu_fetch_done(struct wpa_supplicant *wpa_s)
                 wpa_s->conf->osu_dir);
        f = fopen(fname, "w");
        if (f == NULL) {
+               wpa_msg(wpa_s, MSG_INFO,
+                       "Could not write OSU provider information");
                hs20_free_osu_prov(wpa_s);
+               wpa_s->fetch_anqp_in_progress = 0;
                return;
        }
 
@@ -579,7 +774,8 @@ void hs20_next_osu_icon(struct wpa_supplicant *wpa_s)
                        if (hs20_anqp_send_req(wpa_s, osu->bssid,
                                               BIT(HS20_STYPE_ICON_REQUEST),
                                               (u8 *) icon->filename,
-                                              os_strlen(icon->filename)) < 0) {
+                                              os_strlen(icon->filename),
+                                              0) < 0) {
                                icon->failed = 1;
                                continue;
                        }
@@ -617,7 +813,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        prov->osu_ssid_len = osu_ssid_len;
 
        /* OSU Friendly Name Length */
-       if (pos + 2 > end) {
+       if (end - pos < 2) {
                wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
                           "Friendly Name Length");
                return;
@@ -633,9 +829,9 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        pos += len2;
 
        /* OSU Friendly Name Duples */
-       while (pos2 + 4 <= pos && prov->friendly_name_count < OSU_MAX_ITEMS) {
+       while (pos - pos2 >= 4 && prov->friendly_name_count < OSU_MAX_ITEMS) {
                struct osu_lang_string *f;
-               if (pos2 + 1 + pos2[0] > pos || pos2[0] < 3) {
+               if (1 + pos2[0] > pos - pos2 || pos2[0] < 3) {
                        wpa_printf(MSG_DEBUG, "Invalid OSU Friendly Name");
                        break;
                }
@@ -646,7 +842,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        }
 
        /* OSU Server URI */
-       if (pos + 1 > end) {
+       if (end - pos < 1) {
                wpa_printf(MSG_DEBUG,
                           "HS 2.0: Not enough room for OSU Server URI length");
                return;
@@ -661,7 +857,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        pos += uri_len;
 
        /* OSU Method list */
-       if (pos + 1 > end) {
+       if (end - pos < 1) {
                wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method "
                           "list length");
                return;
@@ -681,7 +877,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        }
 
        /* Icons Available Length */
-       if (pos + 2 > end) {
+       if (end - pos < 2) {
                wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons "
                           "Available Length");
                return;
@@ -701,7 +897,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                struct osu_icon *icon = &prov->icon[prov->icon_count];
                u8 flen;
 
-               if (pos2 + 2 + 2 + 3 + 1 + 1 > pos) {
+               if (2 + 2 + 3 + 1 + 1 > pos - pos2) {
                        wpa_printf(MSG_DEBUG, "HS 2.0: Invalid Icon Metadata");
                        break;
                }
@@ -713,46 +909,46 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                os_memcpy(icon->lang, pos2, 3);
                pos2 += 3;
 
-               flen = pos2[0];
-               if (flen > pos - pos2 - 1) {
+               flen = *pos2++;
+               if (flen > pos - pos2) {
                        wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon Type");
                        break;
                }
-               os_memcpy(icon->icon_type, pos2 + 1, flen);
-               pos2 += 1 + flen;
+               os_memcpy(icon->icon_type, pos2, flen);
+               pos2 += flen;
 
-               if (pos2 + 1 > pos) {
+               if (pos - pos2 < 1) {
                        wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
                                   "Filename length");
                        break;
                }
-               flen = pos2[0];
-               if (flen > pos - pos2 - 1) {
+               flen = *pos2++;
+               if (flen > pos - pos2) {
                        wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
                                   "Filename");
                        break;
                }
-               os_memcpy(icon->filename, pos2 + 1, flen);
-               pos2 += 1 + flen;
+               os_memcpy(icon->filename, pos2, flen);
+               pos2 += flen;
 
                prov->icon_count++;
        }
 
        /* OSU_NAI */
-       if (pos + 1 > end) {
+       if (end - pos < 1) {
                wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI");
                return;
        }
-       osu_nai_len = pos[0];
-       if (osu_nai_len > end - pos - 1) {
+       osu_nai_len = *pos++;
+       if (osu_nai_len > end - pos) {
                wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI");
                return;
        }
-       os_memcpy(prov->osu_nai, pos + 1, osu_nai_len);
-       pos += 1 + osu_nai_len;
+       os_memcpy(prov->osu_nai, pos, osu_nai_len);
+       pos += osu_nai_len;
 
        /* OSU Service Description Length */
-       if (pos + 2 > end) {
+       if (end - pos < 2) {
                wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
                           "Service Description Length");
                return;
@@ -768,20 +964,20 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        pos += len2;
 
        /* OSU Service Description Duples */
-       while (pos2 + 4 <= pos && prov->serv_desc_count < OSU_MAX_ITEMS) {
+       while (pos - pos2 >= 4 && prov->serv_desc_count < OSU_MAX_ITEMS) {
                struct osu_lang_string *f;
                u8 descr_len;
 
-               descr_len = pos2[0];
-               if (descr_len > pos - pos2 - 1 || descr_len < 3) {
+               descr_len = *pos2++;
+               if (descr_len > pos - pos2 || descr_len < 3) {
                        wpa_printf(MSG_DEBUG, "Invalid OSU Service "
                                   "Description");
                        break;
                }
                f = &prov->serv_desc[prov->serv_desc_count++];
-               os_memcpy(f->lang, pos2 + 1, 3);
-               os_memcpy(f->text, pos2 + 1 + 3, descr_len - 3);
-               pos2 += 1 + descr_len;
+               os_memcpy(f->lang, pos2, 3);
+               os_memcpy(f->text, pos2 + 3, descr_len - 3);
+               pos2 += descr_len;
        }
 
        wpa_printf(MSG_DEBUG, "HS 2.0: Added OSU Provider through " MACSTR,
@@ -816,9 +1012,9 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
                end = pos + wpabuf_len(prov_anqp);
 
                /* OSU SSID */
-               if (pos + 1 > end)
+               if (end - pos < 1)
                        continue;
-               if (pos + 1 + pos[0] > end) {
+               if (1 + pos[0] > end - pos) {
                        wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for "
                                   "OSU SSID");
                        continue;
@@ -832,7 +1028,7 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
                osu_ssid = pos;
                pos += osu_ssid_len;
 
-               if (pos + 1 > end) {
+               if (end - pos < 1) {
                        wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for "
                                   "Number of OSU Providers");
                        continue;
@@ -842,7 +1038,7 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
                           num_providers);
 
                /* OSU Providers */
-               while (pos + 2 < end && num_providers > 0) {
+               while (end - pos > 2 && num_providers > 0) {
                        num_providers--;
                        len = WPA_GET_LE16(pos);
                        pos += 2;
@@ -882,7 +1078,7 @@ static void hs20_osu_scan_res_handler(struct wpa_supplicant *wpa_s,
 }
 
 
-int hs20_fetch_osu(struct wpa_supplicant *wpa_s)
+int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan)
 {
        if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
                wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
@@ -913,7 +1109,16 @@ int hs20_fetch_osu(struct wpa_supplicant *wpa_s)
        wpa_msg(wpa_s, MSG_INFO, "Starting OSU provisioning information fetch");
        wpa_s->num_osu_scans = 0;
        wpa_s->num_prov_found = 0;
-       hs20_start_osu_scan(wpa_s);
+       if (skip_scan) {
+               wpa_s->network_select = 0;
+               wpa_s->fetch_all_anqp = 1;
+               wpa_s->fetch_osu_info = 1;
+               wpa_s->fetch_osu_icon_in_progress = 0;
+
+               interworking_start_fetch_anqp(wpa_s);
+       } else {
+               hs20_start_osu_scan(wpa_s);
+       }
 
        return 0;
 }
@@ -1002,8 +1207,16 @@ void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code,
 }
 
 
+void hs20_init(struct wpa_supplicant *wpa_s)
+{
+       dl_list_init(&wpa_s->icon_head);
+}
+
+
 void hs20_deinit(struct wpa_supplicant *wpa_s)
 {
        eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL);
        hs20_free_osu_prov(wpa_s);
+       if (wpa_s->icon_head.next)
+               hs20_del_icon(wpa_s, NULL, NULL);
 }
index 85b5120..0dd559f 100644 (file)
@@ -8,17 +8,16 @@
 #ifndef HS20_SUPPLICANT_H
 #define HS20_SUPPLICANT_H
 
+void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s);
 void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id);
 
 int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
-                      const u8 *payload, size_t payload_len);
-struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
-                                   size_t payload_len);
+                      const u8 *payload, size_t payload_len, int inmem);
 void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
                       struct wpabuf *buf);
 void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                                  struct wpa_bss *bss, const u8 *sa,
-                                 const u8 *data, size_t slen);
+                                 const u8 *data, size_t slen, u8 dialog_token);
 int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
                    struct wpa_bss *bss);
 int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
@@ -32,10 +31,16 @@ void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code,
 void hs20_free_osu_prov(struct wpa_supplicant *wpa_s);
 void hs20_next_osu_icon(struct wpa_supplicant *wpa_s);
 void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s);
-int hs20_fetch_osu(struct wpa_supplicant *wpa_s);
+int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan);
 void hs20_cancel_fetch_osu(struct wpa_supplicant *wpa_s);
 void hs20_icon_fetch_failed(struct wpa_supplicant *wpa_s);
 void hs20_start_osu_scan(struct wpa_supplicant *wpa_s);
+void hs20_init(struct wpa_supplicant *wpa_s);
 void hs20_deinit(struct wpa_supplicant *wpa_s);
+int hs20_get_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                 const char *file_name, size_t offset, size_t size,
+                 char *reply, size_t buf_len);
+int hs20_del_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                 const char *file_name);
 
 #endif /* HS20_SUPPLICANT_H */
index d9d0ae7..53d7d57 100644 (file)
@@ -221,6 +221,7 @@ static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
        peer->supp = wpa_sm_init(ctx);
        if (peer->supp == NULL) {
                wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
+               os_free(ctx);
                return -1;
        }
 
@@ -230,7 +231,7 @@ static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
        wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP);
        wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
        wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK);
-       wpa_sm_set_pmk(peer->supp, psk, PMK_LEN, NULL);
+       wpa_sm_set_pmk(peer->supp, psk, PMK_LEN, NULL, NULL);
 
        peer->supp_ie_len = sizeof(peer->supp_ie);
        if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie,
@@ -404,7 +405,7 @@ static void auth_set_eapol(void *ctx, const u8 *addr,
 
 
 static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
-                                   const u8 *own_addr)
+                                   const u8 *own_addr, struct wpa_ssid *ssid)
 {
        struct wpa_auth_config conf;
        struct wpa_auth_callbacks cb;
@@ -418,7 +419,7 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
        conf.rsn_pairwise = WPA_CIPHER_CCMP;
        conf.wpa_group = WPA_CIPHER_CCMP;
        conf.eapol_version = 2;
-       conf.wpa_group_rekey = 600;
+       conf.wpa_group_rekey = ssid->group_rekey ? ssid->group_rekey : 600;
 
        os_memset(&cb, 0, sizeof(cb));
        cb.ctx = ibss_rsn;
@@ -665,7 +666,8 @@ void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac)
 }
 
 
-struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s)
+struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s,
+                               struct wpa_ssid *ssid)
 {
        struct ibss_rsn *ibss_rsn;
 
@@ -674,7 +676,7 @@ struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s)
                return NULL;
        ibss_rsn->wpa_s = wpa_s;
 
-       if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr) < 0) {
+       if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr, ssid) < 0) {
                ibss_rsn_deinit(ibss_rsn);
                return NULL;
        }
index 67fae2d..626c543 100644 (file)
@@ -51,7 +51,8 @@ struct ibss_rsn {
 };
 
 
-struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s);
+struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s,
+                               struct wpa_ssid *ssid);
 void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn);
 int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr);
 void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac);
index fd47c17..1fb40c7 100644 (file)
@@ -362,13 +362,13 @@ static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos,
        u8 elen, auth_count, a;
        const u8 *e_end;
 
-       if (pos + 3 > end) {
+       if (end - pos < 3) {
                wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields");
                return NULL;
        }
 
        elen = *pos++;
-       if (pos + elen > end || elen < 2) {
+       if (elen > end - pos || elen < 2) {
                wpa_printf(MSG_DEBUG, "No room for EAP Method subfield");
                return NULL;
        }
@@ -381,14 +381,19 @@ static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos,
        for (a = 0; a < auth_count; a++) {
                u8 id, len;
 
-               if (pos + 2 > end || pos + 2 + pos[1] > end) {
-                       wpa_printf(MSG_DEBUG, "No room for Authentication "
-                                  "Parameter subfield");
+               if (end - pos < 2) {
+                       wpa_printf(MSG_DEBUG,
+                                  "No room for Authentication Parameter subfield header");
                        return NULL;
                }
 
                id = *pos++;
                len = *pos++;
+               if (len > end - pos) {
+                       wpa_printf(MSG_DEBUG,
+                                  "No room for Authentication Parameter subfield");
+                       return NULL;
+               }
 
                switch (id) {
                case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH:
@@ -463,7 +468,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
 
        len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */
        pos += 2;
-       if (pos + len > end || len < 3) {
+       if (len > end - pos || len < 3) {
                wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
                           "(len=%u; left=%u)",
                           len, (unsigned int) (end - pos));
@@ -473,7 +478,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
 
        r->encoding = *pos++;
        realm_len = *pos++;
-       if (pos + realm_len > f_end) {
+       if (realm_len > f_end - pos) {
                wpa_printf(MSG_DEBUG, "No room for NAI Realm "
                           "(len=%u; left=%u)",
                           realm_len, (unsigned int) (f_end - pos));
@@ -485,13 +490,13 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
                return NULL;
        pos += realm_len;
 
-       if (pos + 1 > f_end) {
+       if (f_end - pos < 1) {
                wpa_printf(MSG_DEBUG, "No room for EAP Method Count");
                return NULL;
        }
        r->eap_count = *pos++;
        wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count);
-       if (pos + r->eap_count * 3 > f_end) {
+       if (r->eap_count * 3 > f_end - pos) {
                wpa_printf(MSG_DEBUG, "No room for EAP Methods");
                return NULL;
        }
@@ -746,7 +751,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
                return 0;
        pos = wpabuf_head_u8(anqp);
        end = pos + wpabuf_len(anqp);
-       if (pos + 2 > end)
+       if (end - pos < 2)
                return 0;
        if (*pos != 0) {
                wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos);
@@ -754,7 +759,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
        }
        pos++;
        udhl = *pos++;
-       if (pos + udhl > end) {
+       if (udhl > end - pos) {
                wpa_printf(MSG_DEBUG, "Invalid UDHL");
                return 0;
        }
@@ -764,12 +769,12 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
                   plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2],
                   imsi, mnc_len);
 
-       while (pos + 2 <= end) {
+       while (end - pos >= 2) {
                u8 iei, len;
                const u8 *l_end;
                iei = *pos++;
                len = *pos++ & 0x7f;
-               if (pos + len > end)
+               if (len > end - pos)
                        break;
                l_end = pos + len;
 
@@ -780,7 +785,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
                                    pos, len);
                        num = *pos++;
                        for (i = 0; i < num; i++) {
-                               if (pos + 3 > l_end)
+                               if (l_end - pos < 3)
                                        break;
                                if (os_memcmp(pos, plmn, 3) == 0 ||
                                    os_memcmp(pos, plmn2, 3) == 0)
@@ -945,11 +950,9 @@ static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
        if (!key_mgmt)
                key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
                        "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP";
-       if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0)
-               return -1;
-       if (wpa_config_set(ssid, "proto", "RSN", 0) < 0)
-               return -1;
-       if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
+       if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0 ||
+           wpa_config_set(ssid, "proto", "RSN", 0) < 0 ||
+           wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
                return -1;
        return 0;
 }
@@ -1082,12 +1085,12 @@ static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id,
         * OI #1, [OI #2], [OI #3]
         */
 
-       if (pos + 2 > end)
+       if (end - pos < 2)
                return 0;
 
        pos++; /* skip Number of ANQP OIs */
        lens = *pos++;
-       if (pos + (lens & 0x0f) + (lens >> 4) > end)
+       if ((lens & 0x0f) + (lens >> 4) > end - pos)
                return 0;
 
        if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
@@ -1121,7 +1124,7 @@ static int roaming_consortium_anqp_match(const struct wpabuf *anqp,
        /* Set of <OI Length, OI> duples */
        while (pos < end) {
                len = *pos++;
-               if (pos + len > end)
+               if (len > end - pos)
                        break;
                if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
                        return 1;
@@ -1182,6 +1185,7 @@ static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss)
 static int cred_below_min_backhaul(struct wpa_supplicant *wpa_s,
                                   struct wpa_cred *cred, struct wpa_bss *bss)
 {
+#ifdef CONFIG_HS20
        int res;
        unsigned int dl_bandwidth, ul_bandwidth;
        const u8 *wan;
@@ -1233,6 +1237,7 @@ static int cred_below_min_backhaul(struct wpa_supplicant *wpa_s,
                if (cred->min_ul_bandwidth_roaming > ul_bandwidth)
                        return 1;
        }
+#endif /* CONFIG_HS20 */
 
        return 0;
 }
@@ -1260,9 +1265,11 @@ static int cred_over_max_bss_load(struct wpa_supplicant *wpa_s,
 }
 
 
+#ifdef CONFIG_HS20
+
 static int has_proto_match(const u8 *pos, const u8 *end, u8 proto)
 {
-       while (pos + 4 <= end) {
+       while (end - pos >= 4) {
                if (pos[0] == proto && pos[3] == 1 /* Open */)
                        return 1;
                pos += 4;
@@ -1275,7 +1282,7 @@ static int has_proto_match(const u8 *pos, const u8 *end, u8 proto)
 static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto,
                                u16 port)
 {
-       while (pos + 4 <= end) {
+       while (end - pos >= 4) {
                if (pos[0] == proto && WPA_GET_LE16(&pos[1]) == port &&
                    pos[3] == 1 /* Open */)
                        return 1;
@@ -1285,10 +1292,13 @@ static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto,
        return 0;
 }
 
+#endif /* CONFIG_HS20 */
+
 
 static int cred_conn_capab_missing(struct wpa_supplicant *wpa_s,
                                   struct wpa_cred *cred, struct wpa_bss *bss)
 {
+#ifdef CONFIG_HS20
        int res;
        const u8 *capab, *end;
        unsigned int i, j;
@@ -1325,6 +1335,7 @@ static int cred_conn_capab_missing(struct wpa_supplicant *wpa_s,
                        }
                }
        }
+#endif /* CONFIG_HS20 */
 
        return 0;
 }
@@ -1438,7 +1449,24 @@ static int interworking_set_eap_params(struct wpa_ssid *ssid,
                os_free(anon);
        }
 
-       if (cred->username && cred->username[0] &&
+       if (!ttls && cred->username && cred->username[0] && cred->realm &&
+           !os_strchr(cred->username, '@')) {
+               char *id;
+               size_t buflen;
+               int res;
+
+               buflen = os_strlen(cred->username) + 1 +
+                       os_strlen(cred->realm) + 1;
+
+               id = os_malloc(buflen);
+               if (!id)
+                       return -1;
+               os_snprintf(id, buflen, "%s@%s", cred->username, cred->realm);
+               res = wpa_config_set_quoted(ssid, "identity", id);
+               os_free(id);
+               if (res < 0)
+                       return -1;
+       } else if (cred->username && cred->username[0] &&
            wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
                return -1;
 
@@ -1560,9 +1588,8 @@ fail:
 }
 
 
-static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
-                                      struct wpa_bss *bss, int allow_excluded,
-                                      int only_add)
+int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+                        int only_add)
 {
        struct wpa_cred *cred, *cred_rc, *cred_3gpp;
        struct wpa_ssid *ssid;
@@ -1570,7 +1597,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
        struct nai_realm_eap *eap = NULL;
        u16 count, i;
        char buf[100];
-       int excluded = 0, *excl = allow_excluded ? &excluded : NULL;
+       int excluded = 0, *excl = &excluded;
        const char *name;
 
        if (wpa_s->conf->cred == NULL || bss == NULL)
@@ -1584,8 +1611,8 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
        }
 
        wpa_printf(MSG_DEBUG, "Interworking: Considering BSS " MACSTR
-                  " for connection (allow_excluded=%d)",
-                  MAC2STR(bss->bssid), allow_excluded);
+                  " for connection",
+                  MAC2STR(bss->bssid));
 
        if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
                /*
@@ -1603,7 +1630,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
                wpa_msg(wpa_s, MSG_DEBUG,
                        "Interworking: Highest roaming consortium matching credential priority %d sp_priority %d",
                        cred_rc->priority, cred_rc->sp_priority);
-               if (allow_excluded && excl && !(*excl))
+               if (excl && !(*excl))
                        excl = NULL;
        }
 
@@ -1612,7 +1639,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
                wpa_msg(wpa_s, MSG_DEBUG,
                        "Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d",
                        cred->priority, cred->sp_priority);
-               if (allow_excluded && excl && !(*excl))
+               if (excl && !(*excl))
                        excl = NULL;
        }
 
@@ -1622,7 +1649,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
                wpa_msg(wpa_s, MSG_DEBUG,
                        "Interworking: Highest 3GPP matching credential priority %d sp_priority %d",
                        cred_3gpp->priority, cred_3gpp->sp_priority);
-               if (allow_excluded && excl && !(*excl))
+               if (excl && !(*excl))
                        excl = NULL;
        }
 
@@ -1635,7 +1662,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
                        wpa_msg(wpa_s, MSG_DEBUG,
                                "Interworking: Highest roaming consortium matching credential priority %d sp_priority %d (ignore BW)",
                                cred_rc->priority, cred_rc->sp_priority);
-                       if (allow_excluded && excl && !(*excl))
+                       if (excl && !(*excl))
                                excl = NULL;
                }
 
@@ -1645,7 +1672,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
                        wpa_msg(wpa_s, MSG_DEBUG,
                                "Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d (ignore BW)",
                                cred->priority, cred->sp_priority);
-                       if (allow_excluded && excl && !(*excl))
+                       if (excl && !(*excl))
                                excl = NULL;
                }
 
@@ -1655,7 +1682,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
                        wpa_msg(wpa_s, MSG_DEBUG,
                                "Interworking: Highest 3GPP matching credential priority %d sp_priority %d (ignore BW)",
                                cred_3gpp->priority, cred_3gpp->sp_priority);
-                       if (allow_excluded && excl && !(*excl))
+                       if (excl && !(*excl))
                                excl = NULL;
                }
        }
@@ -1820,13 +1847,6 @@ fail:
 }
 
 
-int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
-                        int only_add)
-{
-       return interworking_connect_helper(wpa_s, bss, 1, only_add);
-}
-
-
 #ifdef PCSC_FUNCS
 static int interworking_pcsc_read_imsi(struct wpa_supplicant *wpa_s)
 {
@@ -2125,23 +2145,27 @@ int domain_name_list_contains(struct wpabuf *domain_names,
        pos = wpabuf_head(domain_names);
        end = pos + wpabuf_len(domain_names);
 
-       while (pos + 1 < end) {
-               if (pos + 1 + pos[0] > end)
+       while (end - pos > 1) {
+               u8 elen;
+
+               elen = *pos++;
+               if (elen > end - pos)
                        break;
 
                wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name",
-                                 pos + 1, pos[0]);
-               if (pos[0] == len &&
-                   os_strncasecmp(domain, (const char *) (pos + 1), len) == 0)
+                                 pos, elen);
+               if (elen == len &&
+                   os_strncasecmp(domain, (const char *) pos, len) == 0)
                        return 1;
-               if (!exact_match && pos[0] > len && pos[pos[0] - len] == '.') {
-                       const char *ap = (const char *) (pos + 1);
-                       int offset = pos[0] - len;
+               if (!exact_match && elen > len && pos[elen - len - 1] == '.') {
+                       const char *ap = (const char *) pos;
+                       int offset = elen - len;
+
                        if (os_strncasecmp(domain, ap + offset, len) == 0)
                                return 1;
                }
 
-               pos += 1 + pos[0];
+               pos += elen;
        }
 
        return 0;
@@ -2564,11 +2588,13 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
                return;
        }
 
+#ifdef CONFIG_HS20
        if (wpa_s->fetch_osu_icon_in_progress) {
                wpa_printf(MSG_DEBUG, "Interworking: Next icon (in progress)");
                hs20_next_osu_icon(wpa_s);
                return;
        }
+#endif /* CONFIG_HS20 */
 
        dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
                if (!(bss->caps & IEEE80211_CAP_ESS))
@@ -2602,6 +2628,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
        }
 
        if (found == 0) {
+#ifdef CONFIG_HS20
                if (wpa_s->fetch_osu_info) {
                        if (wpa_s->num_prov_found == 0 &&
                            wpa_s->fetch_osu_waiting_scan &&
@@ -2614,6 +2641,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
                        hs20_osu_icon_fetch(wpa_s);
                        return;
                }
+#endif /* CONFIG_HS20 */
                wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
                wpa_s->fetch_anqp_in_progress = 0;
                if (wpa_s->network_select)
@@ -2664,10 +2692,11 @@ void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
 
 
 int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
-                 u16 info_ids[], size_t num_ids, u32 subtypes)
+                 u16 info_ids[], size_t num_ids, u32 subtypes,
+                 int get_cell_pref)
 {
        struct wpabuf *buf;
-       struct wpabuf *hs20_buf = NULL;
+       struct wpabuf *extra_buf = NULL;
        int ret = 0;
        int freq;
        struct wpa_bss *bss;
@@ -2690,15 +2719,31 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
 
 #ifdef CONFIG_HS20
        if (subtypes != 0) {
-               hs20_buf = wpabuf_alloc(100);
-               if (hs20_buf == NULL)
+               extra_buf = wpabuf_alloc(100);
+               if (extra_buf == NULL)
                        return -1;
-               hs20_put_anqp_req(subtypes, NULL, 0, hs20_buf);
+               hs20_put_anqp_req(subtypes, NULL, 0, extra_buf);
        }
 #endif /* CONFIG_HS20 */
 
-       buf = anqp_build_req(info_ids, num_ids, hs20_buf);
-       wpabuf_free(hs20_buf);
+#ifdef CONFIG_MBO
+       if (get_cell_pref) {
+               struct wpabuf *mbo;
+
+               mbo = mbo_build_anqp_buf(wpa_s, bss);
+               if (mbo) {
+                       if (wpabuf_resize(&extra_buf, wpabuf_len(mbo))) {
+                               wpabuf_free(extra_buf);
+                               return -1;
+                       }
+                       wpabuf_put_buf(extra_buf, mbo);
+                       wpabuf_free(mbo);
+               }
+       }
+#endif /* CONFIG_MBO */
+
+       buf = anqp_build_req(info_ids, num_ids, extra_buf);
+       wpabuf_free(extra_buf);
        if (buf == NULL)
                return -1;
 
@@ -2716,10 +2761,46 @@ 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)
+{
+       struct wpa_bss_anqp_elem *tmp, *elem = NULL;
+
+       if (!anqp)
+               return;
+
+       dl_list_for_each(tmp, &anqp->anqp_elems, struct wpa_bss_anqp_elem,
+                        list) {
+               if (tmp->infoid == info_id) {
+                       elem = tmp;
+                       break;
+               }
+       }
+
+       if (!elem) {
+               elem = os_zalloc(sizeof(*elem));
+               if (!elem)
+                       return;
+               elem->infoid = info_id;
+               dl_list_add(&anqp->anqp_elems, &elem->list);
+       } else {
+               wpabuf_free(elem->payload);
+       }
+
+       elem->payload = wpabuf_alloc_copy(data, slen);
+       if (!elem->payload) {
+               dl_list_del(&elem->list);
+               os_free(elem);
+       }
+}
+
+
 static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                                            struct wpa_bss *bss, const u8 *sa,
                                            u16 info_id,
-                                           const u8 *data, size_t slen)
+                                           const u8 *data, size_t slen,
+                                           u8 dialog_token)
 {
        const u8 *pos = data;
        struct wpa_bss_anqp *anqp = NULL;
@@ -2732,7 +2813,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
 
        switch (info_id) {
        case ANQP_CAPABILITY_LIST:
-               wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
                        " ANQP Capability list", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Capability list",
                                  pos, slen);
@@ -2742,7 +2823,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                }
                break;
        case ANQP_VENUE_NAME:
-               wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
                        " Venue Name", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
                if (anqp) {
@@ -2751,7 +2832,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                }
                break;
        case ANQP_NETWORK_AUTH_TYPE:
-               wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
                        " Network Authentication Type information",
                        MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
@@ -2762,7 +2843,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                }
                break;
        case ANQP_ROAMING_CONSORTIUM:
-               wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
                        " Roaming Consortium list", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
                                  pos, slen);
@@ -2772,7 +2853,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                }
                break;
        case ANQP_IP_ADDR_TYPE_AVAILABILITY:
-               wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
                        " IP Address Type Availability information",
                        MAC2STR(sa));
                wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
@@ -2784,7 +2865,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                }
                break;
        case ANQP_NAI_REALM:
-               wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
                        " NAI Realm list", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
                if (anqp) {
@@ -2793,7 +2874,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                }
                break;
        case ANQP_3GPP_CELLULAR_NETWORK:
-               wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
                        " 3GPP Cellular Network information", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
                                  pos, slen);
@@ -2803,7 +2884,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                }
                break;
        case ANQP_DOMAIN_NAME:
-               wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
                        " Domain Name list", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen);
                if (anqp) {
@@ -2829,7 +2910,8 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                        switch (type) {
                        case HS20_ANQP_OUI_TYPE:
                                hs20_parse_rx_hs20_anqp_resp(wpa_s, bss, sa,
-                                                            pos, slen);
+                                                            pos, slen,
+                                                            dialog_token);
                                break;
                        default:
                                wpa_msg(wpa_s, MSG_DEBUG,
@@ -2849,6 +2931,7 @@ 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);
                break;
        }
 }
@@ -2871,8 +2954,10 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
                   " dialog_token=%u result=%d status_code=%u",
                   MAC2STR(dst), dialog_token, result, status_code);
        if (result != GAS_QUERY_SUCCESS) {
+#ifdef CONFIG_HS20
                if (wpa_s->fetch_osu_icon_in_progress)
                        hs20_icon_fetch_failed(wpa_s);
+#endif /* CONFIG_HS20 */
                anqp_result = "FAILURE";
                goto out;
        }
@@ -2882,8 +2967,10 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
            pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
                wpa_msg(wpa_s, MSG_DEBUG,
                        "ANQP: Unexpected Advertisement Protocol in response");
+#ifdef CONFIG_HS20
                if (wpa_s->fetch_osu_icon_in_progress)
                        hs20_icon_fetch_failed(wpa_s);
+#endif /* CONFIG_HS20 */
                anqp_result = "INVALID_FRAME";
                goto out;
        }
@@ -2927,12 +3014,14 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
                        goto out_parse_done;
                }
                interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos,
-                                               slen);
+                                               slen, dialog_token);
                pos += slen;
        }
 
 out_parse_done:
+#ifdef CONFIG_HS20
        hs20_notify_parse_done(wpa_s);
+#endif /* CONFIG_HS20 */
 out:
        wpa_msg(wpa_s, MSG_INFO, ANQP_QUERY_DONE "addr=" MACSTR " result=%s",
                MAC2STR(dst), anqp_result);
index 3743dc0..3d22292 100644 (file)
@@ -12,7 +12,8 @@
 enum gas_query_result;
 
 int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
-                 u16 info_ids[], size_t num_ids, u32 subtypes);
+                 u16 info_ids[], size_t num_ids, u32 subtypes,
+                 int get_cell_pref);
 void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
                  enum gas_query_result result,
                  const struct wpabuf *adv_proto,
index d5d47e1..e08c2fd 100644 (file)
@@ -65,41 +65,44 @@ static void usage(void)
               "  -B = run daemon in the background\n"
               "  -c = Configuration file\n"
               "  -C = ctrl_interface parameter (only used if -c is not)\n"
-              "  -i = interface name\n"
-              "  -I = additional configuration file\n"
               "  -d = increase debugging verbosity (-dd even more)\n"
               "  -D = driver name (can be multiple drivers: nl80211,wext)\n"
-              "  -e = entropy file\n");
+              "  -e = entropy file\n"
 #ifdef CONFIG_DEBUG_FILE
-       printf("  -f = log output to debug file instead of stdout\n");
+              "  -f = log output to debug file instead of stdout\n"
 #endif /* CONFIG_DEBUG_FILE */
-       printf("  -g = global ctrl_interface\n"
+              "  -g = global ctrl_interface\n"
               "  -G = global ctrl_interface group\n"
-              "  -K = include keys (passwords, etc.) in debug output\n");
-#ifdef CONFIG_DEBUG_SYSLOG
-       printf("  -s = log output to syslog instead of stdout\n");
-#endif /* CONFIG_DEBUG_SYSLOG */
-#ifdef CONFIG_DEBUG_LINUX_TRACING
-       printf("  -T = record to Linux tracing in addition to logging\n");
-       printf("       (records all messages regardless of debug verbosity)\n");
-#endif /* CONFIG_DEBUG_LINUX_TRACING */
-       printf("  -t = include timestamp in debug messages\n"
               "  -h = show this help text\n"
+              "  -i = interface name\n"
+              "  -I = additional configuration file\n"
+              "  -K = include keys (passwords, etc.) in debug output\n"
               "  -L = show license (BSD)\n"
+#ifdef CONFIG_P2P
+              "  -m = Configuration file for the P2P Device interface\n"
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_MATCH_IFACE
+              "  -M = start describing new matching interface\n"
+#endif /* CONFIG_MATCH_IFACE */
+              "  -N = start describing new interface\n"
               "  -o = override driver parameter for new interfaces\n"
               "  -O = override ctrl_interface parameter for new interfaces\n"
               "  -p = driver parameters\n"
               "  -P = PID file\n"
-              "  -q = decrease debugging verbosity (-qq even less)\n");
+              "  -q = decrease debugging verbosity (-qq even less)\n"
+#ifdef CONFIG_DEBUG_SYSLOG
+              "  -s = log output to syslog instead of stdout\n"
+#endif /* CONFIG_DEBUG_SYSLOG */
+              "  -t = include timestamp in debug messages\n"
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+              "  -T = record to Linux tracing in addition to logging\n"
+              "       (records all messages regardless of debug verbosity)\n"
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
 #ifdef CONFIG_DBUS
-       printf("  -u = enable DBus control interface\n");
+              "  -u = enable DBus control interface\n"
 #endif /* CONFIG_DBUS */
-       printf("  -v = show version\n"
-              "  -W = wait for a control interface monitor before starting\n"
-#ifdef CONFIG_P2P
-              "  -m = Configuration file for the P2P Device interface\n"
-#endif /* CONFIG_P2P */
-              "  -N = start describing new interface\n");
+              "  -v = show version\n"
+              "  -W = wait for a control interface monitor before starting\n");
 
        printf("example:\n"
               "  wpa_supplicant -D%s -iwlan0 -c/etc/wpa_supplicant.conf\n",
@@ -153,6 +156,28 @@ static void wpa_supplicant_fd_workaround(int start)
 }
 
 
+#ifdef CONFIG_MATCH_IFACE
+static int wpa_supplicant_init_match(struct wpa_global *global)
+{
+       /*
+        * The assumption is that the first driver is the primary driver and
+        * will handle the arrival / departure of interfaces.
+        */
+       if (wpa_drivers[0]->global_init && !global->drv_priv[0]) {
+               global->drv_priv[0] = wpa_drivers[0]->global_init(global);
+               if (!global->drv_priv[0]) {
+                       wpa_printf(MSG_ERROR,
+                                  "Failed to initialize driver '%s'",
+                                  wpa_drivers[0]->name);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+#endif /* CONFIG_MATCH_IFACE */
+
+
 int main(int argc, char *argv[])
 {
        int c, i;
@@ -176,7 +201,7 @@ int main(int argc, char *argv[])
 
        for (;;) {
                c = getopt(argc, argv,
-                          "b:Bc:C:D:de:f:g:G:hi:I:KLm:No:O:p:P:qsTtuvW");
+                          "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW");
                if (c < 0)
                        break;
                switch (c) {
@@ -282,6 +307,20 @@ int main(int argc, char *argv[])
                case 'W':
                        params.wait_for_monitor++;
                        break;
+#ifdef CONFIG_MATCH_IFACE
+               case 'M':
+                       params.match_iface_count++;
+                       iface = os_realloc_array(params.match_ifaces,
+                                                params.match_iface_count,
+                                                sizeof(struct wpa_interface));
+                       if (!iface)
+                               goto out;
+                       params.match_ifaces = iface;
+                       iface = &params.match_ifaces[params.match_iface_count -
+                                                    1];
+                       os_memset(iface, 0, sizeof(*iface));
+                       break;
+#endif /* CONFIG_MATCH_IFACE */
                case 'N':
                        iface_count++;
                        iface = os_realloc_array(ifaces, iface_count,
@@ -328,6 +367,9 @@ int main(int argc, char *argv[])
                     ifaces[i].ctrl_interface == NULL) ||
                    ifaces[i].ifname == NULL) {
                        if (iface_count == 1 && (params.ctrl_interface ||
+#ifdef CONFIG_MATCH_IFACE
+                                                params.match_iface_count ||
+#endif /* CONFIG_MATCH_IFACE */
                                                 params.dbus_ctrl_interface))
                                break;
                        usage();
@@ -341,6 +383,11 @@ int main(int argc, char *argv[])
                }
        }
 
+#ifdef CONFIG_MATCH_IFACE
+       if (exitcode == 0)
+               exitcode = wpa_supplicant_init_match(global);
+#endif /* CONFIG_MATCH_IFACE */
+
        if (exitcode == 0)
                exitcode = wpa_supplicant_run(global);
 
@@ -351,6 +398,9 @@ int main(int argc, char *argv[])
 out:
        wpa_supplicant_fd_workaround(0);
        os_free(ifaces);
+#ifdef CONFIG_MATCH_IFACE
+       os_free(params.match_ifaces);
+#endif /* CONFIG_MATCH_IFACE */
        os_free(params.pid_file);
 
        os_program_deinit();
index 77f708b..d67d3b2 100644 (file)
@@ -66,9 +66,11 @@ void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
 }
 
 
-static struct mesh_conf * mesh_config_create(struct wpa_ssid *ssid)
+static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s,
+                                            struct wpa_ssid *ssid)
 {
        struct mesh_conf *conf;
+       int cipher;
 
        conf = os_zalloc(sizeof(struct mesh_conf));
        if (!conf)
@@ -82,6 +84,33 @@ static struct mesh_conf * mesh_config_create(struct wpa_ssid *ssid)
                        MESH_CONF_SEC_AMPE;
        else
                conf->security |= MESH_CONF_SEC_NONE;
+       conf->ieee80211w = ssid->ieee80211w;
+       if (conf->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
+               if (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)
+                       conf->ieee80211w = wpa_s->conf->pmf;
+               else
+                       conf->ieee80211w = NO_MGMT_FRAME_PROTECTION;
+       }
+
+       cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 0);
+       if (cipher < 0 || cipher == WPA_CIPHER_TKIP) {
+               wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid pairwise cipher");
+               os_free(conf);
+               return NULL;
+       }
+       conf->pairwise_cipher = cipher;
+
+       cipher = wpa_pick_group_cipher(ssid->group_cipher);
+       if (cipher < 0 || cipher == WPA_CIPHER_TKIP ||
+           cipher == WPA_CIPHER_GTK_NOT_USED) {
+               wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid group cipher");
+               os_free(conf);
+               return NULL;
+       }
+
+       conf->group_cipher = cipher;
+       if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
+               conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
 
        /* defaults */
        conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
@@ -149,6 +178,7 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
        ifmsh->bss[0] = bss = os_zalloc(sizeof(struct hostapd_data));
        if (!bss)
                goto out_free;
+       dl_list_init(&bss->nr_db);
 
        os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN);
        bss->driver = wpa_s->driver;
@@ -175,24 +205,41 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
                wpa_s->conf->dot11RSNASAERetransPeriod;
        os_strlcpy(bss->conf->iface, wpa_s->ifname, sizeof(bss->conf->iface));
 
-       mconf = mesh_config_create(ssid);
+       mconf = mesh_config_create(wpa_s, ssid);
        if (!mconf)
                goto out_free;
        ifmsh->mconf = mconf;
 
        /* need conf->hw_mode for supported rates. */
-       if (ssid->frequency == 0) {
-               conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
-               conf->channel = 1;
-       } else {
-               conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
-                                                      &conf->channel);
-       }
+       conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency, &conf->channel);
        if (conf->hw_mode == NUM_HOSTAPD_MODES) {
                wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz",
                           ssid->frequency);
                goto out_free;
        }
+       if (ssid->ht40)
+               conf->secondary_channel = ssid->ht40;
+       if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A && ssid->vht) {
+               conf->vht_oper_chwidth = ssid->max_oper_chwidth;
+               switch (conf->vht_oper_chwidth) {
+               case VHT_CHANWIDTH_80MHZ:
+               case VHT_CHANWIDTH_80P80MHZ:
+                       ieee80211_freq_to_chan(
+                               ssid->frequency,
+                               &conf->vht_oper_centr_freq_seg0_idx);
+                       conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
+                       break;
+               case VHT_CHANWIDTH_160MHZ:
+                       ieee80211_freq_to_chan(
+                               ssid->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) {
                /*
@@ -318,16 +365,47 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
 
        wpa_supplicant_mesh_deinit(wpa_s);
 
+       wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
+       wpa_s->group_cipher = WPA_CIPHER_NONE;
+       wpa_s->mgmt_group_cipher = 0;
+
        os_memset(&params, 0, sizeof(params));
        params.meshid = ssid->ssid;
        params.meshid_len = ssid->ssid_len;
        ibss_mesh_setup_freq(wpa_s, ssid, &params.freq);
        wpa_s->mesh_ht_enabled = !!params.freq.ht_enabled;
+       wpa_s->mesh_vht_enabled = !!params.freq.vht_enabled;
+       if (params.freq.ht_enabled && params.freq.sec_channel_offset)
+               ssid->ht40 = params.freq.sec_channel_offset;
+       if (wpa_s->mesh_vht_enabled) {
+               ssid->vht = 1;
+               switch (params.freq.bandwidth) {
+               case 80:
+                       if (params.freq.center_freq2) {
+                               ssid->max_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
+                               ssid->vht_center_freq2 =
+                                       params.freq.center_freq2;
+                       } else {
+                               ssid->max_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+                       }
+                       break;
+               case 160:
+                       ssid->max_oper_chwidth = VHT_CHANWIDTH_160MHZ;
+                       break;
+               default:
+                       ssid->max_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+                       break;
+               }
+       }
        if (ssid->beacon_int > 0)
                params.beacon_int = ssid->beacon_int;
        else if (wpa_s->conf->beacon_int > 0)
                params.beacon_int = wpa_s->conf->beacon_int;
-       params.max_peer_links = wpa_s->conf->max_peer_links;
+       if (ssid->dtim_period > 0)
+               params.dtim_period = ssid->dtim_period;
+       else if (wpa_s->conf->dtim_period > 0)
+               params.dtim_period = wpa_s->conf->dtim_period;
+       params.conf.max_peer_links = wpa_s->conf->max_peer_links;
 
        if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
                params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
@@ -337,10 +415,10 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
 
        if (wpa_s->conf->user_mpm) {
                params.flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
-               params.conf.flags &= ~WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+               params.conf.auto_plinks = 0;
        } else {
                params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
-               params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+               params.conf.auto_plinks = 1;
        }
        params.conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
 
@@ -351,21 +429,32 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
                goto out;
        }
 
+       if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+               wpa_s->pairwise_cipher = wpa_s->mesh_rsn->pairwise_cipher;
+               wpa_s->group_cipher = wpa_s->mesh_rsn->group_cipher;
+               wpa_s->mgmt_group_cipher = wpa_s->mesh_rsn->mgmt_group_cipher;
+       }
+
        if (wpa_s->ifmsh) {
                params.ies = wpa_s->ifmsh->mconf->rsn_ie;
                params.ie_len = wpa_s->ifmsh->mconf->rsn_ie_len;
                params.basic_rates = wpa_s->ifmsh->basic_rates;
+               params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
+               params.conf.ht_opmode = wpa_s->ifmsh->bss[0]->iface->ht_op_mode;
        }
 
        wpa_msg(wpa_s, MSG_INFO, "joining mesh %s",
                wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
        ret = wpa_drv_join_mesh(wpa_s, &params);
        if (ret)
-               wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d\n", ret);
+               wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d", ret);
 
        /* hostapd sets the interface down until we associate */
        wpa_drv_set_operstate(wpa_s, 1);
 
+       if (!ret)
+               wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+
 out:
        return ret;
 }
@@ -535,9 +624,22 @@ int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
        if (!mesh_wpa_s) {
                wpa_printf(MSG_ERROR,
                           "mesh: Failed to create new wpa_supplicant interface");
-               wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
+               wpa_drv_if_remove(wpa_s, WPA_IF_MESH, ifname);
                return -1;
        }
        mesh_wpa_s->mesh_if_created = 1;
        return 0;
 }
+
+
+int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+       return mesh_mpm_close_peer(wpa_s, addr);
+}
+
+
+int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr,
+                      int duration)
+{
+       return mesh_mpm_connect_peer(wpa_s, addr, duration);
+}
index 3cb7f1b..7317083 100644 (file)
@@ -18,6 +18,9 @@ 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,
                            size_t len);
+int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr);
+int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr,
+                      int duration);
 
 #ifdef CONFIG_MESH
 
index f81b88c..d14c7e3 100644 (file)
 #include "ap/hostapd.h"
 #include "ap/sta_info.h"
 #include "ap/ieee802_11.h"
+#include "ap/wpa_auth.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
 #include "mesh_mpm.h"
 #include "mesh_rsn.h"
 
 struct mesh_peer_mgmt_ie {
-       const u8 *proto_id;
-       const u8 *llid;
-       const u8 *plid;
-       const u8 *reason;
-       const u8 *pmk;
+       const u8 *proto_id; /* Mesh Peering Protocol Identifier (2 octets) */
+       const u8 *llid; /* Local Link ID (2 octets) */
+       const u8 *plid; /* Peer Link ID (conditional, 2 octets) */
+       const u8 *reason; /* Reason Code (conditional, 2 octets) */
+       const u8 *chosen_pmk; /* Chosen PMK (optional, 16 octets) */
 };
 
 static void plink_timer(void *eloop_ctx, void *user_data);
@@ -34,18 +35,17 @@ enum plink_event {
        PLINK_UNDEFINED,
        OPN_ACPT,
        OPN_RJCT,
-       OPN_IGNR,
        CNF_ACPT,
        CNF_RJCT,
-       CNF_IGNR,
        CLS_ACPT,
-       CLS_IGNR
+       REQ_RJCT
 };
 
 static const char * const mplstate[] = {
-       [PLINK_LISTEN] = "LISTEN",
-       [PLINK_OPEN_SENT] = "OPEN_SENT",
-       [PLINK_OPEN_RCVD] = "OPEN_RCVD",
+       [0] = "UNINITIALIZED",
+       [PLINK_IDLE] = "IDLE",
+       [PLINK_OPN_SNT] = "OPN_SNT",
+       [PLINK_OPN_RCVD] = "OPN_RCVD",
        [PLINK_CNF_RCVD] = "CNF_RCVD",
        [PLINK_ESTAB] = "ESTAB",
        [PLINK_HOLDING] = "HOLDING",
@@ -56,12 +56,10 @@ static const char * const mplevent[] = {
        [PLINK_UNDEFINED] = "UNDEFINED",
        [OPN_ACPT] = "OPN_ACPT",
        [OPN_RJCT] = "OPN_RJCT",
-       [OPN_IGNR] = "OPN_IGNR",
        [CNF_ACPT] = "CNF_ACPT",
        [CNF_RJCT] = "CNF_RJCT",
-       [CNF_IGNR] = "CNF_IGNR",
        [CLS_ACPT] = "CLS_ACPT",
-       [CLS_IGNR] = "CLS_IGNR"
+       [REQ_RJCT] = "REQ_RJCT",
 };
 
 
@@ -72,10 +70,10 @@ static int mesh_mpm_parse_peer_mgmt(struct wpa_supplicant *wpa_s,
 {
        os_memset(mpm_ie, 0, sizeof(*mpm_ie));
 
-       /* remove optional PMK at end */
-       if (len >= 16) {
-               len -= 16;
-               mpm_ie->pmk = ie + len - 16;
+       /* Remove optional Chosen PMK field at end */
+       if (len >= SAE_PMKID_LEN) {
+               mpm_ie->chosen_pmk = ie + len - SAE_PMKID_LEN;
+               len -= SAE_PMKID_LEN;
        }
 
        if ((action_field == PLINK_OPEN && len != 4) ||
@@ -101,8 +99,8 @@ static int mesh_mpm_parse_peer_mgmt(struct wpa_supplicant *wpa_s,
                len -= 2;
        }
 
-       /* plid, present for confirm, and possibly close */
-       if (len)
+       /* Peer Link ID, present for confirm, and possibly close */
+       if (len >= 2)
                mpm_ie->plid = ie;
 
        return 0;
@@ -193,12 +191,13 @@ static void mesh_mpm_init_link(struct wpa_supplicant *wpa_s,
 
        sta->my_lid = llid;
        sta->peer_lid = 0;
+       sta->peer_aid = 0;
 
        /*
         * We do not use wpa_mesh_set_plink_state() here because there is no
         * entry in kernel yet.
         */
-       sta->plink_state = PLINK_LISTEN;
+       sta->plink_state = PLINK_IDLE;
 }
 
 
@@ -212,9 +211,6 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
        struct hostapd_data *bss = ifmsh->bss[0];
        struct mesh_conf *conf = ifmsh->mconf;
        u8 supp_rates[2 + 2 + 32];
-#ifdef CONFIG_IEEE80211N
-       u8 ht_capa_oper[2 + 26 + 2 + 22];
-#endif /* CONFIG_IEEE80211N */
        u8 *pos, *cat;
        u8 ie_len, add_plid = 0;
        int ret;
@@ -239,6 +235,12 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
                           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 */
+                          2 + 5;  /* VHT Operation */
+       }
+#endif /* CONFIG_IEEE80211AC */
        if (type != PLINK_CLOSE)
                buf_len += conf->rsn_ie_len; /* RSN IE */
 
@@ -258,7 +260,7 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
 
                /* aid */
                if (type == PLINK_CONFIRM)
-                       wpabuf_put_le16(buf, sta->peer_lid);
+                       wpabuf_put_le16(buf, sta->aid);
 
                /* IE: supp + ext. supp rates */
                pos = hostapd_eid_supp_rates(bss, supp_rates);
@@ -285,7 +287,8 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
                /* TODO: Add Connected to Mesh Gate/AS subfields */
                wpabuf_put_u8(buf, info);
                /* always forwarding & accepting plinks for now */
-               wpabuf_put_u8(buf, 0x1 | 0x8);
+               wpabuf_put_u8(buf, MESH_CAP_ACCEPT_ADDITIONAL_PEER |
+                             MESH_CAP_FORWARDING);
        } else {        /* Peer closing frame */
                /* IE: Mesh ID */
                wpabuf_put_u8(buf, WLAN_EID_MESH_ID);
@@ -334,11 +337,22 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_IEEE80211N
        if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
+               u8 ht_capa_oper[2 + 26 + 2 + 22];
+
                pos = hostapd_eid_ht_capabilities(bss, ht_capa_oper);
                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];
+
+               pos = hostapd_eid_vht_capabilities(bss, vht_capa_oper, 0);
+               pos = hostapd_eid_vht_operation(bss, pos);
+               wpabuf_put_data(buf, vht_capa_oper, pos - vht_capa_oper);
+       }
+#endif /* CONFIG_IEEE80211AC */
 
        if (ampe && mesh_rsn_protect_frame(wpa_s->mesh_rsn, sta, cat, buf)) {
                wpa_msg(wpa_s, MSG_INFO,
@@ -346,6 +360,9 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
                goto fail;
        }
 
+       wpa_msg(wpa_s, MSG_DEBUG, "Mesh MPM: Sending peering frame type %d to "
+               MACSTR " (my_lid=0x%x peer_lid=0x%x)",
+               type, MAC2STR(sta->addr), sta->my_lid, sta->peer_lid);
        ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0,
                                  sta->addr, wpa_s->own_addr, wpa_s->own_addr,
                                  wpabuf_head(buf), wpabuf_len(buf), 0);
@@ -366,15 +383,17 @@ void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s,
        struct hostapd_sta_add_params params;
        int ret;
 
+       wpa_msg(wpa_s, MSG_DEBUG, "MPM set " MACSTR " from %s into %s",
+               MAC2STR(sta->addr), mplstate[sta->plink_state],
+               mplstate[state]);
        sta->plink_state = state;
 
        os_memset(&params, 0, sizeof(params));
        params.addr = sta->addr;
        params.plink_state = state;
+       params.peer_aid = sta->peer_aid;
        params.set = 1;
 
-       wpa_msg(wpa_s, MSG_DEBUG, "MPM set " MACSTR " into %s",
-               MAC2STR(sta->addr), mplstate[state]);
        ret = wpa_drv_sta_add(wpa_s, &params);
        if (ret) {
                wpa_msg(wpa_s, MSG_ERROR, "Driver failed to set " MACSTR
@@ -400,10 +419,11 @@ static void plink_timer(void *eloop_ctx, void *user_data)
        struct sta_info *sta = user_data;
        u16 reason = 0;
        struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+       struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
 
        switch (sta->plink_state) {
-       case PLINK_OPEN_RCVD:
-       case PLINK_OPEN_SENT:
+       case PLINK_OPN_RCVD:
+       case PLINK_OPN_SNT:
                /* retry timer */
                if (sta->mpm_retries < conf->dot11MeshMaxRetries) {
                        eloop_register_timeout(
@@ -429,6 +449,13 @@ static void plink_timer(void *eloop_ctx, void *user_data)
                break;
        case PLINK_HOLDING:
                /* holding timer */
+
+               if (sta->mesh_sae_pmksa_caching) {
+                       wpa_printf(MSG_DEBUG, "MPM: Peer " MACSTR
+                                  " looks like it does not support mesh SAE PMKSA caching, so remove the cached entry for it",
+                                  MAC2STR(sta->addr));
+                       wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+               }
                mesh_mpm_fsm_restart(wpa_s, sta);
                break;
        default:
@@ -453,8 +480,8 @@ mesh_mpm_plink_open(struct wpa_supplicant *wpa_s, struct sta_info *sta,
 }
 
 
-int mesh_mpm_plink_close(struct hostapd_data *hapd,
-                        struct sta_info *sta, void *ctx)
+static int mesh_mpm_plink_close(struct hostapd_data *hapd, struct sta_info *sta,
+                               void *ctx)
 {
        struct wpa_supplicant *wpa_s = ctx;
        int reason = WLAN_REASON_MESH_PEERING_CANCELLED;
@@ -472,6 +499,85 @@ int mesh_mpm_plink_close(struct hostapd_data *hapd,
 }
 
 
+int mesh_mpm_close_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+       struct hostapd_data *hapd;
+       struct sta_info *sta;
+
+       if (!wpa_s->ifmsh) {
+               wpa_msg(wpa_s, MSG_INFO, "Mesh is not prepared yet");
+               return -1;
+       }
+
+       hapd = wpa_s->ifmsh->bss[0];
+       sta = ap_get_sta(hapd, addr);
+       if (!sta) {
+               wpa_msg(wpa_s, MSG_INFO, "No such mesh peer");
+               return -1;
+       }
+
+       return mesh_mpm_plink_close(hapd, sta, wpa_s) == 0 ? 0 : -1;
+}
+
+
+static void peer_add_timer(void *eloop_ctx, void *user_data)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+       os_memset(hapd->mesh_required_peer, 0, ETH_ALEN);
+}
+
+
+int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+                         int duration)
+{
+       struct wpa_ssid *ssid = wpa_s->current_ssid;
+       struct hostapd_data *hapd;
+       struct sta_info *sta;
+       struct mesh_conf *conf;
+
+       if (!wpa_s->ifmsh) {
+               wpa_msg(wpa_s, MSG_INFO, "Mesh is not prepared yet");
+               return -1;
+       }
+
+       if (!ssid || !ssid->no_auto_peer) {
+               wpa_msg(wpa_s, MSG_INFO,
+                       "This command is available only with no_auto_peer mesh network");
+               return -1;
+       }
+
+       hapd = wpa_s->ifmsh->bss[0];
+       conf = wpa_s->ifmsh->mconf;
+
+       sta = ap_get_sta(hapd, addr);
+       if (!sta) {
+               wpa_msg(wpa_s, MSG_INFO, "No such mesh peer");
+               return -1;
+       }
+
+       if ((PLINK_OPN_SNT <= sta->plink_state &&
+           sta->plink_state <= PLINK_ESTAB) ||
+           (sta->sae && sta->sae->state > SAE_NOTHING)) {
+               wpa_msg(wpa_s, MSG_INFO,
+                       "Specified peer is connecting/connected");
+               return -1;
+       }
+
+       if (conf->security == MESH_CONF_SEC_NONE) {
+               mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
+       } else {
+               mesh_rsn_auth_sae_sta(wpa_s, sta);
+               os_memcpy(hapd->mesh_required_peer, addr, ETH_ALEN);
+               eloop_register_timeout(duration == -1 ? 10 : duration, 0,
+                                      peer_add_timer, wpa_s, NULL);
+       }
+
+       return 0;
+}
+
+
 void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh)
 {
        struct hostapd_data *hapd = ifmsh->bss[0];
@@ -481,6 +587,7 @@ void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh)
 
        hapd->num_plinks = 0;
        hostapd_free_stas(hapd);
+       eloop_cancel_timeout(peer_add_timer, wpa_s, NULL);
 }
 
 
@@ -522,7 +629,7 @@ void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
        if (!sta->my_lid)
                mesh_mpm_init_link(wpa_s, sta);
 
-       mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+       mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
 }
 
 /*
@@ -541,6 +648,14 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
        struct sta_info *sta;
        int ret;
 
+       if (elems->mesh_config_len >= 7 &&
+           !(elems->mesh_config[6] & MESH_CAP_ACCEPT_ADDITIONAL_PEER)) {
+               wpa_msg(wpa_s, MSG_DEBUG,
+                       "mesh: Ignore a crowded peer " MACSTR,
+                       MAC2STR(addr));
+               return NULL;
+       }
+
        sta = ap_get_sta(data, addr);
        if (!sta) {
                sta = ap_sta_add(data, addr);
@@ -548,28 +663,45 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
                        return NULL;
        }
 
+       /* Set WMM by default since Mesh STAs are QoS STAs */
+       sta->flags |= WLAN_STA_WMM;
+
        /* initialize sta */
        if (copy_supp_rates(wpa_s, sta, elems)) {
                ap_free_sta(data, sta);
                return NULL;
        }
 
-       mesh_mpm_init_link(wpa_s, sta);
+       if (!sta->my_lid)
+               mesh_mpm_init_link(wpa_s, sta);
 
 #ifdef CONFIG_IEEE80211N
        copy_sta_ht_capab(data, sta, elems->ht_capabilities);
        update_ht_state(data, sta);
 #endif /* CONFIG_IEEE80211N */
 
+#ifdef CONFIG_IEEE80211AC
+       copy_sta_vht_capab(data, sta, elems->vht_capabilities);
+       set_sta_vht_opmode(data, sta, elems->vht_opmode_notif);
+#endif /* CONFIG_IEEE80211AC */
+
+       if (hostapd_get_aid(data, sta) < 0) {
+               wpa_msg(wpa_s, MSG_ERROR, "No AIDs available");
+               ap_free_sta(data, sta);
+               return NULL;
+       }
+
        /* insert into driver */
        os_memset(&params, 0, sizeof(params));
        params.supp_rates = sta->supported_rates;
        params.supp_rates_len = sta->supported_rates_len;
        params.addr = addr;
        params.plink_state = sta->plink_state;
-       params.aid = sta->peer_lid;
+       params.aid = sta->aid;
+       params.peer_aid = sta->peer_aid;
        params.listen_interval = 100;
        params.ht_capabilities = sta->ht_capabilities;
+       params.vht_capabilities = sta->vht_capabilities;
        params.flags |= WPA_STA_WMM;
        params.flags_mask |= WPA_STA_AUTHENTICATED;
        if (conf->security == MESH_CONF_SEC_NONE) {
@@ -605,7 +737,9 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
        if (!sta)
                return;
 
-       if (ssid && ssid->no_auto_peer) {
+       if (ssid && ssid->no_auto_peer &&
+           (is_zero_ether_addr(data->mesh_required_peer) ||
+            os_memcmp(data->mesh_required_peer, addr, ETH_ALEN) != 0)) {
                wpa_msg(wpa_s, MSG_INFO, "will not initiate new peer link with "
                        MACSTR " because of no_auto_peer", MAC2STR(addr));
                if (data->mesh_pending_auth) {
@@ -634,10 +768,13 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
                return;
        }
 
-       if (conf->security == MESH_CONF_SEC_NONE)
-               mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
-       else
+       if (conf->security == MESH_CONF_SEC_NONE) {
+               if (sta->plink_state < PLINK_OPN_SNT ||
+                   sta->plink_state > PLINK_ESTAB)
+                       mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
+       } else {
                mesh_rsn_auth_sae_sta(wpa_s, sta);
+       }
 }
 
 
@@ -664,64 +801,85 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
                MAC2STR(sta->addr));
 
        if (conf->security & MESH_CONF_SEC_AMPE) {
-               wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 0, 0,
-                               seq, sizeof(seq), sta->mtk, sizeof(sta->mtk));
-               wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 1, 0,
-                               seq, sizeof(seq),
-                               sta->mgtk, sizeof(sta->mgtk));
-               wpa_drv_set_key(wpa_s, WPA_ALG_IGTK, sta->addr, 4, 0,
-                               seq, sizeof(seq),
-                               sta->mgtk, sizeof(sta->mgtk));
-
-               wpa_hexdump_key(MSG_DEBUG, "mtk:", sta->mtk, sizeof(sta->mtk));
-               wpa_hexdump_key(MSG_DEBUG, "mgtk:",
-                               sta->mgtk, sizeof(sta->mgtk));
+               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);
+
+               wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK Key RSC",
+                               sta->mgtk_rsc, sizeof(sta->mgtk_rsc));
+               wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK",
+                               sta->mgtk, sta->mgtk_len);
+               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);
+
+               if (sta->igtk_len) {
+                       wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK Key RSC",
+                                       sta->igtk_rsc, sizeof(sta->igtk_rsc));
+                       wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK",
+                                       sta->igtk, sta->igtk_len);
+                       wpa_drv_set_key(
+                               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);
+               }
        }
 
        wpa_mesh_set_plink_state(wpa_s, sta, PLINK_ESTAB);
        hapd->num_plinks++;
 
        sta->flags |= WLAN_STA_ASSOC;
+       sta->mesh_sae_pmksa_caching = 0;
 
+       eloop_cancel_timeout(peer_add_timer, wpa_s, NULL);
+       peer_add_timer(wpa_s, NULL);
        eloop_cancel_timeout(plink_timer, wpa_s, sta);
 
        /* Send ctrl event */
-       wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR,
-                    MAC2STR(sta->addr));
+       wpa_msg(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR,
+               MAC2STR(sta->addr));
 }
 
 
 static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
-                        enum plink_event event)
+                        enum plink_event event, u16 reason)
 {
        struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
        struct mesh_conf *conf = wpa_s->ifmsh->mconf;
-       u16 reason = 0;
 
        wpa_msg(wpa_s, MSG_DEBUG, "MPM " MACSTR " state %s event %s",
                MAC2STR(sta->addr), mplstate[sta->plink_state],
                mplevent[event]);
 
        switch (sta->plink_state) {
-       case PLINK_LISTEN:
+       case PLINK_IDLE:
                switch (event) {
                case CLS_ACPT:
                        mesh_mpm_fsm_restart(wpa_s, sta);
                        break;
                case OPN_ACPT:
-                       mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_RCVD);
+                       mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_RCVD);
                        mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM,
                                                   0);
                        break;
+               case REQ_RJCT:
+                       mesh_mpm_send_plink_action(wpa_s, sta,
+                                                  PLINK_CLOSE, reason);
+                       break;
                default:
                        break;
                }
                break;
-       case PLINK_OPEN_SENT:
+       case PLINK_OPN_SNT:
                switch (event) {
                case OPN_RJCT:
                case CNF_RJCT:
-                       reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+                       if (!reason)
+                               reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
                        /* fall-through */
                case CLS_ACPT:
                        wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
@@ -736,12 +894,13 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
                        break;
                case OPN_ACPT:
                        /* retry timer is left untouched */
-                       wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPEN_RCVD);
+                       wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPN_RCVD);
                        mesh_mpm_send_plink_action(wpa_s, sta,
                                                   PLINK_CONFIRM, 0);
                        break;
                case CNF_ACPT:
                        wpa_mesh_set_plink_state(wpa_s, sta, PLINK_CNF_RCVD);
+                       eloop_cancel_timeout(plink_timer, wpa_s, sta);
                        eloop_register_timeout(
                                conf->dot11MeshConfirmTimeout / 1000,
                                (conf->dot11MeshConfirmTimeout % 1000) * 1000,
@@ -751,11 +910,12 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
                        break;
                }
                break;
-       case PLINK_OPEN_RCVD:
+       case PLINK_OPN_RCVD:
                switch (event) {
                case OPN_RJCT:
                case CNF_RJCT:
-                       reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+                       if (!reason)
+                               reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
                        /* fall-through */
                case CLS_ACPT:
                        wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
@@ -786,7 +946,8 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
                switch (event) {
                case OPN_RJCT:
                case CNF_RJCT:
-                       reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+                       if (!reason)
+                               reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
                        /* fall-through */
                case CLS_ACPT:
                        wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
@@ -801,6 +962,8 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
                                                   PLINK_CLOSE, reason);
                        break;
                case OPN_ACPT:
+                       if (conf->security & MESH_CONF_SEC_AMPE)
+                               mesh_rsn_derive_mtk(wpa_s, sta);
                        mesh_mpm_plink_estab(wpa_s, sta);
                        mesh_mpm_send_plink_action(wpa_s, sta,
                                                   PLINK_CONFIRM, 0);
@@ -811,9 +974,12 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
                break;
        case PLINK_ESTAB:
                switch (event) {
+               case OPN_RJCT:
+               case CNF_RJCT:
                case CLS_ACPT:
                        wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
-                       reason = WLAN_REASON_MESH_CLOSE_RCVD;
+                       if (!reason)
+                               reason = WLAN_REASON_MESH_CLOSE_RCVD;
 
                        eloop_register_timeout(
                                conf->dot11MeshHoldingTimeout / 1000,
@@ -825,9 +991,8 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
                                " closed with reason %d",
                                MAC2STR(sta->addr), reason);
 
-                       wpa_msg_ctrl(wpa_s, MSG_INFO,
-                                    MESH_PEER_DISCONNECTED MACSTR,
-                                    MAC2STR(sta->addr));
+                       wpa_msg(wpa_s, MSG_INFO, MESH_PEER_DISCONNECTED MACSTR,
+                               MAC2STR(sta->addr));
 
                        hapd->num_plinks--;
 
@@ -875,13 +1040,14 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
        struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
        struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
        struct sta_info *sta;
-       u16 plid = 0, llid = 0;
+       u16 plid = 0, llid = 0, aid = 0;
        enum plink_event event;
        struct ieee802_11_elems elems;
        struct mesh_peer_mgmt_ie peer_mgmt_ie;
        const u8 *ies;
        size_t ie_len;
        int ret;
+       u16 reason = 0;
 
        if (mgmt->u.action.category != WLAN_ACTION_SELF_PROTECTED)
                return;
@@ -912,7 +1078,8 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
                ie_len -= 2;
        }
        if (action_field == PLINK_CONFIRM) {
-               wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", WPA_GET_LE16(ies));
+               aid = WPA_GET_LE16(ies);
+               wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", aid);
                ies += 2;       /* aid */
                ie_len -= 2;
        }
@@ -956,6 +1123,10 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
                llid = WPA_GET_LE16(peer_mgmt_ie.plid);
        wpa_printf(MSG_DEBUG, "MPM: plid=0x%x llid=0x%x", plid, llid);
 
+       if (action_field == PLINK_CLOSE)
+               wpa_printf(MSG_DEBUG, "MPM: close reason=%u",
+                          WPA_GET_LE16(peer_mgmt_ie.reason));
+
        sta = ap_get_sta(hapd, mgmt->sa);
 
        /*
@@ -963,7 +1134,8 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
         * open mesh, then go ahead and add the peer before proceeding.
         */
        if (!sta && action_field == PLINK_OPEN &&
-           !(mconf->security & MESH_CONF_SEC_AMPE))
+           (!(mconf->security & MESH_CONF_SEC_AMPE) ||
+            wpa_auth_pmksa_get(hapd->wpa_auth, mgmt->sa)))
                sta = mesh_mpm_add_peer(wpa_s, mgmt->sa, &elems);
 
        if (!sta) {
@@ -982,12 +1154,24 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
        if (!sta->my_lid)
                mesh_mpm_init_link(wpa_s, sta);
 
-       if ((mconf->security & MESH_CONF_SEC_AMPE) &&
-           mesh_rsn_process_ampe(wpa_s, sta, &elems,
-                                 &mgmt->u.action.category,
-                                 ies, ie_len)) {
-               wpa_printf(MSG_DEBUG, "MPM: RSN process rejected frame");
-               return;
+       if (mconf->security & MESH_CONF_SEC_AMPE) {
+               int res;
+
+               res = mesh_rsn_process_ampe(wpa_s, sta, &elems,
+                                           &mgmt->u.action.category,
+                                           peer_mgmt_ie.chosen_pmk,
+                                           ies, ie_len);
+               if (res) {
+                       wpa_printf(MSG_DEBUG,
+                                  "MPM: RSN process rejected frame (res=%d)",
+                                  res);
+                       if (action_field == PLINK_OPEN && res == -2) {
+                               /* AES-SIV decryption failed */
+                               mesh_mpm_fsm(wpa_s, sta, OPN_RJCT,
+                                            WLAN_REASON_MESH_INVALID_GTK);
+                       }
+                       return;
+               }
        }
 
        if (sta->plink_state == PLINK_BLOCKED) {
@@ -999,12 +1183,16 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
        switch (action_field) {
        case PLINK_OPEN:
                if (plink_free_count(hapd) == 0) {
-                       event = OPN_IGNR;
+                       event = REQ_RJCT;
+                       reason = WLAN_REASON_MESH_MAX_PEERS;
                        wpa_printf(MSG_INFO,
                                   "MPM: Peer link num over quota(%d)",
                                   hapd->max_plinks);
                } else if (sta->peer_lid && sta->peer_lid != plid) {
-                       event = OPN_IGNR;
+                       wpa_printf(MSG_DEBUG,
+                                  "MPM: peer_lid mismatch: 0x%x != 0x%x",
+                                  sta->peer_lid, plid);
+                       return; /* no FSM event */
                } else {
                        sta->peer_lid = plid;
                        event = OPN_ACPT;
@@ -1012,16 +1200,21 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
                break;
        case PLINK_CONFIRM:
                if (plink_free_count(hapd) == 0) {
-                       event = CNF_IGNR;
+                       event = REQ_RJCT;
+                       reason = WLAN_REASON_MESH_MAX_PEERS;
                        wpa_printf(MSG_INFO,
                                   "MPM: Peer link num over quota(%d)",
                                   hapd->max_plinks);
                } else if (sta->my_lid != llid ||
                           (sta->peer_lid && sta->peer_lid != plid)) {
-                       event = CNF_IGNR;
+                       wpa_printf(MSG_DEBUG,
+                                  "MPM: lid mismatch: my_lid: 0x%x != 0x%x or peer_lid: 0x%x != 0x%x",
+                                  sta->my_lid, llid, sta->peer_lid, plid);
+                       return; /* no FSM event */
                } else {
                        if (!sta->peer_lid)
                                sta->peer_lid = plid;
+                       sta->peer_aid = aid;
                        event = CNF_ACPT;
                }
                break;
@@ -1037,12 +1230,19 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
                         * restarted.
                         */
                        event = CLS_ACPT;
-               else if (sta->peer_lid != plid)
-                       event = CLS_IGNR;
-               else if (peer_mgmt_ie.plid && sta->my_lid != llid)
-                       event = CLS_IGNR;
-               else
+               else if (sta->peer_lid != plid) {
+                       wpa_printf(MSG_DEBUG,
+                                  "MPM: peer_lid mismatch: 0x%x != 0x%x",
+                                  sta->peer_lid, plid);
+                       return; /* no FSM event */
+               } else if (peer_mgmt_ie.plid && sta->my_lid != llid) {
+                       wpa_printf(MSG_DEBUG,
+                                  "MPM: my_lid mismatch: 0x%x != 0x%x",
+                                  sta->my_lid, llid);
+                       return; /* no FSM event */
+               } else {
                        event = CLS_ACPT;
+               }
                break;
        default:
                /*
@@ -1052,13 +1252,15 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
                 */
                return;
        }
-       mesh_mpm_fsm(wpa_s, sta, event);
+       mesh_mpm_fsm(wpa_s, sta, event, reason);
 }
 
 
 /* called by ap_free_sta */
-void mesh_mpm_free_sta(struct sta_info *sta)
+void mesh_mpm_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
 {
+       if (sta->plink_state == PLINK_ESTAB)
+               hapd->num_plinks--;
        eloop_cancel_timeout(plink_timer, ELOOP_ALL_CTX, sta);
        eloop_cancel_timeout(mesh_auth_timer, ELOOP_ALL_CTX, sta);
 }
index 7ebaef0..5fc1e61 100644 (file)
@@ -14,10 +14,13 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
                            struct ieee802_11_elems *elems);
 void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh);
 void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr);
-void mesh_mpm_free_sta(struct sta_info *sta);
+void mesh_mpm_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
 void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s,
                              struct sta_info *sta,
                              enum mesh_plink_state state);
+int mesh_mpm_close_peer(struct wpa_supplicant *wpa_s, const u8 *addr);
+int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+                         int duration);
 
 #ifdef CONFIG_MESH
 
index 747f1ae..27ab8cb 100644 (file)
 
 #define MESH_AUTH_TIMEOUT 10
 #define MESH_AUTH_RETRY 3
-#define MESH_AUTH_BLOCK_DURATION 3600
 
 void mesh_auth_timer(void *eloop_ctx, void *user_data)
 {
        struct wpa_supplicant *wpa_s = eloop_ctx;
        struct sta_info *sta = user_data;
+       struct hostapd_data *hapd;
 
        if (sta->sae->state != SAE_ACCEPTED) {
                wpa_printf(MSG_DEBUG, "AUTH: Re-authenticate with " MACSTR
@@ -43,23 +43,20 @@ void mesh_auth_timer(void *eloop_ctx, void *user_data)
                if (sta->sae_auth_retry < MESH_AUTH_RETRY) {
                        mesh_rsn_auth_sae_sta(wpa_s, sta);
                } else {
+                       hapd = wpa_s->ifmsh->bss[0];
+
                        if (sta->sae_auth_retry > MESH_AUTH_RETRY) {
-                               ap_free_sta(wpa_s->ifmsh->bss[0], sta);
+                               ap_free_sta(hapd, sta);
                                return;
                        }
 
                        /* block the STA if exceeded the number of attempts */
                        wpa_mesh_set_plink_state(wpa_s, sta, PLINK_BLOCKED);
                        sta->sae->state = SAE_NOTHING;
-                       if (wpa_s->mesh_auth_block_duration <
-                           MESH_AUTH_BLOCK_DURATION)
-                               wpa_s->mesh_auth_block_duration += 60;
-                       eloop_register_timeout(wpa_s->mesh_auth_block_duration,
-                                              0, mesh_auth_timer, wpa_s, sta);
                        wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_BLOCKED "addr="
                                MACSTR " duration=%d",
                                MAC2STR(sta->addr),
-                               wpa_s->mesh_auth_block_duration);
+                               hapd->conf->ap_max_inactivity);
                }
                sta->sae_auth_retry++;
        }
@@ -139,7 +136,8 @@ static int auth_start_ampe(void *ctx, const u8 *addr)
 }
 
 
-static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)
+static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
+                               enum mfp_options ieee80211w)
 {
        struct wpa_auth_config conf;
        struct wpa_auth_callbacks cb;
@@ -148,13 +146,18 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)
        wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
 
        os_memset(&conf, 0, sizeof(conf));
-       conf.wpa = 2;
+       conf.wpa = WPA_PROTO_RSN;
        conf.wpa_key_mgmt = WPA_KEY_MGMT_SAE;
-       conf.wpa_pairwise = WPA_CIPHER_CCMP;
-       conf.rsn_pairwise = WPA_CIPHER_CCMP;
-       conf.wpa_group = WPA_CIPHER_CCMP;
+       conf.wpa_pairwise = rsn->pairwise_cipher;
+       conf.rsn_pairwise = rsn->pairwise_cipher;
+       conf.wpa_group = rsn->group_cipher;
        conf.eapol_version = 0;
        conf.wpa_group_rekey = -1;
+#ifdef CONFIG_IEEE80211W
+       conf.ieee80211w = ieee80211w;
+       if (ieee80211w != NO_MGMT_FRAME_PROTECTION)
+               conf.group_mgmt_cipher = rsn->mgmt_group_cipher;
+#endif /* CONFIG_IEEE80211W */
 
        os_memset(&cb, 0, sizeof(cb));
        cb.ctx = rsn;
@@ -170,18 +173,34 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)
        }
 
        /* TODO: support rekeying */
-       if (random_get_bytes(rsn->mgtk, 16) < 0) {
-               wpa_deinit(rsn->auth);
+       rsn->mgtk_len = wpa_cipher_key_len(conf.wpa_group);
+       if (random_get_bytes(rsn->mgtk, rsn->mgtk_len) < 0)
                return -1;
-       }
+       rsn->mgtk_key_id = 1;
 
-       /* group mgmt */
-       wpa_drv_set_key(rsn->wpa_s, WPA_ALG_IGTK, NULL, 4, 1,
-                       seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+#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)
+                       return -1;
+               rsn->igtk_key_id = 4;
+
+               /* group mgmt */
+               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,
+                               rsn->igtk_key_id, 1,
+                               seq, sizeof(seq), rsn->igtk, rsn->igtk_len);
+       }
+#endif /* CONFIG_IEEE80211W */
 
        /* group privacy / data frames */
-       wpa_drv_set_key(rsn->wpa_s, WPA_ALG_CCMP, NULL, 1, 1,
-                       seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+       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,
+                       rsn->mgtk_key_id, 1, seq, sizeof(seq),
+                       rsn->mgtk, rsn->mgtk_len);
 
        return 0;
 }
@@ -190,6 +209,9 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)
 static void mesh_rsn_deinit(struct mesh_rsn *rsn)
 {
        os_memset(rsn->mgtk, 0, sizeof(rsn->mgtk));
+       rsn->mgtk_len = 0;
+       os_memset(rsn->igtk, 0, sizeof(rsn->igtk));
+       rsn->igtk_len = 0;
        if (rsn->auth)
                wpa_deinit(rsn->auth);
 }
@@ -207,8 +229,12 @@ struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s,
        if (mesh_rsn == NULL)
                return NULL;
        mesh_rsn->wpa_s = wpa_s;
+       mesh_rsn->pairwise_cipher = conf->pairwise_cipher;
+       mesh_rsn->group_cipher = conf->group_cipher;
+       mesh_rsn->mgmt_group_cipher = conf->mgmt_group_cipher;
 
-       if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr) < 0) {
+       if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr,
+                                conf->ieee80211w) < 0) {
                mesh_rsn_deinit(mesh_rsn);
                os_free(mesh_rsn);
                return NULL;
@@ -291,6 +317,7 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
 {
        struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
        struct wpa_ssid *ssid = wpa_s->current_ssid;
+       struct rsn_pmksa_cache_entry *pmksa;
        unsigned int rnd;
        int ret;
 
@@ -306,6 +333,29 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
                        return -1;
        }
 
+       pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr);
+       if (pmksa) {
+               if (!sta->wpa_sm)
+                       sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+                                                       sta->addr, NULL);
+               if (!sta->wpa_sm) {
+                       wpa_printf(MSG_ERROR,
+                                  "mesh: Failed to initialize RSN state machine");
+                       return -1;
+               }
+
+               wpa_printf(MSG_DEBUG,
+                          "AUTH: Mesh PMKSA cache entry found for " MACSTR
+                          " - try to use PMKSA caching instead of new SAE authentication",
+                          MAC2STR(sta->addr));
+               wpa_auth_pmksa_set_to_sm(pmksa, sta->wpa_sm, hapd->wpa_auth,
+                                        sta->sae->pmkid, sta->sae->pmk);
+               sae_accept_sta(hapd, sta);
+               sta->mesh_sae_pmksa_caching = 1;
+               return 0;
+       }
+       sta->mesh_sae_pmksa_caching = 0;
+
        if (mesh_rsn_build_sae_commit(wpa_s, ssid, sta))
                return -1;
 
@@ -313,7 +363,6 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
                "AUTH: started authentication with SAE peer: " MACSTR,
                MAC2STR(sta->addr));
 
-       wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
        ret = auth_sae_init_committed(hapd, sta);
        if (ret)
                return ret;
@@ -328,10 +377,7 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
 
 void mesh_rsn_get_pmkid(struct mesh_rsn *rsn, struct sta_info *sta, u8 *pmkid)
 {
-       /* don't expect wpa auth to cache the pmkid for now */
-       rsn_pmkid(sta->sae->pmk, PMK_LEN, rsn->wpa_s->own_addr,
-                 sta->addr, pmkid,
-                 wpa_key_mgmt_sha256(wpa_auth_sta_key_mgmt(sta->wpa_sm)));
+       os_memcpy(pmkid, sta->sae->pmkid, SAE_PMKID_LEN);
 }
 
 
@@ -340,18 +386,27 @@ mesh_rsn_derive_aek(struct mesh_rsn *rsn, struct sta_info *sta)
 {
        u8 *myaddr = rsn->wpa_s->own_addr;
        u8 *peer = sta->addr;
-       u8 *addr1 = peer, *addr2 = myaddr;
-       u8 context[AES_BLOCK_SIZE];
+       u8 *addr1, *addr2;
+       u8 context[RSN_SELECTOR_LEN + 2 * ETH_ALEN], *ptr = context;
 
-       /* SAE */
-       RSN_SELECTOR_PUT(context, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP));
+       /*
+        * AEK = KDF-Hash-256(PMK, "AEK Derivation", Selected AKM Suite ||
+        *       min(localMAC, peerMAC) || max(localMAC, peerMAC))
+        */
+       /* Selected AKM Suite: SAE */
+       RSN_SELECTOR_PUT(ptr, RSN_AUTH_KEY_MGMT_SAE);
+       ptr += RSN_SELECTOR_LEN;
 
        if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
                addr1 = myaddr;
                addr2 = peer;
+       } else {
+               addr1 = peer;
+               addr2 = myaddr;
        }
-       os_memcpy(context + 4, addr1, ETH_ALEN);
-       os_memcpy(context + 10, addr2, ETH_ALEN);
+       os_memcpy(ptr, addr1, ETH_ALEN);
+       ptr += ETH_ALEN;
+       os_memcpy(ptr, addr2, ETH_ALEN);
 
        sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk), "AEK Derivation",
                   context, sizeof(context), sta->aek, sizeof(sta->aek));
@@ -363,40 +418,44 @@ int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta)
 {
        u8 *ptr;
        u8 *min, *max;
-       u16 min_lid, max_lid;
-       size_t nonce_len = sizeof(sta->my_nonce);
-       size_t lid_len = sizeof(sta->my_lid);
        u8 *myaddr = wpa_s->own_addr;
        u8 *peer = sta->addr;
-       /* 2 nonces, 2 linkids, akm suite, 2 mac addrs */
-       u8 context[64 + 4 + 4 + 12];
-
+       u8 context[2 * WPA_NONCE_LEN + 2 * 2 + RSN_SELECTOR_LEN + 2 * ETH_ALEN];
+
+       /*
+        * MTK = KDF-Hash-Length(PMK, "Temporal Key Derivation", min(localNonce,
+        *  peerNonce) || max(localNonce, peerNonce) || min(localLinkID,
+        *  peerLinkID) || max(localLinkID, peerLinkID) || Selected AKM Suite ||
+        *  min(localMAC, peerMAC) || max(localMAC, peerMAC))
+        */
        ptr = context;
-       if (os_memcmp(sta->my_nonce, sta->peer_nonce, nonce_len) < 0) {
+       if (os_memcmp(sta->my_nonce, sta->peer_nonce, WPA_NONCE_LEN) < 0) {
                min = sta->my_nonce;
                max = sta->peer_nonce;
        } else {
                min = sta->peer_nonce;
                max = sta->my_nonce;
        }
-       os_memcpy(ptr, min, nonce_len);
-       os_memcpy(ptr + nonce_len, max, nonce_len);
-       ptr += 2 * nonce_len;
+       os_memcpy(ptr, min, WPA_NONCE_LEN);
+       ptr += WPA_NONCE_LEN;
+       os_memcpy(ptr, max, WPA_NONCE_LEN);
+       ptr += WPA_NONCE_LEN;
 
        if (sta->my_lid < sta->peer_lid) {
-               min_lid = host_to_le16(sta->my_lid);
-               max_lid = host_to_le16(sta->peer_lid);
+               WPA_PUT_LE16(ptr, sta->my_lid);
+               ptr += 2;
+               WPA_PUT_LE16(ptr, sta->peer_lid);
+               ptr += 2;
        } else {
-               min_lid = host_to_le16(sta->peer_lid);
-               max_lid = host_to_le16(sta->my_lid);
+               WPA_PUT_LE16(ptr, sta->peer_lid);
+               ptr += 2;
+               WPA_PUT_LE16(ptr, sta->my_lid);
+               ptr += 2;
        }
-       os_memcpy(ptr, &min_lid, lid_len);
-       os_memcpy(ptr + lid_len, &max_lid, lid_len);
-       ptr += 2 * lid_len;
 
-       /* SAE */
-       RSN_SELECTOR_PUT(ptr, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP));
-       ptr += 4;
+       /* Selected AKM Suite: SAE */
+       RSN_SELECTOR_PUT(ptr, RSN_AUTH_KEY_MGMT_SAE);
+       ptr += RSN_SELECTOR_LEN;
 
        if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
                min = myaddr;
@@ -406,22 +465,24 @@ int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta)
                max = myaddr;
        }
        os_memcpy(ptr, min, ETH_ALEN);
-       os_memcpy(ptr + ETH_ALEN, max, ETH_ALEN);
+       ptr += ETH_ALEN;
+       os_memcpy(ptr, max, ETH_ALEN);
 
-       sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk),
+       sta->mtk_len = wpa_cipher_key_len(wpa_s->mesh_rsn->pairwise_cipher);
+       sha256_prf(sta->sae->pmk, SAE_PMK_LEN,
                   "Temporal Key Derivation", context, sizeof(context),
-                  sta->mtk, sizeof(sta->mtk));
+                  sta->mtk, sta->mtk_len);
        return 0;
 }
 
 
 void mesh_rsn_init_ampe_sta(struct wpa_supplicant *wpa_s, struct sta_info *sta)
 {
-       if (random_get_bytes(sta->my_nonce, 32) < 0) {
+       if (random_get_bytes(sta->my_nonce, WPA_NONCE_LEN) < 0) {
                wpa_printf(MSG_INFO, "mesh: Failed to derive random nonce");
                /* TODO: How to handle this more cleanly? */
        }
-       os_memset(sta->peer_nonce, 0, 32);
+       os_memset(sta->peer_nonce, 0, WPA_NONCE_LEN);
        mesh_rsn_derive_aek(wpa_s->mesh_rsn, sta);
 }
 
@@ -437,65 +498,94 @@ int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta,
 {
        struct ieee80211_ampe_ie *ampe;
        u8 const *ie = wpabuf_head_u8(buf) + wpabuf_len(buf);
-       u8 *ampe_ie = NULL, *mic_ie = NULL, *mic_payload;
+       u8 *ampe_ie, *pos, *mic_payload;
        const u8 *aad[] = { rsn->wpa_s->own_addr, sta->addr, cat };
        const size_t aad_len[] = { ETH_ALEN, ETH_ALEN, ie - cat };
        int ret = 0;
+       size_t len;
+
+       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 (AES_BLOCK_SIZE + 2 + sizeof(*ampe) + 2 > wpabuf_tailroom(buf)) {
+       if (2 + AES_BLOCK_SIZE + 2 + len > wpabuf_tailroom(buf)) {
                wpa_printf(MSG_ERROR, "protect frame: buffer too small");
                return -EINVAL;
        }
 
-       ampe_ie = os_zalloc(2 + sizeof(*ampe));
+       ampe_ie = os_zalloc(2 + len);
        if (!ampe_ie) {
                wpa_printf(MSG_ERROR, "protect frame: out of memory");
                return -ENOMEM;
        }
 
-       mic_ie = os_zalloc(2 + AES_BLOCK_SIZE);
-       if (!mic_ie) {
-               wpa_printf(MSG_ERROR, "protect frame: out of memory");
-               ret = -ENOMEM;
-               goto free;
-       }
-
        /*  IE: AMPE */
        ampe_ie[0] = WLAN_EID_AMPE;
-       ampe_ie[1] = sizeof(*ampe);
+       ampe_ie[1] = len;
        ampe = (struct ieee80211_ampe_ie *) (ampe_ie + 2);
 
        RSN_SELECTOR_PUT(ampe->selected_pairwise_suite,
-                    wpa_cipher_to_suite(WPA_PROTO_RSN, WPA_CIPHER_CCMP));
-       os_memcpy(ampe->local_nonce, sta->my_nonce, 32);
-       os_memcpy(ampe->peer_nonce, sta->peer_nonce, 32);
-       /* incomplete: see 13.5.4 */
+                        RSN_CIPHER_SUITE_CCMP);
+       os_memcpy(ampe->local_nonce, sta->my_nonce, WPA_NONCE_LEN);
+       os_memcpy(ampe->peer_nonce, sta->peer_nonce, WPA_NONCE_LEN);
+
+       pos = (u8 *) (ampe + 1);
+       if (cat[1] != PLINK_OPEN)
+               goto skip_keys;
+
+       /* TODO: Key Replay Counter[8] optionally for
+        * Mesh Group Key Inform/Acknowledge frames */
+
        /* TODO: static mgtk for now since we don't support rekeying! */
-       os_memcpy(ampe->mgtk, rsn->mgtk, 16);
-       /*  TODO: Populate Key RSC */
-       /*  expire in 13 decades or so */
-       os_memset(ampe->key_expiration, 0xff, 4);
+       /*
+        * GTKdata[variable]:
+        * MGTK[variable] || Key RSC[8] || GTKExpirationTime[4]
+        */
+       os_memcpy(pos, rsn->mgtk, rsn->mgtk_len);
+       pos += rsn->mgtk_len;
+       wpa_drv_get_seqnum(rsn->wpa_s, NULL, rsn->mgtk_key_id, pos);
+       pos += WPA_KEY_RSC_LEN;
+       /* Use fixed GTKExpirationTime for now */
+       WPA_PUT_LE32(pos, 0xffffffff);
+       pos += 4;
+
+#ifdef CONFIG_IEEE80211W
+       /*
+        * IGTKdata[variable]:
+        * Key ID[2], IPN[6], IGTK[variable]
+        */
+       if (rsn->igtk_len) {
+               WPA_PUT_LE16(pos, rsn->igtk_key_id);
+               pos += 2;
+               wpa_drv_get_seqnum(rsn->wpa_s, NULL, rsn->igtk_key_id, pos);
+               pos += 6;
+               os_memcpy(pos, rsn->igtk, rsn->igtk_len);
+       }
+#endif /* CONFIG_IEEE80211W */
+
+skip_keys:
+       wpa_hexdump_key(MSG_DEBUG, "mesh: Plaintext AMPE element",
+                       ampe_ie, 2 + len);
 
        /* IE: MIC */
-       mic_ie[0] = WLAN_EID_MIC;
-       mic_ie[1] = AES_BLOCK_SIZE;
-       wpabuf_put_data(buf, mic_ie, 2);
+       wpabuf_put_u8(buf, WLAN_EID_MIC);
+       wpabuf_put_u8(buf, AES_BLOCK_SIZE);
        /* MIC field is output ciphertext */
 
        /* encrypt after MIC */
-       mic_payload = (u8 *) wpabuf_put(buf, 2 + sizeof(*ampe) +
-                                       AES_BLOCK_SIZE);
+       mic_payload = wpabuf_put(buf, 2 + len + AES_BLOCK_SIZE);
 
-       if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + sizeof(*ampe), 3,
+       if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + len, 3,
                            aad, aad_len, mic_payload)) {
                wpa_printf(MSG_ERROR, "protect frame: failed to encrypt");
                ret = -ENOMEM;
-               goto free;
        }
 
-free:
        os_free(ampe_ie);
-       os_free(mic_ie);
 
        return ret;
 }
@@ -503,18 +593,37 @@ free:
 
 int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
                          struct ieee802_11_elems *elems, const u8 *cat,
+                         const u8 *chosen_pmk,
                          const u8 *start, size_t elems_len)
 {
        int ret = 0;
        struct ieee80211_ampe_ie *ampe;
-       u8 null_nonce[32] = {};
+       u8 null_nonce[WPA_NONCE_LEN] = {};
        u8 ampe_eid;
        u8 ampe_ie_len;
-       u8 *ampe_buf, *crypt = NULL;
+       u8 *ampe_buf, *crypt = NULL, *pos, *end;
        size_t crypt_len;
        const u8 *aad[] = { sta->addr, wpa_s->own_addr, cat };
        const size_t aad_len[] = { ETH_ALEN, ETH_ALEN,
                                   (elems->mic - 2) - cat };
+       size_t key_len;
+
+       if (!sta->sae) {
+               struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+               if (!wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr)) {
+                       wpa_printf(MSG_INFO,
+                                  "Mesh RSN: SAE is not prepared yet");
+                       return -1;
+               }
+               mesh_rsn_auth_sae_sta(wpa_s, sta);
+       }
+
+       if (chosen_pmk && os_memcmp(chosen_pmk, sta->sae->pmkid, PMKID_LEN)) {
+               wpa_msg(wpa_s, MSG_DEBUG,
+                       "Mesh RSN: Invalid PMKID (Chosen PMK did not match calculated PMKID)");
+               return -1;
+       }
 
        if (!elems->mic || elems->mic_len < AES_BLOCK_SIZE) {
                wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing mic ie");
@@ -526,7 +635,7 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
                return -1;
 
        crypt_len = elems_len - (elems->mic - start);
-       if (crypt_len < 2) {
+       if (crypt_len < 2 + AES_BLOCK_SIZE) {
                wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing ampe ie");
                return -1;
        }
@@ -544,14 +653,19 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
        if (aes_siv_decrypt(sta->aek, crypt, crypt_len, 3,
                            aad, aad_len, ampe_buf)) {
                wpa_printf(MSG_ERROR, "Mesh RSN: frame verification failed!");
-               ret = -1;
+               ret = -2;
                goto free;
        }
 
+       crypt_len -= AES_BLOCK_SIZE;
+       wpa_hexdump_key(MSG_DEBUG, "mesh: Decrypted AMPE element",
+                       ampe_buf, crypt_len);
+
        ampe_eid = *ampe_buf++;
        ampe_ie_len = *ampe_buf++;
 
        if (ampe_eid != WLAN_EID_AMPE ||
+           (size_t) 2 + ampe_ie_len > crypt_len ||
            ampe_ie_len < sizeof(struct ieee80211_ampe_ie)) {
                wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid ampe ie");
                ret = -1;
@@ -559,17 +673,89 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
        }
 
        ampe = (struct ieee80211_ampe_ie *) ampe_buf;
-       if (os_memcmp(ampe->peer_nonce, null_nonce, 32) != 0 &&
-           os_memcmp(ampe->peer_nonce, sta->my_nonce, 32) != 0) {
+       pos = (u8 *) (ampe + 1);
+       end = ampe_buf + ampe_ie_len;
+       if (os_memcmp(ampe->peer_nonce, null_nonce, WPA_NONCE_LEN) != 0 &&
+           os_memcmp(ampe->peer_nonce, sta->my_nonce, WPA_NONCE_LEN) != 0) {
                wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid peer nonce");
                ret = -1;
                goto free;
        }
        os_memcpy(sta->peer_nonce, ampe->local_nonce,
                  sizeof(ampe->local_nonce));
-       os_memcpy(sta->mgtk, ampe->mgtk, sizeof(ampe->mgtk));
 
-       /* todo parse mgtk expiration */
+       /* TODO: Key Replay Counter[8] in Mesh Group Key Inform/Acknowledge
+        * frames */
+
+       /*
+        * GTKdata shall not be included in Mesh Peering Confirm. While the
+        * standard does not state the same about IGTKdata, that same constraint
+        * needs to apply for it. It makes no sense to include the keys in Mesh
+        * Peering Close frames either, so while the standard does not seem to
+        * have a shall statement for these, they are described without
+        * mentioning GTKdata.
+        *
+        * An earlier implementation used to add GTKdata to both Mesh Peering
+        * Open and Mesh Peering Confirm frames, so ignore the possibly present
+        * GTKdata frame without rejecting the frame as a backwards
+        * compatibility mechanism.
+        */
+       if (cat[1] != PLINK_OPEN) {
+               if (end > pos) {
+                       wpa_hexdump_key(MSG_DEBUG,
+                                       "mesh: Ignore unexpected GTKdata(etc.) fields in the end of AMPE element in Mesh Peering Confirm/Close",
+                                       pos, end - pos);
+               }
+               goto free;
+       }
+
+       /*
+        * GTKdata[variable]:
+        * MGTK[variable] || Key RSC[8] || GTKExpirationTime[4]
+        */
+       sta->mgtk_key_id = 1; /* FIX: Where to get Key ID? */
+       key_len = wpa_cipher_key_len(wpa_s->mesh_rsn->group_cipher);
+       if ((int) key_len + WPA_KEY_RSC_LEN + 4 > end - pos) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "mesh: Truncated AMPE element");
+               ret = -1;
+               goto free;
+       }
+       sta->mgtk_len = key_len;
+       os_memcpy(sta->mgtk, pos, sta->mgtk_len);
+       wpa_hexdump_key(MSG_DEBUG, "mesh: GTKdata - MGTK",
+                       sta->mgtk, sta->mgtk_len);
+       pos += sta->mgtk_len;
+       wpa_hexdump(MSG_DEBUG, "mesh: GTKdata - MGTK - Key RSC",
+                   pos, WPA_KEY_RSC_LEN);
+       os_memcpy(sta->mgtk_rsc, pos, sizeof(sta->mgtk_rsc));
+       pos += WPA_KEY_RSC_LEN;
+       wpa_printf(MSG_DEBUG,
+                  "mesh: GTKdata - MGTK - GTKExpirationTime: %u seconds",
+                  WPA_GET_LE32(pos));
+       pos += 4;
+
+#ifdef CONFIG_IEEE80211W
+       /*
+        * IGTKdata[variable]:
+        * Key ID[2], IPN[6], IGTK[variable]
+        */
+       key_len = wpa_cipher_key_len(wpa_s->mesh_rsn->mgmt_group_cipher);
+       if (end - pos >= (int) (2 + 6 + key_len)) {
+               sta->igtk_key_id = WPA_GET_LE16(pos);
+               wpa_printf(MSG_DEBUG, "mesh: IGTKdata - Key ID %u",
+                          sta->igtk_key_id);
+               pos += 2;
+               os_memcpy(sta->igtk_rsc, pos, sizeof(sta->igtk_rsc));
+               wpa_hexdump(MSG_DEBUG, "mesh: IGTKdata - IPN",
+                           sta->igtk_rsc, sizeof(sta->igtk_rsc));
+               pos += 6;
+               os_memcpy(sta->igtk, pos, key_len);
+               sta->igtk_len = key_len;
+               wpa_hexdump_key(MSG_DEBUG, "mesh: IGTKdata - IGTK",
+                               sta->igtk, sta->igtk_len);
+       }
+#endif /* CONFIG_IEEE80211W */
+
 free:
        os_free(crypt);
        return ret;
index b1471b2..8775ced 100644 (file)
 struct mesh_rsn {
        struct wpa_supplicant *wpa_s;
        struct wpa_authenticator *auth;
-       u8 mgtk[16];
+       unsigned int pairwise_cipher;
+       unsigned int group_cipher;
+       u8 mgtk[WPA_TK_MAX_LEN];
+       size_t mgtk_len;
+       u8 mgtk_key_id;
+       unsigned int mgmt_group_cipher;
+       u8 igtk_key_id;
+       u8 igtk[WPA_TK_MAX_LEN];
+       size_t igtk_len;
 #ifdef CONFIG_SAE
        struct wpabuf *sae_token;
        int sae_group_index;
@@ -30,6 +38,7 @@ int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta,
                           const u8 *cat, struct wpabuf *buf);
 int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
                          struct ieee802_11_elems *elems, const u8 *cat,
+                         const u8 *chosen_pmk,
                          const u8 *start, size_t elems_len);
 void mesh_auth_timer(void *eloop_ctx, void *user_data);
 
index 45d06bf..67e36ae 100644 (file)
@@ -13,6 +13,7 @@
 #include "config.h"
 #include "wpa_supplicant_i.h"
 #include "wps_supplicant.h"
+#include "binder/binder.h"
 #include "dbus/dbus_common.h"
 #include "dbus/dbus_old.h"
 #include "dbus/dbus_new.h"
@@ -34,6 +35,12 @@ int wpas_notify_supplicant_initialized(struct wpa_global *global)
        }
 #endif /* CONFIG_DBUS */
 
+#ifdef CONFIG_BINDER
+       global->binder = wpas_binder_init(global);
+       if (!global->binder)
+               return -1;
+#endif /* CONFIG_BINDER */
+
        return 0;
 }
 
@@ -44,6 +51,11 @@ void wpas_notify_supplicant_deinitialized(struct wpa_global *global)
        if (global->dbus)
                wpas_dbus_deinit(global->dbus);
 #endif /* CONFIG_DBUS */
+
+#ifdef CONFIG_BINDER
+       if (global->binder)
+               wpas_binder_deinit(global->binder);
+#endif /* CONFIG_BINDER */
 }
 
 
@@ -128,6 +140,15 @@ void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
 }
 
 
+void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->p2p_mgmt)
+               return;
+
+       wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ASSOC_STATUS_CODE);
+}
+
+
 void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
 {
        if (wpa_s->p2p_mgmt)
@@ -647,13 +668,13 @@ void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
 
 
 void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
-                                  struct wpa_ssid *ssid, int network_id,
+                                  struct wpa_ssid *ssid, int persistent,
                                   int client)
 {
        /* Notify a group has been started */
        wpas_dbus_register_p2p_group(wpa_s, ssid);
 
-       wpas_dbus_signal_p2p_group_started(wpa_s, ssid, client, network_id);
+       wpas_dbus_signal_p2p_group_started(wpa_s, client, persistent);
 }
 
 
index d9f0f5a..8cce0f3 100644 (file)
@@ -23,6 +23,7 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
                               enum wpa_states new_state,
                               enum wpa_states old_state);
 void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
+void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s);
 void wpas_notify_network_changed(struct wpa_supplicant *wpa_s);
 void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s);
 void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s);
@@ -112,7 +113,7 @@ void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
                                         u16 config_methods,
                                         unsigned int generated_pin);
 void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
-                                  struct wpa_ssid *ssid, int network_id,
+                                  struct wpa_ssid *ssid, int persistent,
                                   int client);
 void wpas_notify_p2p_group_formation_failure(struct wpa_supplicant *wpa_s,
                                             const char *reason);
index 63af83a..26d41a4 100644 (file)
@@ -23,8 +23,29 @@ wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src)
 {
        struct wpa_supplicant *iface;
 
-       if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0)
+       if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0) {
+#ifdef CONFIG_P2P
+               if (wpa_s->p2p_mgmt && wpa_s != wpa_s->parent &&
+                   wpa_s->parent->ap_iface &&
+                   os_memcmp(wpa_s->parent->own_addr,
+                             wpa_s->own_addr, ETH_ALEN) == 0 &&
+                   wpabuf_len(wpa_s->pending_action_tx) >= 2 &&
+                   *wpabuf_head_u8(wpa_s->pending_action_tx) !=
+                   WLAN_ACTION_PUBLIC) {
+                       /*
+                        * When P2P Device interface has same MAC address as
+                        * the GO interface, make sure non-Public Action frames
+                        * are sent through the GO interface. The P2P Device
+                        * interface can only send Public Action frames.
+                        */
+                       wpa_printf(MSG_DEBUG,
+                                  "P2P: Use GO interface %s instead of interface %s for Action TX",
+                                  wpa_s->parent->ifname, wpa_s->ifname);
+                       return wpa_s->parent;
+               }
+#endif /* CONFIG_P2P */
                return wpa_s;
+       }
 
        /*
         * Try to find a group interface that matches with the source address.
@@ -118,8 +139,9 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
        }
 
        wpa_printf(MSG_DEBUG, "Off-channel: Sending pending Action frame to "
-                  MACSTR " using interface %s",
-                  MAC2STR(wpa_s->pending_action_dst), iface->ifname);
+                  MACSTR " using interface %s (pending_action_tx=%p)",
+                  MAC2STR(wpa_s->pending_action_dst), iface->ifname,
+                  wpa_s->pending_action_tx);
        res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0,
                                  wpa_s->pending_action_dst,
                                  wpa_s->pending_action_src,
@@ -183,8 +205,12 @@ void offchannel_send_action_tx_status(
                return;
        }
 
-       wpa_printf(MSG_DEBUG, "Off-channel: Delete matching pending action frame");
-
+       wpa_printf(MSG_DEBUG,
+                  "Off-channel: Delete matching pending action frame (dst="
+                  MACSTR " pending_action_tx=%p)", MAC2STR(dst),
+                  wpa_s->pending_action_tx);
+       wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
+                       wpa_s->pending_action_tx);
        wpabuf_free(wpa_s->pending_action_tx);
        wpa_s->pending_action_tx = NULL;
 
@@ -250,8 +276,11 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
 
        if (wpa_s->pending_action_tx) {
                wpa_printf(MSG_DEBUG, "Off-channel: Dropped pending Action "
-                          "frame TX to " MACSTR,
-                          MAC2STR(wpa_s->pending_action_dst));
+                          "frame TX to " MACSTR " (pending_action_tx=%p)",
+                          MAC2STR(wpa_s->pending_action_dst),
+                          wpa_s->pending_action_tx);
+               wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
+                               wpa_s->pending_action_tx);
                wpabuf_free(wpa_s->pending_action_tx);
        }
        wpa_s->pending_action_tx_done = 0;
@@ -268,6 +297,12 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
        os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
        wpa_s->pending_action_freq = freq;
        wpa_s->pending_action_no_cck = no_cck;
+       wpa_printf(MSG_DEBUG,
+                  "Off-channel: Stored pending action frame (dst=" MACSTR
+                  " pending_action_tx=%p)",
+                  MAC2STR(dst), wpa_s->pending_action_tx);
+       wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
+                       wpa_s->pending_action_tx);
 
        if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
                struct wpa_supplicant *iface;
@@ -428,6 +463,9 @@ const void * offchannel_pending_action_tx(struct wpa_supplicant *wpa_s)
  */
 void offchannel_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
 {
+       wpa_printf(MSG_DEBUG,
+                  "Off-channel: Clear pending Action frame TX (pending_action_tx=%p",
+                  wpa_s->pending_action_tx);
        wpabuf_free(wpa_s->pending_action_tx);
        wpa_s->pending_action_tx = NULL;
 }
index 78bdd08..b1fdc28 100644 (file)
  */
 #define P2P_GO_FREQ_CHANGE_TIME 5
 
+/**
+ * Defines CSA parameters which are used when GO evacuates the no longer valid
+ * channel (and if the driver supports channel switch).
+ */
+#define P2P_GO_CSA_COUNT 7
+#define P2P_GO_CSA_BLOCK_TX 0
+
 #ifndef P2P_MAX_CLIENT_IDLE
 /*
  * How many seconds to try to reconnect to the GO when connection in P2P client
@@ -117,6 +124,10 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
                         int go);
 static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
                               const u8 *ssid, size_t ssid_len);
+static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
+                               int *force_freq, int *pref_freq, int go,
+                               unsigned int *pref_freq_list,
+                               unsigned int *num_pref_freq);
 static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
                                   const u8 *ssid, size_t ssid_len);
 static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx);
@@ -340,6 +351,7 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
        int social_channels_freq[] = { 2412, 2437, 2462, 60480 };
        size_t ielen;
        u8 *n, i;
+       unsigned int bands;
 
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return -1;
@@ -369,28 +381,6 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
        if (wps_ie == NULL)
                goto fail;
 
-       ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
-       ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
-       if (ies == NULL) {
-               wpabuf_free(wps_ie);
-               goto fail;
-       }
-       wpabuf_put_buf(ies, wps_ie);
-       wpabuf_free(wps_ie);
-
-       p2p_scan_ie(wpa_s->global->p2p, ies, dev_id);
-
-       params->p2p_probe = 1;
-       n = os_malloc(wpabuf_len(ies));
-       if (n == NULL) {
-               wpabuf_free(ies);
-               goto fail;
-       }
-       os_memcpy(n, wpabuf_head(ies), wpabuf_len(ies));
-       params->extra_ies = n;
-       params->extra_ies_len = wpabuf_len(ies);
-       wpabuf_free(ies);
-
        switch (type) {
        case P2P_SCAN_SOCIAL:
                params->freqs = os_calloc(ARRAY_SIZE(social_channels_freq) + 1,
@@ -431,6 +421,29 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
                break;
        }
 
+       ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
+       ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
+       if (ies == NULL) {
+               wpabuf_free(wps_ie);
+               goto fail;
+       }
+       wpabuf_put_buf(ies, wps_ie);
+       wpabuf_free(wps_ie);
+
+       bands = wpas_get_bands(wpa_s, params->freqs);
+       p2p_scan_ie(wpa_s->global->p2p, ies, dev_id, bands);
+
+       params->p2p_probe = 1;
+       n = os_malloc(wpabuf_len(ies));
+       if (n == NULL) {
+               wpabuf_free(ies);
+               goto fail;
+       }
+       os_memcpy(n, wpabuf_head(ies), wpabuf_len(ies));
+       params->extra_ies = n;
+       params->extra_ies_len = wpabuf_len(ies);
+       wpabuf_free(ies);
+
        radio_remove_works(wpa_s, "p2p-scan", 0);
        if (radio_add_work(wpa_s, 0, "p2p-scan", 0, wpas_p2p_trigger_scan_cb,
                           params) < 0)
@@ -538,27 +551,39 @@ static unsigned int p2p_group_go_member_count(struct wpa_supplicant *wpa_s)
 }
 
 
+static unsigned int p2p_is_active_persistent_group(struct wpa_supplicant *wpa_s)
+{
+       return !wpa_s->p2p_mgmt && wpa_s->current_ssid &&
+               !wpa_s->current_ssid->disabled &&
+               wpa_s->current_ssid->p2p_group &&
+               wpa_s->current_ssid->p2p_persistent_group;
+}
+
+
+static unsigned int p2p_is_active_persistent_go(struct wpa_supplicant *wpa_s)
+{
+       return p2p_is_active_persistent_group(wpa_s) &&
+               wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO;
+}
+
+
 /* Find an interface for a P2P group where we are the GO */
 static struct wpa_supplicant *
 wpas_p2p_get_go_group(struct wpa_supplicant *wpa_s)
 {
        struct wpa_supplicant *save = NULL;
-       struct wpa_ssid *s;
 
        if (!wpa_s)
                return NULL;
 
        for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
-               for (s = wpa_s->conf->ssid; s; s = s->next) {
-                       if (s->disabled || !s->p2p_group ||
-                           s->mode != WPAS_MODE_P2P_GO)
-                               continue;
+               if (!p2p_is_active_persistent_go(wpa_s))
+                       continue;
 
-                       /* Prefer a group with connected clients */
-                       if (p2p_get_group_num_members(wpa_s->p2p_group))
-                               return wpa_s;
-                       save = wpa_s;
-               }
+               /* Prefer a group with connected clients */
+               if (p2p_get_group_num_members(wpa_s->p2p_group))
+                       return wpa_s;
+               save = wpa_s;
        }
 
        /* No group with connected clients, so pick the one without (if any) */
@@ -566,29 +591,23 @@ wpas_p2p_get_go_group(struct wpa_supplicant *wpa_s)
 }
 
 
-/* Find an active P2P group where we are the GO */
-static struct wpa_ssid * wpas_p2p_group_go_ssid(struct wpa_supplicant *wpa_s,
-                                               u8 *bssid)
+static unsigned int p2p_is_active_persistent_cli(struct wpa_supplicant *wpa_s)
 {
-       struct wpa_ssid *s, *empty = NULL;
+       return p2p_is_active_persistent_group(wpa_s) &&
+               wpa_s->current_ssid->mode == WPAS_MODE_INFRA;
+}
 
-       if (!wpa_s)
-               return 0;
 
+/* Find an interface for a P2P group where we are the P2P Client */
+static struct wpa_supplicant *
+wpas_p2p_get_cli_group(struct wpa_supplicant *wpa_s)
+{
        for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
-               for (s = wpa_s->conf->ssid; s; s = s->next) {
-                       if (s->disabled || !s->p2p_group ||
-                           s->mode != WPAS_MODE_P2P_GO)
-                               continue;
-
-                       os_memcpy(bssid, wpa_s->own_addr, ETH_ALEN);
-                       if (p2p_get_group_num_members(wpa_s->p2p_group))
-                               return s;
-                       empty = s;
-               }
+               if (p2p_is_active_persistent_cli(wpa_s))
+                       return wpa_s;
        }
 
-       return empty;
+       return NULL;
 }
 
 
@@ -607,20 +626,34 @@ wpas_p2p_get_persistent_go(struct wpa_supplicant *wpa_s)
 }
 
 
-static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
+static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role,
+                               unsigned int *force_freq,
+                               unsigned int *pref_freq)
 {
-       struct wpa_supplicant *wpa_s = ctx, *tmp_wpa_s;
+       struct wpa_supplicant *wpa_s = ctx;
        struct wpa_ssid *s;
        u8 conncap = P2PS_SETUP_NONE;
        unsigned int owned_members = 0;
-       unsigned int owner = 0;
-       unsigned int client = 0;
-       struct wpa_supplicant *go_wpa_s;
+       struct wpa_supplicant *go_wpa_s, *cli_wpa_s;
        struct wpa_ssid *persistent_go;
        int p2p_no_group_iface;
+       unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size;
 
        wpa_printf(MSG_DEBUG, "P2P: Conncap - in:%d role:%d", incoming, role);
 
+       if (force_freq)
+               *force_freq = 0;
+       if (pref_freq)
+               *pref_freq = 0;
+
+       size = P2P_MAX_PREF_CHANNELS;
+       if (force_freq && pref_freq &&
+           !wpas_p2p_setup_freqs(wpa_s, 0, (int *) force_freq,
+                                 (int *) pref_freq, 0, pref_freq_list, &size))
+               wpas_p2p_set_own_freq_preference(wpa_s,
+                                                *force_freq ? *force_freq :
+                                                *pref_freq);
+
        /*
         * For non-concurrent capable devices:
         * If persistent_go, then no new.
@@ -628,36 +661,21 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
         * If client, then no GO.
         */
        go_wpa_s = wpas_p2p_get_go_group(wpa_s);
+       if (go_wpa_s)
+               owned_members = p2p_get_group_num_members(go_wpa_s->p2p_group);
        persistent_go = wpas_p2p_get_persistent_go(wpa_s);
        p2p_no_group_iface = !wpas_p2p_create_iface(wpa_s);
+       cli_wpa_s = wpas_p2p_get_cli_group(wpa_s);
 
-       wpa_printf(MSG_DEBUG, "P2P: GO(iface)=%p persistent(ssid)=%p",
-                  go_wpa_s, persistent_go);
-
-       for (tmp_wpa_s = wpa_s->global->ifaces; tmp_wpa_s;
-            tmp_wpa_s = tmp_wpa_s->next) {
-               for (s = tmp_wpa_s->conf->ssid; s; s = s->next) {
-                       wpa_printf(MSG_DEBUG,
-                                  "P2P: sup:%p ssid:%p disabled:%d p2p:%d mode:%d",
-                                  tmp_wpa_s, s, s->disabled,
-                                  s->p2p_group, s->mode);
-                       if (!s->disabled && s->p2p_group) {
-                               if (s->mode == WPAS_MODE_P2P_GO) {
-                                       owned_members +=
-                                               p2p_get_group_num_members(
-                                                       tmp_wpa_s->p2p_group);
-                                       owner++;
-                               } else
-                                       client++;
-                       }
-               }
-       }
+       wpa_printf(MSG_DEBUG,
+                  "P2P: GO(iface)=%p members=%u CLI(iface)=%p persistent(ssid)=%p",
+                  go_wpa_s, owned_members, cli_wpa_s, persistent_go);
 
        /* If not concurrent, restrict our choices */
        if (p2p_no_group_iface) {
                wpa_printf(MSG_DEBUG, "P2P: p2p_no_group_iface");
 
-               if (client)
+               if (cli_wpa_s)
                        return P2PS_SETUP_NONE;
 
                if (go_wpa_s) {
@@ -689,10 +707,20 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
        /* If a required role has been specified, handle it here */
        if (role && role != P2PS_SETUP_NEW) {
                switch (incoming) {
+               case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
+               case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
+                       /*
+                        * Peer has an active GO, so if the role allows it and
+                        * we do not have any active roles, become client.
+                        */
+                       if ((role & P2PS_SETUP_CLIENT) && !go_wpa_s &&
+                           !cli_wpa_s)
+                               return P2PS_SETUP_CLIENT;
+
+                       /* fall through */
+
                case P2PS_SETUP_NONE:
                case P2PS_SETUP_NEW:
-               case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
-               case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
                        conncap = role;
                        goto grp_owner;
 
@@ -701,7 +729,7 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
                         * Must be a complimentary role - cannot be a client to
                         * more than one peer.
                         */
-                       if (incoming == role || client)
+                       if (incoming == role || cli_wpa_s)
                                return P2PS_SETUP_NONE;
 
                        return P2PS_SETUP_CLIENT;
@@ -727,7 +755,7 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
        switch (incoming) {
        case P2PS_SETUP_NONE:
        case P2PS_SETUP_NEW:
-               if (client)
+               if (cli_wpa_s)
                        conncap = P2PS_SETUP_GROUP_OWNER;
                else if (!owned_members)
                        conncap = P2PS_SETUP_NEW;
@@ -742,13 +770,13 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
                break;
 
        case P2PS_SETUP_GROUP_OWNER:
-               if (!client)
+               if (!cli_wpa_s)
                        conncap = P2PS_SETUP_CLIENT;
                break;
 
        case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
        case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
-               if (client)
+               if (cli_wpa_s)
                        conncap = P2PS_SETUP_GROUP_OWNER;
                else {
                        u8 r;
@@ -770,15 +798,14 @@ grp_owner:
            (!incoming && (conncap & P2PS_SETUP_NEW))) {
                if (go_wpa_s && p2p_client_limit_reached(go_wpa_s->p2p_group))
                        conncap &= ~P2PS_SETUP_GROUP_OWNER;
-               wpa_printf(MSG_DEBUG, "P2P: GOs:%d members:%d conncap:%d",
-                          owner, owned_members, conncap);
 
                s = wpas_p2p_get_persistent_go(wpa_s);
-
-               if (!s && !owner && p2p_no_group_iface) {
+               if (!s && !go_wpa_s && p2p_no_group_iface) {
                        p2p_set_intended_addr(wpa_s->global->p2p,
+                                             wpa_s->p2p_mgmt ?
+                                             wpa_s->parent->own_addr :
                                              wpa_s->own_addr);
-               } else if (!s && !owner) {
+               } else if (!s && !go_wpa_s) {
                        if (wpas_p2p_add_group_interface(wpa_s,
                                                         WPA_IF_P2P_GO) < 0) {
                                wpa_printf(MSG_ERROR,
@@ -850,7 +877,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
 
        if (wpa_s->cross_connect_in_use) {
                wpa_s->cross_connect_in_use = 0;
-               wpa_msg_global(wpa_s->parent, MSG_INFO,
+               wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
                               P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
                               wpa_s->ifname, wpa_s->cross_connect_uplink);
        }
@@ -881,7 +908,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
                break;
        }
        if (removal_reason != P2P_GROUP_REMOVAL_SILENT) {
-               wpa_msg_global(wpa_s->parent, MSG_INFO,
+               wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
                               P2P_EVENT_GROUP_REMOVED "%s %s%s",
                               wpa_s->ifname, gtype, reason);
        }
@@ -891,7 +918,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
        if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
                wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
        if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
-                                wpa_s->parent, NULL) > 0) {
+                                wpa_s->p2pdev, NULL) > 0) {
                wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group formation "
                           "timeout");
                wpa_s->p2p_in_provisioning = 0;
@@ -926,6 +953,12 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
                return 1;
        }
 
+       /*
+        * The primary interface was used for P2P group operations, so
+        * need to reset its p2pdev.
+        */
+       wpa_s->p2pdev = wpa_s->parent;
+
        if (!wpa_s->p2p_go_group_formation_completed) {
                wpa_s->global->p2p_group_formation = NULL;
                wpa_s->p2p_in_provisioning = 0;
@@ -1043,7 +1076,7 @@ static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s,
                   "go_dev_addr=" MACSTR,
                   MAC2STR(bssid), group_capab, MAC2STR(go_dev_addr));
 
-       return group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+       return !!(group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP);
 }
 
 
@@ -1101,7 +1134,8 @@ static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
        s->auth_alg = WPA_AUTH_ALG_OPEN;
        s->key_mgmt = WPA_KEY_MGMT_PSK;
        s->proto = WPA_PROTO_RSN;
-       s->pairwise_cipher = WPA_CIPHER_CCMP;
+       s->pbss = ssid->pbss;
+       s->pairwise_cipher = ssid->pbss ? WPA_CIPHER_GCMP : WPA_CIPHER_CCMP;
        s->export_keys = 1;
        if (ssid->passphrase) {
                os_free(s->passphrase);
@@ -1241,7 +1275,7 @@ static void wpas_p2p_group_started(struct wpa_supplicant *wpa_s,
         * Include PSK/passphrase only in the control interface message and
         * leave it out from the debug log entry.
         */
-       wpa_msg_global_ctrl(wpa_s->parent, MSG_INFO,
+       wpa_msg_global_ctrl(wpa_s->p2pdev, MSG_INFO,
                            P2P_EVENT_GROUP_STARTED
                            "%s %s ssid=\"%s\" freq=%d%s%s%s%s%s go_dev_addr="
                            MACSTR "%s%s",
@@ -1267,7 +1301,6 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
        int client;
        int persistent;
        u8 go_dev_addr[ETH_ALEN];
-       int network_id = -1;
 
        /*
         * This callback is likely called for the main interface. Update wpa_s
@@ -1284,7 +1317,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
        wpa_s->group_formation_reported = 1;
 
        if (!success) {
-               wpa_msg_global(wpa_s->parent, MSG_INFO,
+               wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
                               P2P_EVENT_GROUP_FORMATION_FAILURE);
                wpas_notify_p2p_group_formation_failure(wpa_s, "");
                if (already_deleted)
@@ -1294,7 +1327,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
                return;
        }
 
-       wpa_msg_global(wpa_s->parent, MSG_INFO,
+       wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
                       P2P_EVENT_GROUP_FORMATION_SUCCESS);
 
        ssid = wpa_s->current_ssid;
@@ -1342,16 +1375,15 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
        }
 
        if (persistent)
-               network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
-                                                            ssid, go_dev_addr);
+               wpas_p2p_store_persistent_group(wpa_s->p2pdev,
+                                               ssid, go_dev_addr);
        else {
                os_free(wpa_s->global->add_psk);
                wpa_s->global->add_psk = NULL;
        }
-       if (network_id < 0 && ssid)
-               network_id = ssid->id;
+
        if (!client) {
-               wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+               wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 0);
                os_get_reltime(&wpa_s->global->p2p_go_wait_client);
        }
 }
@@ -1368,6 +1400,25 @@ struct send_action_work {
 };
 
 
+static void wpas_p2p_free_send_action_work(struct wpa_supplicant *wpa_s)
+{
+       struct send_action_work *awork = wpa_s->p2p_send_action_work->ctx;
+
+       wpa_printf(MSG_DEBUG,
+                  "P2P: Free Action frame radio work @%p (freq=%u dst="
+                  MACSTR " src=" MACSTR " bssid=" MACSTR " wait_time=%u)",
+                  wpa_s->p2p_send_action_work, awork->freq,
+                  MAC2STR(awork->dst), MAC2STR(awork->src),
+                  MAC2STR(awork->bssid), awork->wait_time);
+       wpa_hexdump(MSG_DEBUG, "P2P: Freeing pending Action frame",
+                   awork->buf, awork->len);
+       os_free(awork);
+       wpa_s->p2p_send_action_work->ctx = NULL;
+       radio_work_done(wpa_s->p2p_send_action_work);
+       wpa_s->p2p_send_action_work = NULL;
+}
+
+
 static void wpas_p2p_send_action_work_timeout(void *eloop_ctx,
                                              void *timeout_ctx)
 {
@@ -1377,9 +1428,7 @@ static void wpas_p2p_send_action_work_timeout(void *eloop_ctx,
                return;
 
        wpa_printf(MSG_DEBUG, "P2P: Send Action frame radio work timed out");
-       os_free(wpa_s->p2p_send_action_work->ctx);
-       radio_work_done(wpa_s->p2p_send_action_work);
-       wpa_s->p2p_send_action_work = NULL;
+       wpas_p2p_free_send_action_work(wpa_s);
 }
 
 
@@ -1387,11 +1436,13 @@ static void wpas_p2p_action_tx_clear(struct wpa_supplicant *wpa_s)
 {
        if (wpa_s->p2p_send_action_work) {
                struct send_action_work *awork;
+
                awork = wpa_s->p2p_send_action_work->ctx;
+               wpa_printf(MSG_DEBUG,
+                          "P2P: Clear Action TX work @%p (wait_time=%u)",
+                          wpa_s->p2p_send_action_work, awork->wait_time);
                if (awork->wait_time == 0) {
-                       os_free(awork);
-                       radio_work_done(wpa_s->p2p_send_action_work);
-                       wpa_s->p2p_send_action_work = NULL;
+                       wpas_p2p_free_send_action_work(wpa_s);
                } else {
                        /*
                         * In theory, this should not be needed, but number of
@@ -1447,7 +1498,7 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
                wpa_s->pending_pd_before_join = 0;
                wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
                        "during p2p_connect-auto");
-               wpa_msg_global(wpa_s->parent, MSG_INFO,
+               wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
                               P2P_EVENT_FALLBACK_TO_GO_NEG
                               "reason=no-ACK-to-PD-Req");
                wpas_p2p_fallback_to_go_neg(wpa_s, 0);
@@ -1590,11 +1641,11 @@ static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
        } else if (res->wps_method == WPS_NFC) {
                wpas_wps_start_nfc(wpa_s, res->peer_device_addr,
                                   res->peer_interface_addr,
-                                  wpa_s->parent->p2p_oob_dev_pw,
-                                  wpa_s->parent->p2p_oob_dev_pw_id, 1,
-                                  wpa_s->parent->p2p_oob_dev_pw_id ==
+                                  wpa_s->p2pdev->p2p_oob_dev_pw,
+                                  wpa_s->p2pdev->p2p_oob_dev_pw_id, 1,
+                                  wpa_s->p2pdev->p2p_oob_dev_pw_id ==
                                   DEV_PW_NFC_CONNECTION_HANDOVER ?
-                                  wpa_s->parent->p2p_peer_oob_pubkey_hash :
+                                  wpa_s->p2pdev->p2p_peer_oob_pubkey_hash :
                                   NULL,
                                   NULL, 0, 0);
 #endif /* CONFIG_WPS_NFC */
@@ -1620,7 +1671,7 @@ static void wpas_p2p_add_psk_list(struct wpa_supplicant *wpa_s,
        if (!wpa_s->ap_iface)
                return;
 
-       persistent = wpas_p2p_get_persistent(wpa_s->parent, NULL, ssid->ssid,
+       persistent = wpas_p2p_get_persistent(wpa_s->p2pdev, NULL, ssid->ssid,
                                             ssid->ssid_len);
        if (persistent == NULL)
                return;
@@ -1685,8 +1736,8 @@ static void p2p_go_save_group_common_freqs(struct wpa_supplicant *wpa_s,
 static void p2p_config_write(struct wpa_supplicant *wpa_s)
 {
 #ifndef CONFIG_NO_CONFIG_WRITE
-       if (wpa_s->parent->conf->update_config &&
-           wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+       if (wpa_s->p2pdev->conf->update_config &&
+           wpa_config_write(wpa_s->p2pdev->confname, wpa_s->p2pdev->conf))
                wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
 #endif /* CONFIG_NO_CONFIG_WRITE */
 }
@@ -1697,7 +1748,15 @@ static void p2p_go_configured(void *ctx, void *data)
        struct wpa_supplicant *wpa_s = ctx;
        struct p2p_go_neg_results *params = data;
        struct wpa_ssid *ssid;
-       int network_id = -1;
+
+       wpa_s->ap_configured_cb = NULL;
+       wpa_s->ap_configured_cb_ctx = NULL;
+       wpa_s->ap_configured_cb_data = NULL;
+       if (!wpa_s->go_params) {
+               wpa_printf(MSG_ERROR,
+                          "P2P: p2p_go_configured() called with wpa_s->go_params == NULL");
+               return;
+       }
 
        p2p_go_save_group_common_freqs(wpa_s, params);
        p2p_go_dump_common_freqs(wpa_s);
@@ -1715,8 +1774,8 @@ static void p2p_go_configured(void *ctx, void *data)
                                       params->persistent_group, "");
                wpa_s->group_formation_reported = 1;
 
-               if (wpa_s->parent->p2ps_method_config_any) {
-                       if (is_zero_ether_addr(wpa_s->parent->p2ps_join_addr)) {
+               if (wpa_s->p2pdev->p2ps_method_config_any) {
+                       if (is_zero_ether_addr(wpa_s->p2pdev->p2ps_join_addr)) {
                                wpa_dbg(wpa_s, MSG_DEBUG,
                                        "P2PS: Setting default PIN for ANY");
                                wpa_supplicant_ap_wps_pin(wpa_s, NULL,
@@ -1725,24 +1784,24 @@ static void p2p_go_configured(void *ctx, void *data)
                        } else {
                                wpa_dbg(wpa_s, MSG_DEBUG,
                                        "P2PS: Setting default PIN for " MACSTR,
-                                       MAC2STR(wpa_s->parent->p2ps_join_addr));
+                                       MAC2STR(wpa_s->p2pdev->p2ps_join_addr));
                                wpa_supplicant_ap_wps_pin(
-                                       wpa_s, wpa_s->parent->p2ps_join_addr,
+                                       wpa_s, wpa_s->p2pdev->p2ps_join_addr,
                                        "12345670", NULL, 0, 0);
                        }
-                       wpa_s->parent->p2ps_method_config_any = 0;
+                       wpa_s->p2pdev->p2ps_method_config_any = 0;
                }
 
                os_get_reltime(&wpa_s->global->p2p_go_wait_client);
                if (params->persistent_group) {
-                       network_id = wpas_p2p_store_persistent_group(
-                               wpa_s->parent, ssid,
+                       wpas_p2p_store_persistent_group(
+                               wpa_s->p2pdev, ssid,
                                wpa_s->global->p2p_dev_addr);
                        wpas_p2p_add_psk_list(wpa_s, ssid);
                }
-               if (network_id < 0)
-                       network_id = ssid->id;
-               wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+
+               wpas_notify_p2p_group_started(wpa_s, ssid,
+                                             params->persistent_group, 0);
                wpas_p2p_cross_connect_setup(wpa_s);
                wpas_p2p_set_group_idle_timeout(wpa_s);
 
@@ -1753,11 +1812,11 @@ static void p2p_go_configured(void *ctx, void *data)
                        wpa_s->p2p_go_group_formation_completed = 0;
                        wpa_s->global->p2p_group_formation = wpa_s;
                        eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
-                                            wpa_s->parent, NULL);
+                                            wpa_s->p2pdev, NULL);
                        eloop_register_timeout(
                                wpa_s->p2p_first_connection_timeout, 0,
                                wpas_p2p_group_formation_timeout,
-                               wpa_s->parent, NULL);
+                               wpa_s->p2pdev, NULL);
                }
 
                return;
@@ -1775,17 +1834,17 @@ static void p2p_go_configured(void *ctx, void *data)
                                          params->peer_device_addr);
 #ifdef CONFIG_WPS_NFC
        } else if (params->wps_method == WPS_NFC) {
-               if (wpa_s->parent->p2p_oob_dev_pw_id !=
+               if (wpa_s->p2pdev->p2p_oob_dev_pw_id !=
                    DEV_PW_NFC_CONNECTION_HANDOVER &&
-                   !wpa_s->parent->p2p_oob_dev_pw) {
+                   !wpa_s->p2pdev->p2p_oob_dev_pw) {
                        wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known");
                        return;
                }
                wpas_ap_wps_add_nfc_pw(
-                       wpa_s, wpa_s->parent->p2p_oob_dev_pw_id,
-                       wpa_s->parent->p2p_oob_dev_pw,
-                       wpa_s->parent->p2p_peer_oob_pk_hash_known ?
-                       wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL);
+                       wpa_s, wpa_s->p2pdev->p2p_oob_dev_pw_id,
+                       wpa_s->p2pdev->p2p_oob_dev_pw,
+                       wpa_s->p2pdev->p2p_peer_oob_pk_hash_known ?
+                       wpa_s->p2pdev->p2p_peer_oob_pubkey_hash : NULL);
 #endif /* CONFIG_WPS_NFC */
        } else if (wpa_s->p2p_pin[0])
                wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
@@ -1822,12 +1881,14 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
        wpa_config_set_network_defaults(ssid);
        ssid->temporary = 1;
        ssid->p2p_group = 1;
-       ssid->p2p_persistent_group = params->persistent_group;
+       ssid->p2p_persistent_group = !!params->persistent_group;
        ssid->mode = group_formation ? WPAS_MODE_P2P_GROUP_FORMATION :
                WPAS_MODE_P2P_GO;
        ssid->frequency = params->freq;
        ssid->ht40 = params->ht40;
        ssid->vht = params->vht;
+       ssid->max_oper_chwidth = params->max_oper_chwidth;
+       ssid->vht_center_freq2 = params->vht_center_freq2;
        ssid->ssid = os_zalloc(params->ssid_len + 1);
        if (ssid->ssid) {
                os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
@@ -1845,6 +1906,8 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
                 */
                ssid->pairwise_cipher = WPA_CIPHER_GCMP;
                ssid->group_cipher = WPA_CIPHER_GCMP;
+               /* P2P GO in 60 GHz is always a PCP (PBSS) */
+               ssid->pbss = 1;
        }
        if (os_strlen(params->passphrase) > 0) {
                ssid->passphrase = os_strdup(params->passphrase);
@@ -1861,7 +1924,7 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
                os_memcpy(ssid->psk, params->psk, sizeof(ssid->psk));
        else if (ssid->passphrase)
                wpa_config_update_psk(ssid);
-       ssid->ap_max_inactivity = wpa_s->parent->conf->p2p_go_max_inactivity;
+       ssid->ap_max_inactivity = wpa_s->p2pdev->conf->p2p_go_max_inactivity;
 
        wpa_s->ap_configured_cb = p2p_go_configured;
        wpa_s->ap_configured_cb_ctx = wpa_s;
@@ -1885,7 +1948,12 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
        d = dst->conf;
        s = src->conf;
 
-#define C(n) if (s->n) d->n = os_strdup(s->n)
+#define C(n)                            \
+do {                                    \
+       if (s->n && !d->n)              \
+               d->n = os_strdup(s->n); \
+} while (0)
+
        C(device_name);
        C(manufacturer);
        C(model_name);
@@ -1913,7 +1981,10 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
        d->disable_scan_offload = s->disable_scan_offload;
        d->passive_scan = s->passive_scan;
 
-       if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey) {
+       if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey &&
+           !d->wps_nfc_pw_from_config) {
+               wpabuf_free(d->wps_nfc_dh_privkey);
+               wpabuf_free(d->wps_nfc_dh_pubkey);
                d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey);
                d->wps_nfc_dh_pubkey = wpabuf_dup(s->wps_nfc_dh_pubkey);
        }
@@ -2071,7 +2142,7 @@ static void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s,
                                            int already_deleted)
 {
        eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
-                            wpa_s->parent, NULL);
+                            wpa_s->p2pdev, NULL);
        if (wpa_s->global->p2p)
                p2p_group_formation_failed(wpa_s->global->p2p);
        wpas_group_formation_completed(wpa_s, 0, already_deleted);
@@ -2082,9 +2153,9 @@ static void wpas_p2p_grpform_fail_after_wps(struct wpa_supplicant *wpa_s)
 {
        wpa_printf(MSG_DEBUG, "P2P: Reject group formation due to WPS provisioning failure");
        eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
-                            wpa_s->parent, NULL);
+                            wpa_s->p2pdev, NULL);
        eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
-                              wpa_s->parent, NULL);
+                              wpa_s->p2pdev, NULL);
        wpa_s->global->p2p_fail_on_wps_complete = 0;
 }
 
@@ -2095,15 +2166,16 @@ void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s)
                return;
        /* Speed up group formation timeout since this cannot succeed */
        eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
-                            wpa_s->parent, NULL);
+                            wpa_s->p2pdev, NULL);
        eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
-                              wpa_s->parent, NULL);
+                              wpa_s->p2pdev, NULL);
 }
 
 
 static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
 {
        struct wpa_supplicant *wpa_s = ctx;
+       struct wpa_supplicant *group_wpa_s;
 
        if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
                wpa_drv_cancel_remain_on_channel(wpa_s);
@@ -2129,6 +2201,8 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
                res->ht40 = 1;
        if (wpa_s->p2p_go_vht)
                res->vht = 1;
+       res->max_oper_chwidth = wpa_s->p2p_go_max_oper_chwidth;
+       res->vht_center_freq2 = wpa_s->p2p_go_vht_center_freq2;
 
        wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS "role=%s "
                       "freq=%d ht40=%d peer_dev=" MACSTR " peer_iface=" MACSTR
@@ -2154,7 +2228,7 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
        }
 
        if (wpa_s->create_p2p_iface) {
-               struct wpa_supplicant *group_wpa_s =
+               group_wpa_s =
                        wpas_p2p_init_group_interface(wpa_s, res->role_go);
                if (group_wpa_s == NULL) {
                        wpas_p2p_remove_pending_group_interface(wpa_s);
@@ -2163,31 +2237,27 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
                        wpas_p2p_group_formation_failed(wpa_s, 1);
                        return;
                }
-               if (group_wpa_s != wpa_s) {
-                       os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin,
-                                 sizeof(group_wpa_s->p2p_pin));
-                       group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method;
-               }
                os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN);
                wpa_s->pending_interface_name[0] = '\0';
-               group_wpa_s->p2p_in_provisioning = 1;
-
-               if (res->role_go) {
-                       wpas_start_wps_go(group_wpa_s, res, 1);
-               } else {
-                       os_get_reltime(&group_wpa_s->scan_min_time);
-                       wpas_start_wps_enrollee(group_wpa_s, res);
-               }
        } else {
-               wpa_s->p2p_in_provisioning = 1;
-               wpa_s->global->p2p_group_formation = wpa_s;
+               group_wpa_s = wpa_s->parent;
+               wpa_s->global->p2p_group_formation = group_wpa_s;
+               if (group_wpa_s != wpa_s)
+                       wpas_p2p_clone_config(group_wpa_s, wpa_s);
+       }
 
-               if (res->role_go) {
-                       wpas_start_wps_go(wpa_s, res, 1);
-               } else {
-                       os_get_reltime(&wpa_s->scan_min_time);
-                       wpas_start_wps_enrollee(ctx, res);
-               }
+       group_wpa_s->p2p_in_provisioning = 1;
+       group_wpa_s->p2pdev = wpa_s;
+       if (group_wpa_s != wpa_s) {
+               os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin,
+                         sizeof(group_wpa_s->p2p_pin));
+               group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method;
+       }
+       if (res->role_go) {
+               wpas_start_wps_go(group_wpa_s, res, 1);
+       } else {
+               os_get_reltime(&group_wpa_s->scan_min_time);
+               wpas_start_wps_enrollee(group_wpa_s, res);
        }
 
        wpa_s->p2p_long_listen = 0;
@@ -2308,6 +2378,10 @@ static void wpas_dev_lost(void *ctx, const u8 *dev_addr)
 static void wpas_find_stopped(void *ctx)
 {
        struct wpa_supplicant *wpa_s = ctx;
+
+       if (wpa_s->p2p_scan_work && wpas_abort_ongoing_scan(wpa_s) < 0)
+               wpa_printf(MSG_DEBUG, "P2P: Abort ongoing scan failed");
+
        wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_FIND_STOPPED);
        wpas_notify_p2p_find_stopped(wpa_s);
 }
@@ -2521,7 +2595,13 @@ static void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
        params[sizeof(params) - 1] = '\0';
 
        if (config_methods & WPS_CONFIG_DISPLAY) {
-               generated_pin = wps_generate_pin();
+               if (wps_generate_pin(&generated_pin) < 0) {
+                       wpa_printf(MSG_DEBUG, "P2P: Could not generate PIN");
+                       wpas_notify_p2p_provision_discovery(
+                               wpa_s, peer, 0 /* response */,
+                               P2P_PROV_DISC_INFO_UNAVAILABLE, 0, 0);
+                       return;
+               }
                wpas_prov_disc_local_display(wpa_s, peer, params,
                                             generated_pin);
        } else if (config_methods & WPS_CONFIG_KEYPAD)
@@ -2566,7 +2646,13 @@ static void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
        if (config_methods & WPS_CONFIG_DISPLAY)
                wpas_prov_disc_local_keypad(wpa_s, peer, params);
        else if (config_methods & WPS_CONFIG_KEYPAD) {
-               generated_pin = wps_generate_pin();
+               if (wps_generate_pin(&generated_pin) < 0) {
+                       wpa_printf(MSG_DEBUG, "P2P: Could not generate PIN");
+                       wpas_notify_p2p_provision_discovery(
+                               wpa_s, peer, 0 /* response */,
+                               P2P_PROV_DISC_INFO_UNAVAILABLE, 0, 0);
+                       return;
+               }
                wpas_prov_disc_local_display(wpa_s, peer, params,
                                             generated_pin);
        } else if (config_methods & WPS_CONFIG_PUSHBUTTON)
@@ -2589,7 +2675,7 @@ static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
        if (wpa_s->p2p_fallback_to_go_neg) {
                wpa_dbg(wpa_s, MSG_DEBUG, "P2P: PD for p2p_connect-auto "
                        "failed - fall back to GO Negotiation");
-               wpa_msg_global(wpa_s->parent, MSG_INFO,
+               wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
                               P2P_EVENT_FALLBACK_TO_GO_NEG
                               "reason=PD-failed");
                wpas_p2p_fallback_to_go_neg(wpa_s, 0);
@@ -2685,6 +2771,29 @@ static int wpas_p2p_go_is_peer_freq(struct wpa_supplicant *wpa_s, int freq)
 }
 
 
+static int wpas_sta_check_ecsa(struct hostapd_data *hapd,
+                              struct sta_info *sta, void *ctx)
+{
+       int *ecsa_support = ctx;
+
+       *ecsa_support &= sta->ecsa_supported;
+
+       return 0;
+}
+
+
+/* Check if all the peers support eCSA */
+static int wpas_p2p_go_clients_support_ecsa(struct wpa_supplicant *wpa_s)
+{
+       int ecsa_support = 1;
+
+       ap_for_each_sta(wpa_s->ap_iface->bss[0], wpas_sta_check_ecsa,
+                       &ecsa_support);
+
+       return ecsa_support;
+}
+
+
 /**
  * Pick the best frequency to use from all the currently used frequencies.
  */
@@ -2811,7 +2920,11 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
                                   "invitation");
                        return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
                }
-               os_memcpy(group_bssid, wpa_s->own_addr, ETH_ALEN);
+               if (wpa_s->p2p_mgmt)
+                       os_memcpy(group_bssid, wpa_s->parent->own_addr,
+                                 ETH_ALEN);
+               else
+                       os_memcpy(group_bssid, wpa_s->own_addr, ETH_ALEN);
        } else if (s->mode == WPAS_MODE_P2P_GO) {
                *go = 1;
                if (wpas_p2p_add_group_interface(wpa_s, WPA_IF_P2P_GO) < 0)
@@ -2893,12 +3006,31 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
                           MAC2STR(sa), op_freq, wpa_ssid_txt(ssid, ssid_len));
                if (s) {
                        int go = s->mode == WPAS_MODE_P2P_GO;
+                       if (go) {
+                               wpa_msg_global(wpa_s, MSG_INFO,
+                                              P2P_EVENT_INVITATION_ACCEPTED
+                                              "sa=" MACSTR
+                                              " persistent=%d freq=%d",
+                                              MAC2STR(sa), s->id, op_freq);
+                       } else {
+                               wpa_msg_global(wpa_s, MSG_INFO,
+                                              P2P_EVENT_INVITATION_ACCEPTED
+                                              "sa=" MACSTR
+                                              " persistent=%d",
+                                              MAC2STR(sa), s->id);
+                       }
                        wpas_p2p_group_add_persistent(
-                               wpa_s, s, go, 0, op_freq, 0, 0, NULL,
+                               wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, NULL,
                                go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0,
                                1);
                } else if (bssid) {
                        wpa_s->user_initiated_pd = 0;
+                       wpa_msg_global(wpa_s, MSG_INFO,
+                                      P2P_EVENT_INVITATION_ACCEPTED
+                                      "sa=" MACSTR " go_dev_addr=" MACSTR
+                                      " bssid=" MACSTR " unknown-network",
+                                      MAC2STR(sa), MAC2STR(go_dev_addr),
+                                      MAC2STR(bssid));
                        wpas_p2p_join(wpa_s, bssid, go_dev_addr,
                                      wpa_s->p2p_wps_method, 0, op_freq,
                                      ssid, ssid_len);
@@ -2999,7 +3131,7 @@ static void wpas_remove_persistent_client(struct wpa_supplicant *wpa_s,
        if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
            !ssid->p2p_persistent_group)
                return; /* Not operating as a GO in persistent group */
-       ssid = wpas_p2p_get_persistent(wpa_s->parent, peer,
+       ssid = wpas_p2p_get_persistent(wpa_s->p2pdev, peer,
                                       ssid->ssid, ssid->ssid_len);
        wpas_remove_persistent_peer(wpa_s, ssid, peer, 1);
 }
@@ -3027,9 +3159,37 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
        wpa_printf(MSG_DEBUG, "P2P: Invitation result - status=%d peer=" MACSTR,
                   status, MAC2STR(peer));
        if (wpa_s->pending_invite_ssid_id == -1) {
+               struct wpa_supplicant *group_if =
+                       wpa_s->global->p2p_invite_group;
+
                if (status == P2P_SC_FAIL_UNKNOWN_GROUP)
                        wpas_remove_persistent_client(wpa_s, peer);
-               return; /* Invitation to active group */
+
+               /*
+                * Invitation to an active group. If this is successful and we
+                * are the GO, set the client wait to postpone some concurrent
+                * operations and to allow provisioning and connection to happen
+                * more quickly.
+                */
+               if (status == P2P_SC_SUCCESS &&
+                   group_if && group_if->current_ssid &&
+                   group_if->current_ssid->mode == WPAS_MODE_P2P_GO) {
+                       os_get_reltime(&wpa_s->global->p2p_go_wait_client);
+#ifdef CONFIG_TESTING_OPTIONS
+                       if (group_if->p2p_go_csa_on_inv) {
+                               wpa_printf(MSG_DEBUG,
+                                          "Testing: force P2P GO CSA after invitation");
+                               eloop_cancel_timeout(
+                                       wpas_p2p_reconsider_moving_go,
+                                       wpa_s, NULL);
+                               eloop_register_timeout(
+                                       0, 50000,
+                                       wpas_p2p_reconsider_moving_go,
+                                       wpa_s, NULL);
+                       }
+#endif /* CONFIG_TESTING_OPTIONS */
+               }
+               return;
        }
 
        if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
@@ -3083,7 +3243,9 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
                                      ssid->mode == WPAS_MODE_P2P_GO,
                                      wpa_s->p2p_persistent_go_freq,
                                      freq,
+                                     wpa_s->p2p_go_vht_center_freq2,
                                      wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
+                                     wpa_s->p2p_go_max_oper_chwidth,
                                      channels,
                                      ssid->mode == WPAS_MODE_P2P_GO ?
                                      P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
@@ -3169,21 +3331,6 @@ static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
 }
 
 
-static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
-                                         u16 num_modes,
-                                         enum hostapd_hw_mode mode)
-{
-       u16 i;
-
-       for (i = 0; i < num_modes; i++) {
-               if (modes[i].mode == mode)
-                       return &modes[i];
-       }
-
-       return NULL;
-}
-
-
 enum chan_allowed {
        NOT_ALLOWED, NO_IR, ALLOWED
 };
@@ -3217,49 +3364,12 @@ static int has_channel(struct wpa_global *global,
 }
 
 
-struct p2p_oper_class_map {
-       enum hostapd_hw_mode mode;
-       u8 op_class;
-       u8 min_chan;
-       u8 max_chan;
-       u8 inc;
-       enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160 } bw;
-};
-
-static const struct p2p_oper_class_map op_class[] = {
-       { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 },
-#if 0 /* Do not enable HT40 on 2 GHz for now */
-       { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS },
-       { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS },
-#endif
-       { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 },
-       { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20 },
-       { HOSTAPD_MODE_IEEE80211A, 125, 149, 169, 4, BW20 },
-       { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS },
-       { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
-       { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
-       { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
-
-       /*
-        * 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
-        * (these center frequencies are not actual channels, which makes
-        * has_channel() fail). wpas_p2p_verify_80mhz() should take care of
-        * removing invalid channels.
-        */
-       { HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80 },
-       { HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160 },
-       { -1, 0, 0, 0, 0, BW20 }
-};
-
-
 static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s,
                                     struct hostapd_hw_modes *mode,
                                     u8 channel)
 {
        u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
-       unsigned int i;
+       size_t i;
 
        if (mode->mode != HOSTAPD_MODE_IEEE80211A)
                return 0;
@@ -3315,6 +3425,75 @@ 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 center_channels[] = { 50, 114 };
+       unsigned int i;
+
+       if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+               return 0;
+
+       for (i = 0; i < ARRAY_SIZE(center_channels); 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.
+                */
+               if (channel >= center_channels[i] - 14 &&
+                   channel <= center_channels[i] + 14)
+                       return center_channels[i];
+
+       return 0;
+}
+
+
+static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s,
+                                              struct hostapd_hw_modes *mode,
+                                              u8 channel, u8 bw)
+{
+       u8 center_chan;
+       int i, flags;
+       enum chan_allowed res, ret = ALLOWED;
+
+       center_chan = wpas_p2p_get_center_160mhz(wpa_s, mode, channel);
+       if (!center_chan)
+               return NOT_ALLOWED;
+       /* VHT 160 MHz uses DFS channels in most countries. */
+
+       /* Check all the channels are available */
+       for (i = 0; i < 8; i++) {
+               int adj_chan = center_chan - 14 + i * 4;
+
+               res = has_channel(wpa_s->global, mode, adj_chan, &flags);
+               if (res == NOT_ALLOWED)
+                       return NOT_ALLOWED;
+
+               if (res == NO_IR)
+                       ret = NO_IR;
+
+               if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150))
+                       return NOT_ALLOWED;
+               if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130))
+                       return NOT_ALLOWED;
+               if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110))
+                       return NOT_ALLOWED;
+               if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90))
+                       return NOT_ALLOWED;
+               if (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70))
+                       return NOT_ALLOWED;
+               if (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50))
+                       return NOT_ALLOWED;
+               if (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30))
+                       return NOT_ALLOWED;
+               if (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10))
+                       return NOT_ALLOWED;
+       }
+
+       return ret;
+}
+
+
 static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
                                                 struct hostapd_hw_modes *mode,
                                                 u8 channel, u8 bw)
@@ -3333,6 +3512,8 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
                res2 = has_channel(wpa_s->global, mode, channel + 4, NULL);
        } else if (bw == BW80) {
                res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw);
+       } else if (bw == BW160) {
+               res2 = wpas_p2p_verify_160mhz(wpa_s, mode, channel, bw);
        }
 
        if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -3359,11 +3540,14 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
 
        cla = cli_cla = 0;
 
-       for (op = 0; op_class[op].op_class; op++) {
-               const struct p2p_oper_class_map *o = &op_class[op];
+       for (op = 0; global_op_class[op].op_class; op++) {
+               const struct oper_class_map *o = &global_op_class[op];
                u8 ch;
                struct p2p_reg_class *reg = NULL, *cli_reg = NULL;
 
+               if (o->p2p == NO_P2P_SUPP)
+                       continue;
+
                mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
                if (mode == NULL)
                        continue;
@@ -3418,10 +3602,13 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
        int op;
        enum chan_allowed ret;
 
-       for (op = 0; op_class[op].op_class; op++) {
-               const struct p2p_oper_class_map *o = &op_class[op];
+       for (op = 0; global_op_class[op].op_class; op++) {
+               const struct oper_class_map *o = &global_op_class[op];
                u8 ch;
 
+               if (o->p2p == NO_P2P_SUPP)
+                       continue;
+
                for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
                        if (o->mode != HOSTAPD_MODE_IEEE80211A ||
                            (o->bw != BW40PLUS && o->bw != BW40MINUS) ||
@@ -3446,6 +3633,15 @@ int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
 }
 
 
+int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s,
+                              struct hostapd_hw_modes *mode, u8 channel)
+{
+       if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW160))
+               return 0;
+       return wpas_p2p_get_center_160mhz(wpa_s, mode, channel);
+}
+
+
 static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
                        size_t buf_len)
 {
@@ -3577,6 +3773,7 @@ int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
+       p2pdev_wpa_s->p2pdev = p2pdev_wpa_s;
        wpa_s->pending_interface_name[0] = '\0';
        return 0;
 }
@@ -3638,11 +3835,12 @@ static int wpas_get_persistent_group(void *ctx, const u8 *addr, const u8 *ssid,
 
 
 static int wpas_get_go_info(void *ctx, u8 *intended_addr,
-                           u8 *ssid, size_t *ssid_len, int *group_iface)
+                           u8 *ssid, size_t *ssid_len, int *group_iface,
+                           unsigned int *freq)
 {
        struct wpa_supplicant *wpa_s = ctx;
+       struct wpa_supplicant *go;
        struct wpa_ssid *s;
-       u8 bssid[ETH_ALEN];
 
        /*
         * group_iface will be set to 1 only if a dedicated interface for P2P
@@ -3652,17 +3850,25 @@ static int wpas_get_go_info(void *ctx, u8 *intended_addr,
         * that the pending interface should be used.
         */
        *group_iface = 0;
-       s = wpas_p2p_group_go_ssid(wpa_s, bssid);
-       if (!s) {
+
+       if (freq)
+               *freq = 0;
+
+       go = wpas_p2p_get_go_group(wpa_s);
+       if (!go) {
                s = wpas_p2p_get_persistent_go(wpa_s);
                *group_iface = wpas_p2p_create_iface(wpa_s);
                if (s)
-                       os_memcpy(bssid, s->bssid, ETH_ALEN);
+                       os_memcpy(intended_addr, s->bssid, ETH_ALEN);
                else
                        return 0;
+       } else {
+               s = go->current_ssid;
+               os_memcpy(intended_addr, go->own_addr, ETH_ALEN);
+               if (freq)
+                       *freq = go->assoc_freq;
        }
 
-       os_memcpy(intended_addr, bssid, ETH_ALEN);
        os_memcpy(ssid, s->ssid, s->ssid_len);
        *ssid_len = s->ssid_len;
 
@@ -3750,11 +3956,13 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
                                    const u8 *persist_ssid,
                                    size_t persist_ssid_size, int response_done,
                                    int prov_start, const char *session_info,
-                                   const u8 *feat_cap, size_t feat_cap_len)
+                                   const u8 *feat_cap, size_t feat_cap_len,
+                                   unsigned int freq,
+                                   const u8 *group_ssid, size_t group_ssid_len)
 {
        struct wpa_supplicant *wpa_s = ctx;
        u8 mac[ETH_ALEN];
-       struct wpa_ssid *persistent_go, *stale, *s;
+       struct wpa_ssid *persistent_go, *stale, *s = NULL;
        int save_config = 0;
        struct wpa_supplicant *go_wpa_s;
        char feat_cap_str[256];
@@ -3825,8 +4033,9 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
        }
 
        /* Clean up stale persistent groups with this device */
-       s = wpas_p2p_get_persistent(wpa_s, dev, persist_ssid,
-                                   persist_ssid_size);
+       if (persist_ssid && persist_ssid_size)
+               s = wpas_p2p_get_persistent(wpa_s, dev, persist_ssid,
+                                           persist_ssid_size);
 
        if (persist_ssid && s && s->mode != WPAS_MODE_P2P_GO &&
            is_zero_ether_addr(grp_mac)) {
@@ -3908,6 +4117,7 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
                go_ifname[0] = '\0';
                if (!go_wpa_s) {
                        wpa_s->global->pending_p2ps_group = 1;
+                       wpa_s->global->pending_p2ps_group_freq = freq;
 
                        if (!wpas_p2p_create_iface(wpa_s))
                                os_memcpy(go_ifname, wpa_s->ifname,
@@ -3922,7 +4132,8 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
                                        wpa_s, P2P_SC_FAIL_UNKNOWN_GROUP,
                                        dev, adv_mac, ses_mac,
                                        grp_mac, adv_id, ses_id, 0, 0,
-                                       NULL, 0, 0, 0, NULL, NULL, 0);
+                                       NULL, 0, 0, 0, NULL, NULL, 0, 0,
+                                       NULL, 0);
                                return;
                        }
 
@@ -3930,13 +4141,13 @@ 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, 0, 0, 0, NULL,
+                                       0, 0, freq, 0, 0, 0, 0, NULL,
                                        persistent_go->mode ==
                                        WPAS_MODE_P2P_GO ?
                                        P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
                                        0, 0);
                        } else if (response_done) {
-                               wpas_p2p_group_add(wpa_s, 1, 0, 0, 0);
+                               wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0);
                        }
 
                        if (passwd_id == DEV_PW_P2PS_DEFAULT) {
@@ -3989,16 +4200,24 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
        }
 
        if (conncap == P2PS_SETUP_CLIENT) {
+               char ssid_hex[32 * 2 + 1];
+
+               if (group_ssid)
+                       wpa_snprintf_hex(ssid_hex, sizeof(ssid_hex),
+                                        group_ssid, group_ssid_len);
+               else
+                       ssid_hex[0] = '\0';
                wpa_msg_global(wpa_s, MSG_INFO,
                               P2P_EVENT_P2PS_PROVISION_DONE MACSTR
                               " status=%d conncap=%x"
                               " adv_id=%x adv_mac=" MACSTR
                               " session=%x mac=" MACSTR
-                              " dev_passwd_id=%d join=" MACSTR "%s",
+                              " dev_passwd_id=%d join=" MACSTR "%s%s%s",
                               MAC2STR(dev), status, conncap,
                               adv_id, MAC2STR(adv_mac),
                               ses_id, MAC2STR(ses_mac),
-                              passwd_id, MAC2STR(grp_mac), feat_cap_str);
+                              passwd_id, MAC2STR(grp_mac), feat_cap_str,
+                              group_ssid ? " group_ssid=" : "", ssid_hex);
        } else {
                wpa_msg_global(wpa_s, MSG_INFO,
                               P2P_EVENT_P2PS_PROVISION_DONE MACSTR
@@ -4025,10 +4244,13 @@ static int wpas_prov_disc_resp_cb(void *ctx)
 {
        struct wpa_supplicant *wpa_s = ctx;
        struct wpa_ssid *persistent_go;
+       unsigned int freq;
 
        if (!wpa_s->global->pending_p2ps_group)
                return 0;
 
+       freq = wpa_s->global->pending_p2ps_group_freq;
+       wpa_s->global->pending_p2ps_group_freq = 0;
        wpa_s->global->pending_p2ps_group = 0;
 
        if (wpas_p2p_get_go_group(wpa_s))
@@ -4037,11 +4259,11 @@ 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, NULL,
+                       wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, NULL,
                        persistent_go->mode == WPAS_MODE_P2P_GO ?
                        P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0);
        } else {
-               wpas_p2p_group_add(wpa_s, 1, 0, 0, 0);
+               wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0);
        }
 
        return 1;
@@ -4333,8 +4555,7 @@ static void wpas_p2p_deinit_global(struct wpa_global *global)
 
 static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s)
 {
-       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
-           wpa_s->conf->p2p_no_group_iface)
+       if (wpa_s->conf->p2p_no_group_iface)
                return 0; /* separate interface disabled per configuration */
        if (wpa_s->drv_flags &
            (WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE |
@@ -4415,7 +4636,7 @@ static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s)
                                       MAC2STR(wpa_s->pending_join_dev_addr));
                        return;
                }
-               wpa_msg_global(wpa_s->parent, MSG_INFO,
+               wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
                               P2P_EVENT_GROUP_FORMATION_FAILURE);
                wpas_notify_p2p_group_formation_failure(wpa_s, "");
        }
@@ -4551,7 +4772,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
                if (join < 0) {
                        wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be "
                                   "running a GO -> use GO Negotiation");
-                       wpa_msg_global(wpa_s->parent, MSG_INFO,
+                       wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
                                       P2P_EVENT_FALLBACK_TO_GO_NEG
                                       "reason=peer-not-running-GO");
                        wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr,
@@ -4559,10 +4780,13 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
                                         wpa_s->p2p_persistent_group, 0, 0, 0,
                                         wpa_s->p2p_go_intent,
                                         wpa_s->p2p_connect_freq,
+                                        wpa_s->p2p_go_vht_center_freq2,
                                         wpa_s->p2p_persistent_id,
                                         wpa_s->p2p_pd_before_go_neg,
                                         wpa_s->p2p_go_ht40,
-                                        wpa_s->p2p_go_vht);
+                                        wpa_s->p2p_go_vht,
+                                        wpa_s->p2p_go_max_oper_chwidth,
+                                        NULL, 0);
                        return;
                }
 
@@ -4570,7 +4794,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
                           "try to join the group", join ? "" :
                           " in older scan");
                if (!join) {
-                       wpa_msg_global(wpa_s->parent, MSG_INFO,
+                       wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
                                       P2P_EVENT_FALLBACK_TO_GO_NEG_ENABLED);
                        wpa_s->p2p_fallback_to_go_neg = 1;
                }
@@ -4608,8 +4832,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
                bss = wpa_bss_get(wpa_s, wpa_s->pending_join_iface_addr,
                                  wpa_s->p2p_join_ssid,
                                  wpa_s->p2p_join_ssid_len);
-       }
-       if (!bss) {
+       } else if (!bss) {
                wpa_printf(MSG_DEBUG, "P2P: Trying to find target GO BSS entry based on BSSID "
                           MACSTR, MAC2STR(wpa_s->pending_join_iface_addr));
                bss = wpa_bss_get_bssid_latest(wpa_s,
@@ -4640,7 +4863,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
                u16 method;
 
                if (wpas_check_freq_conflict(wpa_s, freq) > 0) {
-                       wpa_msg_global(wpa_s->parent, MSG_INFO,
+                       wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
                                       P2P_EVENT_GROUP_FORMATION_FAILURE
                                       "reason=FREQ_CONFLICT");
                        wpas_notify_p2p_group_formation_failure(
@@ -4708,7 +4931,8 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
 
 start:
        /* Start join operation immediately */
-       wpas_p2p_join_start(wpa_s, 0, NULL, 0);
+       wpas_p2p_join_start(wpa_s, 0, wpa_s->p2p_join_ssid,
+                           wpa_s->p2p_join_ssid_len);
 }
 
 
@@ -4720,6 +4944,7 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
        struct wpabuf *wps_ie, *ies;
        size_t ielen;
        int freqs[2] = { 0, 0 };
+       unsigned int bands;
 
        os_memset(&params, 0, sizeof(params));
 
@@ -4745,22 +4970,6 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
                return;
        }
 
-       ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
-       ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
-       if (ies == NULL) {
-               wpabuf_free(wps_ie);
-               wpas_p2p_scan_res_join(wpa_s, NULL);
-               return;
-       }
-       wpabuf_put_buf(ies, wps_ie);
-       wpabuf_free(wps_ie);
-
-       p2p_scan_ie(wpa_s->global->p2p, ies, NULL);
-
-       params.p2p_probe = 1;
-       params.extra_ies = wpabuf_head(ies);
-       params.extra_ies_len = wpabuf_len(ies);
-
        if (!freq) {
                int oper_freq;
                /*
@@ -4777,6 +4986,23 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
                params.freqs = freqs;
        }
 
+       ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
+       ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
+       if (ies == NULL) {
+               wpabuf_free(wps_ie);
+               wpas_p2p_scan_res_join(wpa_s, NULL);
+               return;
+       }
+       wpabuf_put_buf(ies, wps_ie);
+       wpabuf_free(wps_ie);
+
+       bands = wpas_get_bands(wpa_s, freqs);
+       p2p_scan_ie(wpa_s->global->p2p, ies, NULL, bands);
+
+       params.p2p_probe = 1;
+       params.extra_ies = wpabuf_head(ies);
+       params.extra_ies_len = wpabuf_len(ies);
+
        /*
         * Run a scan to update BSS table and start Provision Discovery once
         * the new scan results become available.
@@ -4874,8 +5100,13 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
                res.ssid_len = ssid_len;
                os_memcpy(res.ssid, ssid, ssid_len);
        } else {
-               bss = wpa_bss_get_bssid_latest(wpa_s,
-                                              wpa_s->pending_join_iface_addr);
+               if (ssid && ssid_len) {
+                       bss = wpa_bss_get(wpa_s, wpa_s->pending_join_iface_addr,
+                                         ssid, ssid_len);
+               } else {
+                       bss = wpa_bss_get_bssid_latest(
+                               wpa_s, wpa_s->pending_join_iface_addr);
+               }
                if (bss) {
                        res.freq = bss->freq;
                        res.ssid_len = bss->ssid_len;
@@ -4883,6 +5114,11 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
                        wpa_printf(MSG_DEBUG, "P2P: Join target GO operating frequency from BSS table: %d MHz (SSID %s)",
                                   bss->freq,
                                   wpa_ssid_txt(bss->ssid, bss->ssid_len));
+               } else if (ssid && ssid_len) {
+                       res.ssid_len = ssid_len;
+                       os_memcpy(res.ssid, ssid, ssid_len);
+                       wpa_printf(MSG_DEBUG, "P2P: Join target GO (SSID %s)",
+                                  wpa_ssid_txt(ssid, ssid_len));
                }
        }
 
@@ -5067,12 +5303,17 @@ exit_free:
  *     initiating Group Owner negotiation
  * @go_intent: GO Intent or -1 to use default
  * @freq: Frequency for the group or 0 for auto-selection
+ * @freq2: Center frequency of segment 1 for the GO operating in VHT 80P80 mode
  * @persistent_id: Persistent group credentials to use for forcing GO
  *     parameters or -1 to generate new values (SSID/passphrase)
  * @pd: Whether to send Provision Discovery prior to GO Negotiation as an
  *     interoperability workaround when initiating group formation
  * @ht40: Start GO with 40 MHz channel width
  * @vht:  Start GO with VHT support
+ * @vht_chwidth: Channel width supported by GO operating with VHT support
+ *     (VHT_CHANWIDTH_*).
+ * @group_ssid: Specific Group SSID for join or %NULL if not set
+ * @group_ssid_len: Length of @group_ssid in octets
  * 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
@@ -5080,8 +5321,10 @@ exit_free:
 int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                     const char *pin, enum p2p_wps_method wps_method,
                     int persistent_group, int auto_join, int join, int auth,
-                    int go_intent, int freq, int persistent_id, int pd,
-                    int ht40, int vht)
+                    int go_intent, int freq, unsigned int vht_center_freq2,
+                    int persistent_id, int pd, int ht40, int vht,
+                    unsigned int vht_chwidth, const u8 *group_ssid,
+                    size_t group_ssid_len)
 {
        int force_freq = 0, pref_freq = 0;
        int ret = 0, res;
@@ -5105,6 +5348,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 
        wpa_s->global->p2p_fail_on_wps_complete = 0;
        wpa_s->global->pending_p2ps_group = 0;
+       wpa_s->global->pending_p2ps_group_freq = 0;
        wpa_s->p2ps_method_config_any = 0;
 
        if (go_intent < 0)
@@ -5122,17 +5366,23 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        wpa_s->p2p_pd_before_go_neg = !!pd;
        wpa_s->p2p_go_ht40 = !!ht40;
        wpa_s->p2p_go_vht = !!vht;
+       wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
+       wpa_s->p2p_go_max_oper_chwidth = vht_chwidth;
 
        if (pin)
                os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
        else if (wps_method == WPS_PIN_DISPLAY) {
-               ret = wps_generate_pin();
+               if (wps_generate_pin((unsigned int *) &ret) < 0)
+                       return -1;
                res = os_snprintf(wpa_s->p2p_pin, sizeof(wpa_s->p2p_pin),
                                  "%08d", ret);
                if (os_snprintf_error(sizeof(wpa_s->p2p_pin), res))
                        wpa_s->p2p_pin[sizeof(wpa_s->p2p_pin) - 1] = '\0';
                wpa_printf(MSG_DEBUG, "P2P: Randomly generated PIN: %s",
                           wpa_s->p2p_pin);
+       } else if (wps_method == WPS_P2PS) {
+               /* Force the P2Ps default PIN to be used */
+               os_strlcpy(wpa_s->p2p_pin, "12345670", sizeof(wpa_s->p2p_pin));
        } else
                wpa_s->p2p_pin[0] = '\0';
 
@@ -5161,7 +5411,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                }
                wpa_s->user_initiated_pd = 1;
                if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
-                                 auto_join, freq, NULL, 0) < 0)
+                                 auto_join, freq,
+                                 group_ssid, group_ssid_len) < 0)
                        return -1;
                return ret;
        }
@@ -5191,7 +5442,10 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 
                if_addr = wpa_s->pending_interface_addr;
        } else {
-               if_addr = wpa_s->own_addr;
+               if (wpa_s->p2p_mgmt)
+                       if_addr = wpa_s->parent->own_addr;
+               else
+                       if_addr = wpa_s->own_addr;
                os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
        }
 
@@ -5520,29 +5774,51 @@ out:
 
 static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
                                   struct p2p_go_neg_results *params,
-                                  int freq, int ht40, int vht,
+                                  int freq, int vht_center_freq2, int ht40,
+                                  int vht, int max_oper_chwidth,
                                   const struct p2p_channels *channels)
 {
        struct wpa_used_freq_data *freqs;
        unsigned int cand;
        unsigned int num, i;
+       int ignore_no_freqs = 0;
+       int unused_channels = wpas_p2p_num_unused_channels(wpa_s) > 0;
 
        os_memset(params, 0, sizeof(*params));
        params->role_go = 1;
        params->ht40 = ht40;
        params->vht = vht;
-
-       if (wpa_s->p2p_group_common_freqs_num)
-               wpa_printf(MSG_DEBUG, "P2P: %s called for an active GO",
-                          __func__);
+       params->max_oper_chwidth = max_oper_chwidth;
+       params->vht_center_freq2 = vht_center_freq2;
 
        freqs = os_calloc(wpa_s->num_multichan_concurrent,
                          sizeof(struct wpa_used_freq_data));
        if (!freqs)
                return -1;
 
-       num = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
-                                       wpa_s->num_multichan_concurrent);
+       num = get_shared_radio_freqs_data(wpa_s, freqs,
+                                         wpa_s->num_multichan_concurrent);
+
+       if (wpa_s->current_ssid &&
+           wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO &&
+           wpa_s->wpa_state == WPA_COMPLETED) {
+               wpa_printf(MSG_DEBUG, "P2P: %s called for an active GO",
+                          __func__);
+
+               /*
+                * If the frequency selection is done for an active P2P GO that
+                * is not sharing a frequency, allow to select a new frequency
+                * even if there are no unused frequencies as we are about to
+                * move the P2P GO so its frequency can be re-used.
+                */
+               for (i = 0; i < num; i++) {
+                       if (freqs[i].freq == wpa_s->current_ssid->frequency &&
+                           freqs[i].flags == 0) {
+                               ignore_no_freqs = 1;
+                               break;
+                       }
+               }
+       }
 
        /* try using the forced freq */
        if (freq) {
@@ -5563,7 +5839,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
                        }
                }
 
-               if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
+               if (!ignore_no_freqs && !unused_channels) {
                        wpa_printf(MSG_DEBUG,
                                   "P2P: Cannot force GO on freq (%d MHz) as all the channels are in use",
                                   freq);
@@ -5578,12 +5854,13 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
        }
 
        /* consider using one of the shared frequencies */
-       if (num) {
+       if (num &&
+           (!wpa_s->conf->p2p_ignore_shared_freq || !unused_channels)) {
                cand = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num);
                if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
                        wpa_printf(MSG_DEBUG,
                                   "P2P: Use shared freq (%d MHz) for GO",
-                                  freq);
+                                  cand);
                        params->freq = cand;
                        goto success;
                }
@@ -5594,14 +5871,14 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
                                                       freqs[i].freq)) {
                                wpa_printf(MSG_DEBUG,
                                           "P2P: Use shared freq (%d MHz) for GO",
-                                          freq);
+                                          freqs[i].freq);
                                params->freq = freqs[i].freq;
                                goto success;
                        }
                }
        }
 
-       if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
+       if (!ignore_no_freqs && !unused_channels) {
                wpa_printf(MSG_DEBUG,
                           "P2P: Cannot force GO on any of the channels we are already using");
                goto fail;
@@ -5714,9 +5991,20 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
        struct wpa_supplicant *group_wpa_s;
 
        if (!wpas_p2p_create_iface(wpa_s)) {
-               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use same interface for group "
-                       "operations");
+               if (wpa_s->p2p_mgmt) {
+                       /*
+                        * We may be called on the p2p_dev interface which
+                        * cannot be used for group operations, so always use
+                        * the primary interface.
+                        */
+                       wpa_s->parent->p2pdev = wpa_s;
+                       wpa_s = wpa_s->parent;
+               }
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "P2P: Use primary interface for group operations");
                wpa_s->p2p_first_connection_timeout = 0;
+               if (wpa_s != wpa_s->p2pdev)
+                       wpas_p2p_clone_config(wpa_s, wpa_s->p2pdev);
                return wpa_s;
        }
 
@@ -5746,15 +6034,18 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
  * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
  * @persistent_group: Whether to create a persistent group
  * @freq: Frequency for the group or 0 to indicate no hardcoding
+ * @vht_center_freq2: segment_1 center frequency for GO operating in VHT 80P80
  * @ht40: Start GO with 40 MHz channel width
  * @vht:  Start GO with VHT support
+ * @vht_chwidth: channel bandwidth for GO operating with VHT support
  * Returns: 0 on success, -1 on failure
  *
  * This function creates a new P2P group with the local end as the Group Owner,
  * i.e., without using Group Owner Negotiation.
  */
 int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
-                      int freq, int ht40, int vht)
+                      int freq, int vht_center_freq2, int ht40, int vht,
+                      int max_oper_chwidth)
 {
        struct p2p_go_neg_results params;
 
@@ -5772,7 +6063,8 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
        if (freq < 0)
                return -1;
 
-       if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, NULL))
+       if (wpas_p2p_init_go_params(wpa_s, &params, freq, vht_center_freq2,
+                                   ht40, vht, max_oper_chwidth, NULL))
                return -1;
        if (params.freq &&
            !p2p_supported_freq_go(wpa_s->global->p2p, params.freq)) {
@@ -5826,8 +6118,10 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
        wpa_config_set_network_defaults(ssid);
        ssid->temporary = 1;
        ssid->proto = WPA_PROTO_RSN;
-       ssid->pairwise_cipher = WPA_CIPHER_CCMP;
-       ssid->group_cipher = WPA_CIPHER_CCMP;
+       ssid->pbss = params->pbss;
+       ssid->pairwise_cipher = params->pbss ? WPA_CIPHER_GCMP :
+               WPA_CIPHER_CCMP;
+       ssid->group_cipher = params->pbss ? WPA_CIPHER_GCMP : WPA_CIPHER_CCMP;
        ssid->key_mgmt = WPA_KEY_MGMT_PSK;
        ssid->ssid = os_malloc(params->ssid_len);
        if (ssid->ssid == NULL) {
@@ -5848,12 +6142,14 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
        wpa_s->show_group_started = 1;
        wpa_s->p2p_in_invitation = 1;
        wpa_s->p2p_invite_go_freq = freq;
+       wpa_s->p2p_go_group_formation_completed = 0;
+       wpa_s->global->p2p_group_formation = wpa_s;
 
-       eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
+       eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->p2pdev,
                             NULL);
        eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
                               wpas_p2p_group_formation_timeout,
-                              wpa_s->parent, NULL);
+                              wpa_s->p2pdev, NULL);
        wpa_supplicant_select_network(wpa_s, ssid);
 
        return 0;
@@ -5862,8 +6158,10 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
 
 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 ht40,
-                                 int vht, const struct p2p_channels *channels,
+                                 int force_freq, int neg_freq,
+                                 int vht_center_freq2, int ht40,
+                                 int vht, int max_oper_chwidth,
+                                 const struct p2p_channels *channels,
                                  int connection_timeout, int force_scan)
 {
        struct p2p_go_neg_results params;
@@ -5878,7 +6176,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
                           "already running");
                if (go == 0 &&
                    eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
-                                        wpa_s->parent, NULL)) {
+                                        wpa_s->p2pdev, NULL)) {
                        /*
                         * This can happen if Invitation Response frame was lost
                         * and the peer (GO of a persistent group) tries to
@@ -5891,7 +6189,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
                                   "P2P: Reschedule group formation timeout since peer is still trying to invite us");
                        eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
                                               wpas_p2p_group_formation_timeout,
-                                              wpa_s->parent, NULL);
+                                              wpa_s->p2pdev, NULL);
                }
                return 0;
        }
@@ -5937,7 +6235,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
-       if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, channels))
+       if (wpas_p2p_init_go_params(wpa_s, &params, freq, vht_center_freq2,
+                                   ht40, vht, max_oper_chwidth, channels))
                return -1;
 
        params.role_go = 1;
@@ -6019,7 +6318,8 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
        struct p2p_group *group;
        struct p2p_group_config *cfg;
 
-       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
+           !ssid->p2p_group)
                return NULL;
 
        cfg = os_zalloc(sizeof(*cfg));
@@ -6042,6 +6342,8 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
        cfg->cb_ctx = wpa_s;
        cfg->ie_update = wpas_p2p_ie_update;
        cfg->idle_update = wpas_p2p_idle_update;
+       cfg->ip_addr_alloc = WPA_GET_BE32(wpa_s->p2pdev->conf->ip_addr_start)
+               != 0;
 
        group = p2p_group_init(wpa_s->global->p2p, cfg);
        if (group == NULL)
@@ -6073,7 +6375,7 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                p2p_clear_provisioning_info(wpa_s->global->p2p, go_dev_addr);
        }
 
-       eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
+       eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->p2pdev,
                             NULL);
        wpa_s->p2p_go_group_formation_completed = 1;
        if (ssid && ssid->mode == WPAS_MODE_INFRA) {
@@ -6088,7 +6390,9 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                        P2P_MAX_INITIAL_CONN_WAIT);
                eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
                                       wpas_p2p_group_formation_timeout,
-                                      wpa_s->parent, NULL);
+                                      wpa_s->p2pdev, NULL);
+               /* Complete group formation on successful data connection. */
+               wpa_s->p2p_go_group_formation_completed = 0;
        } else if (ssid) {
                /*
                 * Use a separate timeout for initial data connection to
@@ -6100,7 +6404,7 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                        P2P_MAX_INITIAL_CONN_WAIT_GO);
                eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT_GO, 0,
                                       wpas_p2p_group_formation_timeout,
-                                      wpa_s->parent, NULL);
+                                      wpa_s->p2pdev, NULL);
                /*
                 * Complete group formation on first successful data connection
                 */
@@ -6139,7 +6443,7 @@ void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
                wpa_s->global->p2p_fail_on_wps_complete = 1;
                eloop_deplete_timeout(0, 50000,
                                      wpas_p2p_group_formation_timeout,
-                                     wpa_s->parent, NULL);
+                                     wpa_s->p2pdev, NULL);
        }
 }
 
@@ -6164,11 +6468,14 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        u16 config_methods;
 
        wpa_s->global->pending_p2ps_group = 0;
+       wpa_s->global->pending_p2ps_group_freq = 0;
        wpa_s->p2p_fallback_to_go_neg = 0;
        wpa_s->pending_pd_use = NORMAL_PD;
        if (p2ps_prov && use == WPAS_P2P_PD_FOR_ASP) {
                p2ps_prov->conncap = p2ps_group_capability(
-                       wpa_s, P2PS_SETUP_NONE, p2ps_prov->role);
+                       wpa_s, P2PS_SETUP_NONE, p2ps_prov->role,
+                       &p2ps_prov->force_freq, &p2ps_prov->pref_freq);
+
                wpa_printf(MSG_DEBUG,
                           "P2P: %s conncap: %d - ASP parsed: %x %x %d %s",
                           __func__, p2ps_prov->conncap,
@@ -6229,7 +6536,12 @@ static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
        if (!offchannel_pending_action_tx(wpa_s))
                return;
 
-       wpas_p2p_action_tx_clear(wpa_s);
+       if (wpa_s->p2p_send_action_work) {
+               wpas_p2p_free_send_action_work(wpa_s);
+               eloop_cancel_timeout(wpas_p2p_send_action_work_timeout,
+                                    wpa_s, NULL);
+               offchannel_send_action_done(wpa_s);
+       }
 
        wpa_printf(MSG_DEBUG, "P2P: Drop pending Action TX due to new "
                   "operation request");
@@ -6320,6 +6632,12 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout)
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return -1;
 
+       if (wpa_s->p2p_lo_started) {
+               wpa_printf(MSG_DEBUG,
+                       "P2P: Cannot start P2P listen, it is offloaded");
+               return -1;
+       }
+
        wpa_supplicant_cancel_sched_scan(wpa_s);
        wpas_p2p_clear_pending_action_tx(wpa_s);
 
@@ -6393,7 +6711,7 @@ int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
                return 0;
 
        switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
-                                ie, ie_len, rx_freq)) {
+                                ie, ie_len, rx_freq, wpa_s->p2p_lo_started)) {
        case P2P_PREQ_NOT_P2P:
                wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
                                 ssi_signal);
@@ -6425,12 +6743,15 @@ void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
 
 void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies)
 {
+       unsigned int bands;
+
        if (wpa_s->global->p2p_disabled)
                return;
        if (wpa_s->global->p2p == NULL)
                return;
 
-       p2p_scan_ie(wpa_s->global->p2p, ies, NULL);
+       bands = wpas_get_bands(wpa_s, NULL);
+       p2p_scan_ie(wpa_s->global->p2p, ies, NULL, bands);
 }
 
 
@@ -6460,7 +6781,8 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
 /* Invite to reinvoke a persistent group */
 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 ht40, int vht, int pref_freq)
+                   int vht_center_freq2, int ht40, int vht, int max_chwidth,
+                   int pref_freq)
 {
        enum p2p_invite_role role;
        u8 *bssid = NULL;
@@ -6477,6 +6799,9 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 
        wpa_s->p2p_persistent_go_freq = freq;
        wpa_s->p2p_go_ht40 = !!ht40;
+       wpa_s->p2p_go_vht = !!vht;
+       wpa_s->p2p_go_max_oper_chwidth = max_chwidth;
+       wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
        if (ssid->mode == WPAS_MODE_P2P_GO) {
                role = P2P_INVITE_ROLE_GO;
                if (peer_addr == NULL) {
@@ -6493,7 +6818,9 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                                return -1;
                        }
                        bssid = wpa_s->pending_interface_addr;
-               } else
+               } else if (wpa_s->p2p_mgmt)
+                       bssid = wpa_s->parent->own_addr;
+               else
                        bssid = wpa_s->own_addr;
        } else {
                role = P2P_INVITE_ROLE_CLIENT;
@@ -6507,11 +6834,12 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                                   pref_freq_list, &size);
        if (res)
                return res;
-       p2p_set_own_pref_freq_list(wpa_s->global->p2p, pref_freq_list, size);
 
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return -1;
 
+       p2p_set_own_pref_freq_list(wpa_s->global->p2p, pref_freq_list, size);
+
        if (wpa_s->parent->conf->p2p_ignore_shared_freq &&
            no_pref_freq_given && pref_freq > 0 &&
            wpa_s->num_multichan_concurrent > 1 &&
@@ -6549,6 +6877,8 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
        wpa_s->p2p_persistent_go_freq = 0;
        wpa_s->p2p_go_ht40 = 0;
        wpa_s->p2p_go_vht = 0;
+       wpa_s->p2p_go_vht_center_freq2 = 0;
+       wpa_s->p2p_go_max_oper_chwidth = 0;
 
        for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
                if (os_strcmp(wpa_s->ifname, ifname) == 0)
@@ -6568,7 +6898,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
 
        wpa_s->global->p2p_invite_group = wpa_s;
        persistent = ssid->p2p_persistent_group &&
-               wpas_p2p_get_persistent(wpa_s->parent, peer_addr,
+               wpas_p2p_get_persistent(wpa_s->p2pdev, peer_addr,
                                        ssid->ssid, ssid->ssid_len);
 
        if (ssid->mode == WPAS_MODE_P2P_GO) {
@@ -6591,7 +6921,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
                freq = wpa_s->current_bss ? wpa_s->current_bss->freq :
                        (int) wpa_s->assoc_freq;
        }
-       wpa_s->parent->pending_invite_ssid_id = -1;
+       wpa_s->p2pdev->pending_invite_ssid_id = -1;
 
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return -1;
@@ -6614,7 +6944,6 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
 {
        struct wpa_ssid *ssid = wpa_s->current_ssid;
        u8 go_dev_addr[ETH_ALEN];
-       int network_id = -1;
        int persistent;
        int freq;
        u8 ip[3 * 4];
@@ -6622,13 +6951,22 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
 
        if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) {
                eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
-                                    wpa_s->parent, NULL);
+                                    wpa_s->p2pdev, NULL);
        }
 
        if (!wpa_s->show_group_started || !ssid)
                return;
 
        wpa_s->show_group_started = 0;
+       if (!wpa_s->p2p_go_group_formation_completed &&
+           wpa_s->global->p2p_group_formation == wpa_s) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "P2P: Marking group formation completed on client on data connection");
+               wpa_s->p2p_go_group_formation_completed = 1;
+               wpa_s->global->p2p_group_formation = NULL;
+               wpa_s->p2p_in_provisioning = 0;
+               wpa_s->p2p_in_invitation = 0;
+       }
 
        os_memset(go_dev_addr, 0, ETH_ALEN);
        if (ssid->bssid_set)
@@ -6664,11 +7002,10 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
                               ip_addr);
 
        if (persistent)
-               network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
-                                                            ssid, go_dev_addr);
-       if (network_id < 0)
-               network_id = ssid->id;
-       wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
+               wpas_p2p_store_persistent_group(wpa_s->p2pdev,
+                                               ssid, go_dev_addr);
+
+       wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 1);
 }
 
 
@@ -7001,7 +7338,7 @@ int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled)
 
                        iface->cross_connect_enabled = 0;
                        iface->cross_connect_in_use = 0;
-                       wpa_msg_global(iface->parent, MSG_INFO,
+                       wpa_msg_global(iface->p2pdev, MSG_INFO,
                                       P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
                                       iface->ifname,
                                       iface->cross_connect_uplink);
@@ -7031,7 +7368,7 @@ static void wpas_p2p_enable_cross_connect(struct wpa_supplicant *uplink)
                        continue;
 
                iface->cross_connect_in_use = 1;
-               wpa_msg_global(iface->parent, MSG_INFO,
+               wpa_msg_global(iface->p2pdev, MSG_INFO,
                               P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
                               iface->ifname, iface->cross_connect_uplink);
        }
@@ -7051,7 +7388,7 @@ static void wpas_p2p_disable_cross_connect(struct wpa_supplicant *uplink)
                if (!iface->cross_connect_in_use)
                        continue;
 
-               wpa_msg_global(iface->parent, MSG_INFO,
+               wpa_msg_global(iface->p2pdev, MSG_INFO,
                               P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
                               iface->ifname, iface->cross_connect_uplink);
                iface->cross_connect_in_use = 0;
@@ -7114,7 +7451,7 @@ static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s)
                        break;
 
                wpa_s->cross_connect_in_use = 1;
-               wpa_msg_global(wpa_s->parent, MSG_INFO,
+               wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
                               P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
                               wpa_s->ifname, wpa_s->cross_connect_uplink);
                break;
@@ -7130,8 +7467,8 @@ int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
 
        wpa_printf(MSG_DEBUG, "P2P: Terminate connection due to WPS PBC "
                   "session overlap");
-       if (wpa_s != wpa_s->parent)
-               wpa_msg_ctrl(wpa_s->parent, MSG_INFO, WPS_EVENT_OVERLAP);
+       if (wpa_s != wpa_s->p2pdev)
+               wpa_msg_ctrl(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_OVERLAP);
        wpas_p2p_group_formation_failed(wpa_s, 0);
        return 1;
 }
@@ -7238,7 +7575,7 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
                                   wpa_s->ifname);
                        found = 1;
                        eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
-                                            wpa_s->parent, NULL);
+                                            wpa_s->p2pdev, NULL);
                        if (wpa_s->p2p_in_provisioning) {
                                wpas_group_formation_completed(wpa_s, 0, 0);
                                break;
@@ -7251,6 +7588,7 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
                                   wpa_s->ifname);
                        found = 1;
                        wpas_p2p_group_formation_failed(wpa_s, 0);
+                       break;
                }
        }
 
@@ -7367,7 +7705,7 @@ void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
 {
        if (wpa_s->p2p_in_provisioning && ssid->p2p_group &&
            eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
-                                wpa_s->parent, NULL) > 0) {
+                                wpa_s->p2pdev, NULL) > 0) {
                /**
                 * Remove the network by scheduling the group formation
                 * timeout to happen immediately. The teardown code
@@ -7379,7 +7717,7 @@ void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
                wpa_printf(MSG_DEBUG, "P2P: Canceled group formation due to "
                           "P2P group network getting removed");
                eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
-                                      wpa_s->parent, NULL);
+                                      wpa_s->p2pdev, NULL);
        }
 }
 
@@ -7423,7 +7761,7 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
                                       const u8 *addr)
 {
        if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
-                                wpa_s->parent, NULL) > 0) {
+                                wpa_s->p2pdev, NULL) > 0) {
                /*
                 * This can happen if WPS provisioning step is not terminated
                 * cleanly (e.g., P2P Client does not send WSC_Done). Since the
@@ -7479,10 +7817,12 @@ static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
        wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin,
                         wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0,
                         0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq,
+                        wpa_s->p2p_go_vht_center_freq2,
                         wpa_s->p2p_persistent_id,
                         wpa_s->p2p_pd_before_go_neg,
                         wpa_s->p2p_go_ht40,
-                        wpa_s->p2p_go_vht);
+                        wpa_s->p2p_go_vht,
+                        wpa_s->p2p_go_max_oper_chwidth, NULL, 0);
        return ret;
 }
 
@@ -7500,7 +7840,7 @@ int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s)
 
        wpa_dbg(wpa_s, MSG_DEBUG, "P2P: GO not found for p2p_connect-auto - "
                "fallback to GO Negotiation");
-       wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_FALLBACK_TO_GO_NEG
+       wpa_msg_global(wpa_s->p2pdev, MSG_INFO, P2P_EVENT_FALLBACK_TO_GO_NEG
                       "reason=GO-not-found");
        res = wpas_p2p_fallback_to_go_neg(wpa_s, 1);
 
@@ -7609,7 +7949,7 @@ void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
                return;
        }
 
-       persistent = wpas_p2p_get_persistent(wpa_s->parent, NULL, ssid->ssid,
+       persistent = wpas_p2p_get_persistent(wpa_s->p2pdev, NULL, ssid->ssid,
                                             ssid->ssid_len);
        if (!persistent) {
                wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not find persistent group information to store the new PSK");
@@ -7638,7 +7978,7 @@ void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
                os_free(last);
        }
 
-       wpas_p2p_remove_psk_entry(wpa_s->parent, persistent,
+       wpas_p2p_remove_psk_entry(wpa_s->p2pdev, persistent,
                                  p2p_dev_addr ? p2p_dev_addr : mac_addr,
                                  p2p_dev_addr == NULL);
        if (p2p_dev_addr) {
@@ -7650,8 +7990,8 @@ void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
        }
        dl_list_add(&persistent->psk_list, &p->list);
 
-       if (wpa_s->parent->conf->update_config &&
-           wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+       if (wpa_s->p2pdev->conf->update_config &&
+           wpa_config_write(wpa_s->p2pdev->confname, wpa_s->p2pdev->conf))
                wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
 }
 
@@ -7830,14 +8170,14 @@ int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s)
 
                wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Two 4-way handshake failures for a P2P group - go_dev_addr="
                        MACSTR, MAC2STR(go_dev_addr));
-               persistent = wpas_p2p_get_persistent(wpa_s->parent, go_dev_addr,
+               persistent = wpas_p2p_get_persistent(wpa_s->p2pdev, go_dev_addr,
                                                     ssid->ssid,
                                                     ssid->ssid_len);
                if (persistent == NULL || persistent->mode != WPAS_MODE_INFRA) {
                        wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No matching persistent group stored");
                        goto disconnect;
                }
-               wpa_msg_global(wpa_s->parent, MSG_INFO,
+               wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
                               P2P_EVENT_PERSISTENT_PSK_FAIL "%d",
                               persistent->id);
        disconnect:
@@ -8016,7 +8356,10 @@ static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s,
 
        return wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
                                WPS_NFC, 0, 0, 1, 0, wpa_s->conf->p2p_go_intent,
-                               params->go_freq, -1, 0, 1, 1);
+                               params->go_freq, wpa_s->p2p_go_vht_center_freq2,
+                               -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
+                               params->go_ssid_len ? params->go_ssid : NULL,
+                               params->go_ssid_len);
 }
 
 
@@ -8043,17 +8386,17 @@ static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
-       if (wpa_s->parent->p2p_oob_dev_pw_id !=
+       if (wpa_s->p2pdev->p2p_oob_dev_pw_id !=
            DEV_PW_NFC_CONNECTION_HANDOVER &&
-           !wpa_s->parent->p2p_oob_dev_pw) {
+           !wpa_s->p2pdev->p2p_oob_dev_pw) {
                wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known");
                return -1;
        }
        res = wpas_ap_wps_add_nfc_pw(
-               wpa_s, wpa_s->parent->p2p_oob_dev_pw_id,
-               wpa_s->parent->p2p_oob_dev_pw,
-               wpa_s->parent->p2p_peer_oob_pk_hash_known ?
-               wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL);
+               wpa_s, wpa_s->p2pdev->p2p_oob_dev_pw_id,
+               wpa_s->p2pdev->p2p_oob_dev_pw,
+               wpa_s->p2pdev->p2p_peer_oob_pk_hash_known ?
+               wpa_s->p2pdev->p2p_peer_oob_pubkey_hash : NULL);
        if (res)
                return res;
 
@@ -8071,16 +8414,16 @@ static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s,
 
        wpa_s->global->p2p_invite_group = wpa_s;
        persistent = ssid->p2p_persistent_group &&
-               wpas_p2p_get_persistent(wpa_s->parent,
+               wpas_p2p_get_persistent(wpa_s->p2pdev,
                                        params->peer->p2p_device_addr,
                                        ssid->ssid, ssid->ssid_len);
-       wpa_s->parent->pending_invite_ssid_id = -1;
+       wpa_s->p2pdev->pending_invite_ssid_id = -1;
 
        return p2p_invite(wpa_s->global->p2p, params->peer->p2p_device_addr,
                          P2P_INVITE_ROLE_ACTIVE_GO, wpa_s->own_addr,
                          ssid->ssid, ssid->ssid_len, ssid->frequency,
                          wpa_s->global->p2p_dev_addr, persistent, 0,
-                         wpa_s->parent->p2p_oob_dev_pw_id);
+                         wpa_s->p2pdev->p2p_oob_dev_pw_id);
 }
 
 
@@ -8092,7 +8435,9 @@ static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s,
                   "connection handover");
        return wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
                                WPS_NFC, 0, 0, 0, 0, wpa_s->conf->p2p_go_intent,
-                               forced_freq, -1, 0, 1, 1);
+                               forced_freq, wpa_s->p2p_go_vht_center_freq2,
+                               -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
+                               NULL, 0);
 }
 
 
@@ -8106,7 +8451,9 @@ static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s,
                   "connection handover");
        res = wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
                               WPS_NFC, 0, 0, 0, 1, wpa_s->conf->p2p_go_intent,
-                              forced_freq, -1, 0, 1, 1);
+                              forced_freq, wpa_s->p2p_go_vht_center_freq2,
+                              -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
+                              NULL, 0);
        if (res)
                return res;
 
@@ -8397,7 +8744,9 @@ int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled)
                }
 
                if_addr = wpa_s->pending_interface_addr;
-       } else
+       } else if (wpa_s->p2p_mgmt)
+               if_addr = wpa_s->parent->own_addr;
+       else
                if_addr = wpa_s->own_addr;
 
        wpa_s->p2p_nfc_tag_enabled = enabled;
@@ -8473,14 +8822,115 @@ static void wpas_p2p_optimize_listen_channel(struct wpa_supplicant *wpa_s,
 
 static int wpas_p2p_move_go_csa(struct wpa_supplicant *wpa_s)
 {
+       struct hostapd_config *conf;
+       struct p2p_go_neg_results params;
+       struct csa_settings csa_settings;
+       struct wpa_ssid *current_ssid = wpa_s->current_ssid;
+       int old_freq = current_ssid->frequency;
+       int ret;
+
        if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)) {
                wpa_dbg(wpa_s, MSG_DEBUG, "CSA is not enabled");
                return -1;
        }
 
-       /* TODO: Add CSA support */
-       wpa_dbg(wpa_s, MSG_DEBUG, "Moving GO with CSA is not implemented");
-       return -1;
+       /*
+        * 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, NULL)) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "P2P CSA: Failed to select new frequency for GO");
+               return -1;
+       }
+
+       if (current_ssid->frequency == params.freq) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "P2P CSA: Selected same frequency - not moving GO");
+               return 0;
+       }
+
+       conf = hostapd_config_defaults();
+       if (!conf) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "P2P CSA: Failed to allocate default config");
+               return -1;
+       }
+
+       current_ssid->frequency = params.freq;
+       if (wpa_supplicant_conf_ap_ht(wpa_s, current_ssid, conf)) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "P2P CSA: Failed to create new GO config");
+               ret = -1;
+               goto out;
+       }
+
+       if (conf->hw_mode != wpa_s->ap_iface->current_mode->mode) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "P2P CSA: CSA to a different band is not supported");
+               ret = -1;
+               goto out;
+       }
+
+       os_memset(&csa_settings, 0, sizeof(csa_settings));
+       csa_settings.cs_count = P2P_GO_CSA_COUNT;
+       csa_settings.block_tx = P2P_GO_CSA_BLOCK_TX;
+       csa_settings.freq_params.freq = params.freq;
+       csa_settings.freq_params.sec_channel_offset = conf->secondary_channel;
+       csa_settings.freq_params.ht_enabled = conf->ieee80211n;
+       csa_settings.freq_params.bandwidth = conf->secondary_channel ? 40 : 20;
+
+       if (conf->ieee80211ac) {
+               int freq1 = 0, freq2 = 0;
+               u8 chan, opclass;
+
+               if (ieee80211_freq_to_channel_ext(params.freq,
+                                                 conf->secondary_channel,
+                                                 conf->vht_oper_chwidth,
+                                                 &opclass, &chan) ==
+                   NUM_HOSTAPD_MODES) {
+                       wpa_printf(MSG_ERROR, "P2P CSA: Bad freq");
+                       ret = -1;
+                       goto out;
+               }
+
+               if (conf->vht_oper_centr_freq_seg0_idx)
+                       freq1 = ieee80211_chan_to_freq(
+                               NULL, opclass,
+                               conf->vht_oper_centr_freq_seg0_idx);
+
+               if (conf->vht_oper_centr_freq_seg1_idx)
+                       freq2 = ieee80211_chan_to_freq(
+                               NULL, opclass,
+                               conf->vht_oper_centr_freq_seg1_idx);
+
+               if (freq1 < 0 || freq2 < 0) {
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "P2P CSA: Selected invalid VHT center freqs");
+                       ret = -1;
+                       goto out;
+               }
+
+               csa_settings.freq_params.vht_enabled = conf->ieee80211ac;
+               csa_settings.freq_params.center_freq1 = freq1;
+               csa_settings.freq_params.center_freq2 = freq2;
+
+               switch (conf->vht_oper_chwidth) {
+               case VHT_CHANWIDTH_80MHZ:
+               case VHT_CHANWIDTH_80P80MHZ:
+                       csa_settings.freq_params.bandwidth = 80;
+                       break;
+               case VHT_CHANWIDTH_160MHZ:
+                       csa_settings.freq_params.bandwidth = 160;
+                       break;
+               }
+       }
+
+       ret = ap_switch_channel(wpa_s, &csa_settings);
+out:
+       current_ssid->frequency = old_freq;
+       hostapd_config_free(conf);
+       return ret;
 }
 
 
@@ -8500,7 +8950,7 @@ static void wpas_p2p_move_go_no_csa(struct wpa_supplicant *wpa_s)
        wpa_supplicant_ap_deinit(wpa_s);
 
        /* Reselect the GO frequency */
-       if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, NULL)) {
+       if (wpas_p2p_init_go_params(wpa_s, &params, 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);
@@ -8537,6 +8987,13 @@ static void wpas_p2p_move_go(void *eloop_ctx, void *timeout_ctx)
 
        wpas_p2p_go_update_common_freqs(wpa_s);
 
+       /* Do not move GO in the middle of a CSA */
+       if (hostapd_csa_in_progress(wpa_s->ap_iface)) {
+               wpa_printf(MSG_DEBUG,
+                          "P2P: CSA is in progress - not moving GO");
+               return;
+       }
+
        /*
         * First, try a channel switch flow. If it is not supported or fails,
         * take down the GO and bring it up again.
@@ -8613,6 +9070,25 @@ static void wpas_p2p_consider_moving_one_go(struct wpa_supplicant *wpa_s,
                           P2P_GO_FREQ_MOVE_SCM_PEER_SUPPORTS &&
                           wpas_p2p_go_is_peer_freq(wpa_s, freqs[i].freq)) {
                        policy_move = 1;
+               } else if ((wpa_s->conf->p2p_go_freq_change_policy ==
+                           P2P_GO_FREQ_MOVE_SCM_ECSA) &&
+                          wpas_p2p_go_is_peer_freq(wpa_s, freqs[i].freq)) {
+                       if (!p2p_get_group_num_members(wpa_s->p2p_group)) {
+                               policy_move = 1;
+                       } else if ((wpa_s->drv_flags &
+                                   WPA_DRIVER_FLAGS_AP_CSA) &&
+                                  wpas_p2p_go_clients_support_ecsa(wpa_s)) {
+                               u8 chan;
+
+                               /*
+                                * We do not support CSA between bands, so move
+                                * GO only within the same band.
+                                */
+                               if (wpa_s->ap_iface->current_mode->mode ==
+                                   ieee80211_freq_to_chan(freqs[i].freq,
+                                                          &chan))
+                                       policy_move = 1;
+                       }
                }
        }
 
@@ -8647,6 +9123,16 @@ static void wpas_p2p_consider_moving_one_go(struct wpa_supplicant *wpa_s,
                return;
        }
 
+       /*
+        * Do not consider moving GO if it is in the middle of a CSA. When the
+        * CSA is finished this flow should be retriggered.
+        */
+       if (hostapd_csa_in_progress(wpa_s->ap_iface)) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "P2P: Not initiating a GO frequency change - CSA is in progress");
+               return;
+       }
+
        if (invalid_freq && !wpas_p2p_disallowed_freq(wpa_s->global, freq))
                timeout = P2P_GO_FREQ_CHANGE_TIME;
        else
@@ -8726,3 +9212,86 @@ void wpas_p2p_ap_deinit(struct wpa_supplicant *wpa_s)
                wpa_s->ap_iface->bss[0]->p2p_group = NULL;
        wpas_p2p_group_deinit(wpa_s);
 }
+
+
+int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq,
+                     unsigned int period, unsigned int interval,
+                     unsigned int count)
+{
+       struct p2p_data *p2p = wpa_s->global->p2p;
+       u8 *device_types;
+       size_t dev_types_len;
+       struct wpabuf *buf;
+       int ret;
+
+       if (wpa_s->p2p_lo_started) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "P2P Listen offload is already started");
+               return 0;
+       }
+
+       if (wpa_s->global->p2p == NULL ||
+           !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD)) {
+               wpa_printf(MSG_DEBUG, "P2P: Listen offload not supported");
+               return -1;
+       }
+
+       if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+               wpa_printf(MSG_ERROR, "P2P: Input channel not supported: %u",
+                          freq);
+               return -1;
+       }
+
+       /* Get device type */
+       dev_types_len = (wpa_s->conf->num_sec_device_types + 1) *
+               WPS_DEV_TYPE_LEN;
+       device_types = os_malloc(dev_types_len);
+       if (!device_types)
+               return -1;
+       os_memcpy(device_types, wpa_s->conf->device_type, WPS_DEV_TYPE_LEN);
+       os_memcpy(&device_types[WPS_DEV_TYPE_LEN], wpa_s->conf->sec_device_type,
+                 wpa_s->conf->num_sec_device_types * WPS_DEV_TYPE_LEN);
+
+       /* Get Probe Response IE(s) */
+       buf = p2p_build_probe_resp_template(p2p, freq);
+       if (!buf) {
+               os_free(device_types);
+               return -1;
+       }
+
+       ret = wpa_drv_p2p_lo_start(wpa_s, freq, period, interval, count,
+                                  device_types, dev_types_len,
+                                  wpabuf_mhead_u8(buf), wpabuf_len(buf));
+       if (ret < 0)
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "P2P: Failed to start P2P listen offload");
+
+       os_free(device_types);
+       wpabuf_free(buf);
+
+       if (ret == 0) {
+               wpa_s->p2p_lo_started = 1;
+
+               /* Stop current P2P listen if any */
+               wpas_stop_listen(wpa_s);
+       }
+
+       return ret;
+}
+
+
+int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s)
+{
+       int ret;
+
+       if (!wpa_s->p2p_lo_started)
+               return 0;
+
+       ret = wpa_drv_p2p_lo_stop(wpa_s);
+       if (ret < 0)
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "P2P: Failed to stop P2P listen offload");
+
+       wpa_s->p2p_lo_started = 0;
+       return ret;
+}
index 56e6834..63910d1 100644 (file)
@@ -34,17 +34,22 @@ struct wpa_supplicant * wpas_get_p2p_client_iface(struct wpa_supplicant *wpa_s,
                                                  const u8 *peer_dev_addr);
 int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                     const char *pin, enum p2p_wps_method wps_method,
-                    int persistent_group, int auto_join, int join,
-                    int auth, int go_intent, int freq, int persistent_id,
-                    int pd, int ht40, int vht);
+                    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, const u8 *group_ssid,
+                    size_t group_ssid_len);
 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 ht40, int vht);
+                      int freq, int vht_center_freq2, int ht40, int vht,
+                      int max_oper_chwidth);
 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 ht40,
-                                 int vht, const struct p2p_channels *channels,
+                                 int force_freq, int neg_freq,
+                                 int vht_center_freq2, int ht40,
+                                 int vht, int max_oper_chwidth,
+                                 const struct p2p_channels *channels,
                                  int connection_timeout, int force_scan);
 struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
                                       struct wpa_ssid *ssid);
@@ -111,7 +116,8 @@ 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 ht40, int vht, int pref_freq);
+                   int vht_center_freq2, int ht40, int vht,
+                   int max_oper_chwidth, int pref_freq);
 int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
                          const u8 *peer_addr, const u8 *go_dev_addr);
 int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
@@ -140,6 +146,8 @@ 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);
+int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s,
+                              struct hostapd_hw_modes *mode, u8 channel);
 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,
@@ -199,6 +207,10 @@ int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s);
 void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
                         struct wps_event_fail *fail);
 int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
+int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq,
+                     unsigned int period, unsigned int interval,
+                     unsigned int count);
+int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s);
 
 #else /* CONFIG_P2P */
 
index fc07b07..f8675e6 100644 (file)
@@ -48,7 +48,7 @@ static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start,
                        u8 *spos_tmp;
 
                        /* Offset */
-                       if (*spos + 2 > end) {
+                       if (end - *spos < 2) {
                                wpa_printf(MSG_DEBUG, "P2P: No room for full "
                                           "DNS offset field");
                                return -1;
@@ -74,14 +74,14 @@ static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start,
                        return 0;
 
                (*spos)++;
-               if (*spos + len > end) {
+               if (len > end - *spos) {
                        wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
                                   "sequence - no room for label with length "
                                   "%u", len);
                        return -1;
                }
 
-               if (*upos + len + 2 > uend)
+               if (len + 2 > uend - *upos)
                        return -2;
 
                os_memcpy(*upos, *spos, len);
@@ -722,11 +722,11 @@ void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
        if (resp == NULL)
                return;
 
-       while (pos + 1 < end) {
+       while (end - pos > 1) {
                wpa_printf(MSG_DEBUG, "P2P: Service Request TLV");
                slen = WPA_GET_LE16(pos);
                pos += 2;
-               if (pos + slen > end || slen < 2) {
+               if (slen > end - pos || slen < 2) {
                        wpa_printf(MSG_DEBUG, "P2P: Unexpected Query Data "
                                   "length");
                        wpabuf_free(resp);
@@ -827,10 +827,10 @@ static void wpas_sd_p2ps_serv_response(struct wpa_supplicant *wpa_s,
                u8 svc_len;
 
                /* Sanity check fixed length+svc_str */
-               if (pos + 6 >= tlv_end)
+               if (6 >= tlv_end - pos)
                        break;
                svc_len = pos[6];
-               if (pos + svc_len + 10 > tlv_end)
+               if (svc_len + 10 > tlv_end - pos)
                        break;
 
                /* Advertisement ID */
@@ -917,13 +917,13 @@ void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
                }
        }
 
-       while (pos < end) {
+       while (end - pos >= 2) {
                u8 srv_proto, srv_trans_id, status;
 
                wpa_printf(MSG_DEBUG, "P2P: Service Response TLV");
                slen = WPA_GET_LE16(pos);
                pos += 2;
-               if (pos + slen > end || slen < 3) {
+               if (slen > end - pos || slen < 3) {
                        wpa_printf(MSG_DEBUG, "P2P: Unexpected Response Data "
                                   "length");
                        return;
index d7049a1..fb8ebdf 100644 (file)
@@ -36,8 +36,7 @@ static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
 
        if (wpa_s->current_ssid == NULL) {
                wpa_s->current_ssid = ssid;
-               if (wpa_s->current_ssid != NULL)
-                       wpas_notify_network_changed(wpa_s);
+               wpas_notify_network_changed(wpa_s);
        }
        wpa_supplicant_initiate_eapol(wpa_s);
        wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with a configured "
@@ -60,10 +59,7 @@ static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
 
                wps = 1;
                *req_type = wpas_wps_get_req_type(ssid);
-               if (!ssid->eap.phase1)
-                       continue;
-
-               if (os_strstr(ssid->eap.phase1, "pbc=1"))
+               if (ssid->eap.phase1 && os_strstr(ssid->eap.phase1, "pbc=1"))
                        return 2;
        }
 
@@ -166,6 +162,8 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
        if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
                wpa_msg(wpa_s, MSG_INFO,
                        "Failed to assign random MAC address for a scan");
+               wpa_scan_free_params(params);
+               wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1");
                radio_work_done(work);
                return;
        }
@@ -229,12 +227,11 @@ int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
        }
 
        ctx = wpa_scan_clone_params(params);
-       if (ctx == NULL)
-               return -1;
-
-       if (radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
+       if (!ctx ||
+           radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
        {
                wpa_scan_free_params(ctx);
+               wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1");
                return -1;
        }
 
@@ -266,14 +263,14 @@ wpa_supplicant_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 }
 
 
-int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
-                                   struct wpa_driver_scan_params *params,
-                                   int interval)
+static int
+wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
+                               struct wpa_driver_scan_params *params)
 {
        int ret;
 
        wpa_supplicant_notify_scanning(wpa_s, 1);
-       ret = wpa_drv_sched_scan(wpa_s, params, interval * 1000);
+       ret = wpa_drv_sched_scan(wpa_s, params);
        if (ret)
                wpa_supplicant_notify_scanning(wpa_s, 0);
        else
@@ -283,7 +280,7 @@ int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
 }
 
 
-int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
+static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
 {
        int ret;
 
@@ -429,6 +426,39 @@ static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_INTERWORKING */
 
 
+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;
+       enum wpa_driver_if_type type = WPA_IF_STATION;
+
+#ifdef CONFIG_P2P
+       if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT)
+               type = WPA_IF_P2P_CLIENT;
+#endif /* CONFIG_P2P */
+
+       wpa_drv_get_ext_capa(wpa_s, type);
+
+       ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
+                                            sizeof(ext_capab));
+       if (ext_capab_len > 0 &&
+           wpabuf_resize(&default_ies, ext_capab_len) == 0)
+               wpabuf_put_data(default_ies, ext_capab, ext_capab_len);
+
+#ifdef CONFIG_MBO
+       /* Send cellular capabilities for potential MBO STAs */
+       if (wpabuf_resize(&default_ies, 9) == 0)
+               wpas_mbo_scan_ie(wpa_s, default_ies);
+#endif /* CONFIG_MBO */
+
+       if (default_ies)
+               wpa_drv_set_default_scan_ies(wpa_s, wpabuf_head(default_ies),
+                                            wpabuf_len(default_ies));
+       wpabuf_free(default_ies);
+}
+
+
 static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
 {
        struct wpabuf *extra_ie = NULL;
@@ -439,6 +469,13 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
        enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
 #endif /* CONFIG_WPS */
 
+#ifdef CONFIG_P2P
+       if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT)
+               wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
+       else
+#endif /* CONFIG_P2P */
+               wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+
        ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
                                             sizeof(ext_capab));
        if (ext_capab_len > 0 &&
@@ -491,6 +528,19 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
                wpabuf_put_buf(extra_ie, wpa_s->fst_ies);
 #endif /* CONFIG_FST */
 
+#ifdef CONFIG_MBO
+       /* Send cellular capabilities for potential MBO STAs */
+       if (wpabuf_resize(&extra_ie, 9) == 0)
+               wpas_mbo_scan_ie(wpa_s, extra_ie);
+#endif /* CONFIG_MBO */
+
+       if (wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ]) {
+               struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ];
+
+               if (wpabuf_resize(&extra_ie, wpabuf_len(buf)) == 0)
+                       wpabuf_put_buf(extra_ie, buf);
+       }
+
        return extra_ie;
 }
 
@@ -522,21 +572,6 @@ static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s)
 #endif /* CONFIG_P2P */
 
 
-static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
-                                         u16 num_modes,
-                                         enum hostapd_hw_mode mode)
-{
-       u16 i;
-
-       for (i = 0; i < num_modes; i++) {
-               if (modes[i].mode == mode)
-                       return &modes[i];
-       }
-
-       return NULL;
-}
-
-
 static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
                                        enum hostapd_hw_mode band,
                                        struct wpa_driver_scan_params *params)
@@ -586,6 +621,12 @@ static void wpa_set_scan_ssids(struct wpa_supplicant *wpa_s,
        unsigned int i;
        struct wpa_ssid *ssid;
 
+       /*
+        * For devices with max_ssids greater than 1, leave the last slot empty
+        * for adding the wildcard scan entry.
+        */
+       max_ssids = max_ssids > 1 ? max_ssids - 1 : max_ssids;
+
        for (i = 0; i < wpa_s->scan_id_count; i++) {
                unsigned int j;
 
@@ -840,12 +881,10 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                 * slot for the zero-terminator.
                 */
                params.freqs = os_malloc(sizeof(int) * 2);
-               if (params.freqs == NULL) {
-                       wpa_dbg(wpa_s, MSG_ERROR, "Memory allocation failed");
-                       return;
+               if (params.freqs) {
+                       params.freqs[0] = wpa_s->assoc_freq;
+                       params.freqs[1] = 0;
                }
-               params.freqs[0] = wpa_s->assoc_freq;
-               params.freqs[1] = 0;
 
                /*
                 * Reset the reattach flag so that we fall back to full scan if
@@ -1016,6 +1055,27 @@ ssid_list_set:
                }
        }
 
+       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 &&
+                   params.ssids[0].ssid_len == 0) {
+                       params.ssids[0].ssid = bss->ssid;
+                       params.ssids[0].ssid_len = bss->ssid_len;
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "Scan a previously specified BSSID " MACSTR
+                               " and SSID %s",
+                               MAC2STR(params.bssid),
+                               wpa_ssid_txt(bss->ssid, bss->ssid_len));
+               } else {
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "Scan a previously specified BSSID " MACSTR,
+                               MAC2STR(params.bssid));
+               }
+       }
+
        scan_params = &params;
 
 scan:
@@ -1076,6 +1136,8 @@ scan:
 #ifdef CONFIG_INTERWORKING
                wpa_s->interworking_fast_assoc_tried = 0;
 #endif /* CONFIG_INTERWORKING */
+               if (params.bssid)
+                       os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN);
        }
 }
 
@@ -1182,6 +1244,7 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
        unsigned int max_sched_scan_ssids;
        int wildcard = 0;
        int need_ssids;
+       struct sched_scan_plan scan_plan;
 
        if (!wpa_s->sched_scan_supported)
                return -1;
@@ -1193,6 +1256,8 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
        if (max_sched_scan_ssids < 1 || wpa_s->conf->disable_scan_offload)
                return -1;
 
+       wpa_s->sched_scan_stop_req = 0;
+
        if (wpa_s->sched_scanning) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning");
                return 0;
@@ -1271,11 +1336,6 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
 
        if (!ssid || !wpa_s->prev_sched_ssid) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list");
-               if (wpa_s->conf->sched_scan_interval)
-                       wpa_s->sched_scan_interval =
-                               wpa_s->conf->sched_scan_interval;
-               if (wpa_s->sched_scan_interval == 0)
-                       wpa_s->sched_scan_interval = 10;
                wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
                wpa_s->first_sched_scan = 1;
                ssid = wpa_s->conf->ssid;
@@ -1360,14 +1420,51 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
        scan_params = &params;
 
 scan:
-       if (ssid || !wpa_s->first_sched_scan) {
+       wpa_s->sched_scan_timed_out = 0;
+
+       /*
+        * We cannot support multiple scan plans if the scan request includes
+        * too many SSID's, so in this case use only the last scan plan and make
+        * it run infinitely. It will be stopped by the timeout.
+        */
+       if (wpa_s->sched_scan_plans_num == 1 ||
+           (wpa_s->sched_scan_plans_num && !ssid && wpa_s->first_sched_scan)) {
+               params.sched_scan_plans = wpa_s->sched_scan_plans;
+               params.sched_scan_plans_num = wpa_s->sched_scan_plans_num;
+       } else if (wpa_s->sched_scan_plans_num > 1) {
                wpa_dbg(wpa_s, MSG_DEBUG,
-                       "Starting sched scan: interval %d timeout %d",
-                       wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout);
+                       "Too many SSIDs. Default to using single scheduled_scan plan");
+               params.sched_scan_plans =
+                       &wpa_s->sched_scan_plans[wpa_s->sched_scan_plans_num -
+                                                1];
+               params.sched_scan_plans_num = 1;
        } else {
+               if (wpa_s->conf->sched_scan_interval)
+                       scan_plan.interval = wpa_s->conf->sched_scan_interval;
+               else
+                       scan_plan.interval = 10;
+
+               if (scan_plan.interval > wpa_s->max_sched_scan_plan_interval) {
+                       wpa_printf(MSG_WARNING,
+                                  "Scan interval too long(%u), use the maximum allowed(%u)",
+                                  scan_plan.interval,
+                                  wpa_s->max_sched_scan_plan_interval);
+                       scan_plan.interval =
+                               wpa_s->max_sched_scan_plan_interval;
+               }
+
+               scan_plan.iterations = 0;
+               params.sched_scan_plans = &scan_plan;
+               params.sched_scan_plans_num = 1;
+       }
+
+       if (ssid || !wpa_s->first_sched_scan) {
                wpa_dbg(wpa_s, MSG_DEBUG,
-                       "Starting sched scan: interval %d (no timeout)",
-                       wpa_s->sched_scan_interval);
+                       "Starting sched scan: interval %u timeout %d",
+                       params.sched_scan_plans[0].interval,
+                       wpa_s->sched_scan_timeout);
+       } else {
+               wpa_dbg(wpa_s, MSG_DEBUG, "Starting sched scan (no timeout)");
        }
 
        wpa_setband_scan_freqs(wpa_s, scan_params);
@@ -1381,8 +1478,7 @@ scan:
                }
        }
 
-       ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
-                                             wpa_s->sched_scan_interval);
+       ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params);
        wpabuf_free(extra_ie);
        os_free(params.filter_ssids);
        if (ret) {
@@ -1400,9 +1496,12 @@ scan:
                                       wpa_s, NULL);
                wpa_s->first_sched_scan = 0;
                wpa_s->sched_scan_timeout /= 2;
-               wpa_s->sched_scan_interval *= 2;
-               if (wpa_s->sched_scan_timeout < wpa_s->sched_scan_interval) {
-                       wpa_s->sched_scan_interval = 10;
+               params.sched_scan_plans[0].interval *= 2;
+               if ((unsigned int) wpa_s->sched_scan_timeout <
+                   params.sched_scan_plans[0].interval ||
+                   params.sched_scan_plans[0].interval >
+                   wpa_s->max_sched_scan_plan_interval) {
+                       params.sched_scan_plans[0].interval = 10;
                        wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
                }
        }
@@ -1457,6 +1556,9 @@ void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s)
        if (!wpa_s->sched_scanning)
                return;
 
+       if (wpa_s->sched_scanning)
+               wpa_s->sched_scan_stop_req = 1;
+
        wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling sched scan");
        eloop_cancel_timeout(wpa_supplicant_sched_scan_timeout, wpa_s, NULL);
        wpa_supplicant_stop_sched_scan(wpa_s);
@@ -1516,20 +1618,7 @@ static int wpa_scan_get_max_rate(const struct wpa_scan_res *res)
  */
 const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
 {
-       const u8 *end, *pos;
-
-       pos = (const u8 *) (res + 1);
-       end = pos + res->ie_len;
-
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
-                       break;
-               if (pos[0] == ie)
-                       return pos;
-               pos += 2 + pos[1];
-       }
-
-       return NULL;
+       return get_ie((const u8 *) (res + 1), res->ie_len, ie);
 }
 
 
@@ -1550,8 +1639,8 @@ const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
        pos = (const u8 *) (res + 1);
        end = pos + res->ie_len;
 
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
+       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]))
@@ -1587,8 +1676,8 @@ const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res,
        pos += res->ie_len;
        end = pos + res->beacon_ie_len;
 
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
+       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]))
@@ -1623,8 +1712,8 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
        pos = (const u8 *) (res + 1);
        end = pos + res->ie_len;
 
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
+       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]))
@@ -1832,8 +1921,8 @@ int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
 }
 
 
-static void filter_scan_res(struct wpa_supplicant *wpa_s,
-                           struct wpa_scan_results *res)
+void filter_scan_res(struct wpa_supplicant *wpa_s,
+                    struct wpa_scan_results *res)
 {
        size_t i, j;
 
@@ -1860,13 +1949,13 @@ static void filter_scan_res(struct wpa_supplicant *wpa_s,
 
 /*
  * Noise floor values to use when we have signal strength
- * measurements, but no noise floor measurments. These values were
+ * 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)
 
-static void scan_snr(struct wpa_scan_res *res)
+void scan_snr(struct wpa_scan_res *res)
 {
        if (res->flags & WPA_SCAN_NOISE_INVALID) {
                res->noise = IS_5GHZ(res->freq) ?
@@ -1950,8 +2039,8 @@ static unsigned int max_vht80_rate(int snr)
 }
 
 
-static void scan_est_throughput(struct wpa_supplicant *wpa_s,
-                               struct wpa_scan_res *res)
+void scan_est_throughput(struct wpa_supplicant *wpa_s,
+                        struct wpa_scan_res *res)
 {
        enum local_hw_capab capab = wpa_s->hw_capab;
        int rate; /* max legacy rate in 500 kb/s units */
@@ -2148,6 +2237,9 @@ void scan_only_handler(struct wpa_supplicant *wpa_s,
                wpa_s->scan_work = NULL;
                radio_work_done(work);
        }
+
+       if (wpa_s->wpa_state == WPA_SCANNING)
+               wpa_supplicant_set_state(wpa_s, wpa_s->scan_prev_wpa_state);
 }
 
 
@@ -2214,6 +2306,19 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
        params->only_new_results = src->only_new_results;
        params->low_priority = src->low_priority;
 
+       if (src->sched_scan_plans_num > 0) {
+               params->sched_scan_plans =
+                       os_malloc(sizeof(*src->sched_scan_plans) *
+                                 src->sched_scan_plans_num);
+               if (!params->sched_scan_plans)
+                       goto failed;
+
+               os_memcpy(params->sched_scan_plans, src->sched_scan_plans,
+                         sizeof(*src->sched_scan_plans) *
+                         src->sched_scan_plans_num);
+               params->sched_scan_plans_num = src->sched_scan_plans_num;
+       }
+
        if (src->mac_addr_rand) {
                params->mac_addr_rand = src->mac_addr_rand;
 
@@ -2231,6 +2336,17 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
                        params->mac_addr_mask = mac_addr + ETH_ALEN;
                }
        }
+
+       if (src->bssid) {
+               u8 *bssid;
+
+               bssid = os_malloc(ETH_ALEN);
+               if (!bssid)
+                       goto failed;
+               os_memcpy(bssid, src->bssid, ETH_ALEN);
+               params->bssid = bssid;
+       }
+
        return params;
 
 failed:
@@ -2251,6 +2367,7 @@ void wpa_scan_free_params(struct wpa_driver_scan_params *params)
        os_free((u8 *) params->extra_ies);
        os_free(params->freqs);
        os_free(params->filter_ssids);
+       os_free(params->sched_scan_plans);
 
        /*
         * Note: params->mac_addr_mask points to same memory allocation and
@@ -2258,20 +2375,31 @@ void wpa_scan_free_params(struct wpa_driver_scan_params *params)
         */
        os_free((u8 *) params->mac_addr);
 
+       os_free((u8 *) params->bssid);
+
        os_free(params);
 }
 
 
 int wpas_start_pno(struct wpa_supplicant *wpa_s)
 {
-       int ret, interval, prio;
+       int ret, prio;
        size_t i, num_ssid, num_match_ssid;
        struct wpa_ssid *ssid;
        struct wpa_driver_scan_params params;
+       struct sched_scan_plan scan_plan;
+       unsigned int max_sched_scan_ssids;
 
        if (!wpa_s->sched_scan_supported)
                return -1;
 
+       if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS)
+               max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS;
+       else
+               max_sched_scan_ssids = wpa_s->max_sched_scan_ssids;
+       if (max_sched_scan_ssids < 1)
+               return -1;
+
        if (wpa_s->pno || wpa_s->pno_sched_pending)
                return 0;
 
@@ -2292,6 +2420,13 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s)
                }
        }
 
+       if (wpa_s->sched_scan_stop_req) {
+               wpa_printf(MSG_DEBUG,
+                          "Schedule PNO after previous sched scan has stopped");
+               wpa_s->pno_sched_pending = 1;
+               return 0;
+       }
+
        os_memset(&params, 0, sizeof(params));
 
        num_ssid = num_match_ssid = 0;
@@ -2315,10 +2450,10 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s)
                num_ssid++;
        }
 
-       if (num_ssid > WPAS_MAX_SCAN_SSIDS) {
+       if (num_ssid > max_sched_scan_ssids) {
                wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from "
-                          "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid);
-               num_ssid = WPAS_MAX_SCAN_SSIDS;
+                          "%u", max_sched_scan_ssids, (unsigned int) num_ssid);
+               num_ssid = max_sched_scan_ssids;
        }
 
        if (num_match_ssid > wpa_s->max_match_sets) {
@@ -2361,8 +2496,20 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s)
        if (wpa_s->conf->filter_rssi)
                params.filter_rssi = wpa_s->conf->filter_rssi;
 
-       interval = wpa_s->conf->sched_scan_interval ?
-               wpa_s->conf->sched_scan_interval : 10;
+       if (wpa_s->sched_scan_plans_num) {
+               params.sched_scan_plans = wpa_s->sched_scan_plans;
+               params.sched_scan_plans_num = wpa_s->sched_scan_plans_num;
+       } else {
+               /* Set one scan plan that will run infinitely */
+               if (wpa_s->conf->sched_scan_interval)
+                       scan_plan.interval = wpa_s->conf->sched_scan_interval;
+               else
+                       scan_plan.interval = 10;
+
+               scan_plan.iterations = 0;
+               params.sched_scan_plans = &scan_plan;
+               params.sched_scan_plans_num = 1;
+       }
 
        if (params.freqs == NULL && wpa_s->manual_sched_scan_freqs) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Limit sched scan to specified channels");
@@ -2377,7 +2524,7 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s)
                }
        }
 
-       ret = wpa_supplicant_start_sched_scan(wpa_s, &params, interval);
+       ret = wpa_supplicant_start_sched_scan(wpa_s, &params);
        os_free(params.filter_ssids);
        if (ret == 0)
                wpa_s->pno = 1;
@@ -2395,6 +2542,7 @@ int wpas_stop_pno(struct wpa_supplicant *wpa_s)
                return 0;
 
        ret = wpa_supplicant_stop_sched_scan(wpa_s);
+       wpa_s->sched_scan_stop_req = 1;
 
        wpa_s->pno = 0;
        wpa_s->pno_sched_pending = 0;
@@ -2462,3 +2610,160 @@ int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
        wpa_s->mac_addr_rand_enable |= type;
        return 0;
 }
+
+
+int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s)
+{
+       int scan_work = !!wpa_s->scan_work;
+
+#ifdef CONFIG_P2P
+       scan_work |= !!wpa_s->p2p_scan_work;
+#endif /* CONFIG_P2P */
+
+       if (scan_work && wpa_s->own_scan_running) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "Abort an ongoing scan");
+               return wpa_drv_abort_scan(wpa_s);
+       }
+
+       return 0;
+}
+
+
+int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+       struct sched_scan_plan *scan_plans = NULL;
+       const char *token, *context = NULL;
+       unsigned int num = 0;
+
+       if (!cmd)
+               return -1;
+
+       if (!cmd[0]) {
+               wpa_printf(MSG_DEBUG, "Clear sched scan plans");
+               os_free(wpa_s->sched_scan_plans);
+               wpa_s->sched_scan_plans = NULL;
+               wpa_s->sched_scan_plans_num = 0;
+               return 0;
+       }
+
+       while ((token = cstr_token(cmd, " ", &context))) {
+               int ret;
+               struct sched_scan_plan *scan_plan, *n;
+
+               n = os_realloc_array(scan_plans, num + 1, sizeof(*scan_plans));
+               if (!n)
+                       goto fail;
+
+               scan_plans = n;
+               scan_plan = &scan_plans[num];
+               num++;
+
+               ret = sscanf(token, "%u:%u", &scan_plan->interval,
+                            &scan_plan->iterations);
+               if (ret <= 0 || ret > 2 || !scan_plan->interval) {
+                       wpa_printf(MSG_ERROR,
+                                  "Invalid sched scan plan input: %s", token);
+                       goto fail;
+               }
+
+               if (scan_plan->interval > wpa_s->max_sched_scan_plan_interval) {
+                       wpa_printf(MSG_WARNING,
+                                  "scan plan %u: Scan interval too long(%u), use the maximum allowed(%u)",
+                                  num, scan_plan->interval,
+                                  wpa_s->max_sched_scan_plan_interval);
+                       scan_plan->interval =
+                               wpa_s->max_sched_scan_plan_interval;
+               }
+
+               if (ret == 1) {
+                       scan_plan->iterations = 0;
+                       break;
+               }
+
+               if (!scan_plan->iterations) {
+                       wpa_printf(MSG_ERROR,
+                                  "scan plan %u: Number of iterations cannot be zero",
+                                  num);
+                       goto fail;
+               }
+
+               if (scan_plan->iterations >
+                   wpa_s->max_sched_scan_plan_iterations) {
+                       wpa_printf(MSG_WARNING,
+                                  "scan plan %u: Too many iterations(%u), use the maximum allowed(%u)",
+                                  num, scan_plan->iterations,
+                                  wpa_s->max_sched_scan_plan_iterations);
+                       scan_plan->iterations =
+                               wpa_s->max_sched_scan_plan_iterations;
+               }
+
+               wpa_printf(MSG_DEBUG,
+                          "scan plan %u: interval=%u iterations=%u",
+                          num, scan_plan->interval, scan_plan->iterations);
+       }
+
+       if (!scan_plans) {
+               wpa_printf(MSG_ERROR, "Invalid scan plans entry");
+               goto fail;
+       }
+
+       if (cstr_token(cmd, " ", &context) || scan_plans[num - 1].iterations) {
+               wpa_printf(MSG_ERROR,
+                          "All scan plans but the last must specify a number of iterations");
+               goto fail;
+       }
+
+       wpa_printf(MSG_DEBUG, "scan plan %u (last plan): interval=%u",
+                  num, scan_plans[num - 1].interval);
+
+       if (num > wpa_s->max_sched_scan_plans) {
+               wpa_printf(MSG_WARNING,
+                          "Too many scheduled scan plans (only %u supported)",
+                          wpa_s->max_sched_scan_plans);
+               wpa_printf(MSG_WARNING,
+                          "Use only the first %u scan plans, and the last one (in infinite loop)",
+                          wpa_s->max_sched_scan_plans - 1);
+               os_memcpy(&scan_plans[wpa_s->max_sched_scan_plans - 1],
+                         &scan_plans[num - 1], sizeof(*scan_plans));
+               num = wpa_s->max_sched_scan_plans;
+       }
+
+       os_free(wpa_s->sched_scan_plans);
+       wpa_s->sched_scan_plans = scan_plans;
+       wpa_s->sched_scan_plans_num = num;
+
+       return 0;
+
+fail:
+       os_free(scan_plans);
+       wpa_printf(MSG_ERROR, "invalid scan plans list");
+       return -1;
+}
+
+
+/**
+ * wpas_scan_reset_sched_scan - Reset sched_scan state
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to cancel a running scheduled scan and to reset an
+ * internal scan state to continue with a regular scan on the following
+ * wpa_supplicant_req_scan() calls.
+ */
+void wpas_scan_reset_sched_scan(struct wpa_supplicant *wpa_s)
+{
+       wpa_s->normal_scans = 0;
+       if (wpa_s->sched_scanning) {
+               wpa_s->sched_scan_timed_out = 0;
+               wpa_s->prev_sched_ssid = NULL;
+               wpa_supplicant_cancel_sched_scan(wpa_s);
+       }
+}
+
+
+void wpas_scan_restart_sched_scan(struct wpa_supplicant *wpa_s)
+{
+       /* simulate timeout to restart the sched scan */
+       wpa_s->sched_scan_timed_out = 1;
+       wpa_s->prev_sched_ssid = NULL;
+       wpa_supplicant_cancel_sched_scan(wpa_s);
+}
index 7650f5a..2aa0a8b 100644 (file)
@@ -39,20 +39,25 @@ void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec);
 void scan_only_handler(struct wpa_supplicant *wpa_s,
                       struct wpa_scan_results *scan_res);
 int wpas_scan_scheduled(struct wpa_supplicant *wpa_s);
-int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
-                                   struct wpa_driver_scan_params *params,
-                                   int interval);
-int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s);
 struct wpa_driver_scan_params *
 wpa_scan_clone_params(const struct wpa_driver_scan_params *src);
 void wpa_scan_free_params(struct wpa_driver_scan_params *params);
 int wpas_start_pno(struct wpa_supplicant *wpa_s);
 int wpas_stop_pno(struct wpa_supplicant *wpa_s);
+void wpas_scan_reset_sched_scan(struct wpa_supplicant *wpa_s);
+void wpas_scan_restart_sched_scan(struct wpa_supplicant *wpa_s);
 
 void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s,
                                   unsigned int type);
 int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
                                unsigned int type, const u8 *addr,
                                const 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);
+void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s);
 
 #endif /* SCAN_H */
index f2e5a43..61fd3b2 100644 (file)
@@ -161,9 +161,10 @@ static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s,
                return;
        }
 
-       if (!(wpa_s->drv_rrm_flags &
-             WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) ||
-           !(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) {
+       if (!((wpa_s->drv_rrm_flags &
+              WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) &&
+             (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) &&
+           !(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_RRM)) {
                wpa_printf(MSG_DEBUG,
                           "RRM: Insufficient RRM support in driver - do not use RRM");
                return;
@@ -186,6 +187,9 @@ static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s,
        if (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)
                *pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT;
 
+       if (wpa_s->lci)
+               pos[1] |= WLAN_RRM_CAPS_LCI_MEASUREMENT;
+
        wpa_s->sme.assoc_req_ie_len += rrm_ie_len + 2;
        wpa_s->rrm.rrm_used = 1;
 }
@@ -208,6 +212,9 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
        u8 ext_capab[18];
        int ext_capab_len;
        int skip_auth;
+#ifdef CONFIG_MBO
+       const u8 *mbo;
+#endif /* CONFIG_MBO */
 
        if (bss == NULL) {
                wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
@@ -416,28 +423,6 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_P2P */
 
-#ifdef CONFIG_HS20
-       if (is_hs20_network(wpa_s, ssid, bss)) {
-               struct wpabuf *hs20;
-               hs20 = wpabuf_alloc(20);
-               if (hs20) {
-                       int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
-                       size_t len;
-
-                       wpas_hs20_add_indication(hs20, pps_mo_id);
-                       len = sizeof(wpa_s->sme.assoc_req_ie) -
-                               wpa_s->sme.assoc_req_ie_len;
-                       if (wpabuf_len(hs20) <= len) {
-                               os_memcpy(wpa_s->sme.assoc_req_ie +
-                                         wpa_s->sme.assoc_req_ie_len,
-                                         wpabuf_head(hs20), wpabuf_len(hs20));
-                               wpa_s->sme.assoc_req_ie_len += wpabuf_len(hs20);
-                       }
-                       wpabuf_free(hs20);
-               }
-       }
-#endif /* CONFIG_HS20 */
-
 #ifdef CONFIG_FST
        if (wpa_s->fst_ies) {
                int fst_ies_len = wpabuf_len(wpa_s->fst_ies);
@@ -453,6 +438,28 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_FST */
 
+       sme_auth_handle_rrm(wpa_s, bss);
+
+#ifdef CONFIG_MBO
+       mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
+       if (mbo) {
+               int len;
+
+               len = wpas_mbo_supp_op_class_ie(
+                       wpa_s, bss->freq,
+                       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);
+               if (len > 0)
+                       wpa_s->sme.assoc_req_ie_len += len;
+       }
+#endif /* CONFIG_MBO */
+
+       if (params.p2p)
+               wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
+       else
+               wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+
        ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
                                             sizeof(ext_capab));
        if (ext_capab_len > 0) {
@@ -466,6 +473,29 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
                os_memcpy(pos, ext_capab, ext_capab_len);
        }
 
+#ifdef CONFIG_HS20
+       if (is_hs20_network(wpa_s, ssid, bss)) {
+               struct wpabuf *hs20;
+
+               hs20 = wpabuf_alloc(20);
+               if (hs20) {
+                       int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
+                       size_t len;
+
+                       wpas_hs20_add_indication(hs20, pps_mo_id);
+                       len = sizeof(wpa_s->sme.assoc_req_ie) -
+                               wpa_s->sme.assoc_req_ie_len;
+                       if (wpabuf_len(hs20) <= len) {
+                               os_memcpy(wpa_s->sme.assoc_req_ie +
+                                         wpa_s->sme.assoc_req_ie_len,
+                                         wpabuf_head(hs20), wpabuf_len(hs20));
+                               wpa_s->sme.assoc_req_ie_len += wpabuf_len(hs20);
+                       }
+                       wpabuf_free(hs20);
+               }
+       }
+#endif /* CONFIG_HS20 */
+
        if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
                struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
                size_t len;
@@ -480,7 +510,18 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
                }
        }
 
-       sme_auth_handle_rrm(wpa_s, bss);
+#ifdef CONFIG_MBO
+       if (mbo) {
+               int len;
+
+               len = wpas_mbo_ie(wpa_s, 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);
+               if (len >= 0)
+                       wpa_s->sme.assoc_req_ie_len += len;
+       }
+#endif /* CONFIG_MBO */
 
 #ifdef CONFIG_SAE
        if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE &&
@@ -524,6 +565,10 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
        if (old_ssid != wpa_s->current_ssid)
                wpas_notify_network_changed(wpa_s);
 
+#ifdef CONFIG_HS20
+       hs20_configure_frame_filters(wpa_s);
+#endif /* CONFIG_HS20 */
+
 #ifdef CONFIG_P2P
        /*
         * If multi-channel concurrency is not supported, check for any
@@ -632,6 +677,8 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                radio_remove_works(wpa_s, "sme-connect", 0);
        }
 
+       wpas_abort_ongoing_scan(wpa_s);
+
        cwork = os_zalloc(sizeof(*cwork));
        if (cwork == NULL)
                return;
@@ -812,7 +859,7 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
                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->pending_bssid);
+                              wpa_s->sme.sae.pmkid, wpa_s->pending_bssid);
        }
 #endif /* CONFIG_SAE */
 
@@ -975,8 +1022,8 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
        if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)
                params.p2p = 1;
 
-       if (wpa_s->parent->set_sta_uapsd)
-               params.uapsd = wpa_s->parent->sta_uapsd;
+       if (wpa_s->p2pdev->set_sta_uapsd)
+               params.uapsd = wpa_s->p2pdev->sta_uapsd;
        else
                params.uapsd = -1;
 
@@ -1320,21 +1367,6 @@ int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
 }
 
 
-static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
-                                         u16 num_modes,
-                                         enum hostapd_hw_mode mode)
-{
-       u16 i;
-
-       for (i = 0; i < num_modes; i++) {
-               if (modes[i].mode == mode)
-                       return &modes[i];
-       }
-
-       return NULL;
-}
-
-
 static void wpa_obss_scan_freqs_list(struct wpa_supplicant *wpa_s,
                                     struct wpa_driver_scan_params *params)
 {
@@ -1553,8 +1585,10 @@ static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
        nbuf = os_realloc_array(wpa_s->sme.sa_query_trans_id,
                                wpa_s->sme.sa_query_count + 1,
                                WLAN_SA_QUERY_TR_ID_LEN);
-       if (nbuf == NULL)
+       if (nbuf == NULL) {
+               sme_stop_sa_query(wpa_s);
                return;
+       }
        if (wpa_s->sme.sa_query_count == 0) {
                /* Starting a new SA Query procedure */
                os_get_reltime(&wpa_s->sme.sa_query_start);
@@ -1565,6 +1599,7 @@ static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
 
        if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) {
                wpa_printf(MSG_DEBUG, "Could not generate SA Query ID");
+               sme_stop_sa_query(wpa_s);
                return;
        }
 
index ea964ce..bc5d49a 100644 (file)
@@ -5,9 +5,9 @@ Wants=network.target
 
 [Service]
 Type=dbus
-BusName=fi.epitest.hostap.WPASupplicant
+BusName=@DBUS_INTERFACE@
 ExecStart=@BINDIR@/wpa_supplicant -u
 
 [Install]
 WantedBy=multi-user.target
-Alias=dbus-fi.epitest.hostap.WPASupplicant.service
+Alias=dbus-@DBUS_INTERFACE@.service
diff --git a/libeap/wpa_supplicant/tests/link_test.c b/libeap/wpa_supplicant/tests/link_test.c
deleted file mode 100644 (file)
index 3bfbed5..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Dummy functions to allow link_test to be linked. The need for these
- * functions should be removed to allow IEEE 802.1X/EAPOL authenticator to
- * be built outside hostapd.
- */
-
-#include "includes.h"
-
-#include "common.h"
-
-
-struct hostapd_data;
-struct sta_info;
-struct rsn_pmksa_cache_entry;
-struct eapol_state_machine;
-struct hostapd_eap_user;
-struct hostapd_bss_config;
-struct hostapd_vlan;
-
-
-struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
-{
-       return NULL;
-}
-
-
-int ap_for_each_sta(struct hostapd_data *hapd,
-                   int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
-                             void *ctx),
-                   void *ctx)
-{
-       return 0;
-}
-
-
-void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
-                           u32 session_timeout)
-{
-}
-
-
-int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
-                    int old_vlanid)
-{
-       return 0;
-}
-
-
-void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
-                         int success)
-{
-}
-
-
-void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
-                     u8 *buf, size_t len)
-{
-}
-
-
-void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
-{
-}
-
-
-void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
-                              struct eapol_state_machine *eapol)
-{
-}
-
-
-const struct hostapd_eap_user *
-hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
-                    size_t identity_len, int phase2)
-{
-       return NULL;
-}
-
-
-const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
-{
-       return NULL;
-}
diff --git a/libeap/wpa_supplicant/tests/test_eap_sim_common.c b/libeap/wpa_supplicant/tests/test_eap_sim_common.c
deleted file mode 100644 (file)
index f60b182..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Test program for EAP-SIM PRF
- * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "eap_common/eap_sim_common.c"
-
-
-static int test_eap_sim_prf(void)
-{
-       /* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
-       u8 xkey[] = {
-               0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
-               0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
-               0xeb, 0x5a, 0x38, 0xb6
-       };
-       u8 w[] = {
-               0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
-               0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
-               0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
-               0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
-               0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
-       };
-       u8 buf[40];
-
-       printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n");
-       eap_sim_prf(xkey, buf, sizeof(buf));
-       if (memcmp(w, buf, sizeof(w)) != 0) {
-               printf("eap_sim_prf failed\n");
-               return 1;
-       }
-
-       return 0;
-}
-
-
-int main(int argc, char *argv[])
-{
-       int errors = 0;
-
-       errors += test_eap_sim_prf();
-
-       return errors;
-}
diff --git a/libeap/wpa_supplicant/tests/test_wpa.c b/libeap/wpa_supplicant/tests/test_wpa.c
deleted file mode 100644 (file)
index 39971f2..0000000
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Test program for combined WPA authenticator/supplicant
- * Copyright (c) 2006-2007, 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 "common/ieee802_11_defs.h"
-#include "../config.h"
-#include "rsn_supp/wpa.h"
-#include "rsn_supp/wpa_ie.h"
-#include "ap/wpa_auth.h"
-
-
-struct wpa {
-       u8 auth_addr[ETH_ALEN];
-       u8 supp_addr[ETH_ALEN];
-       u8 psk[PMK_LEN];
-
-       /* from authenticator */
-       u8 auth_eapol_dst[ETH_ALEN];
-       u8 *auth_eapol;
-       size_t auth_eapol_len;
-
-       /* from supplicant */
-       u8 *supp_eapol;
-       size_t supp_eapol_len;
-
-       struct wpa_sm *supp;
-       struct wpa_authenticator *auth_group;
-       struct wpa_state_machine *auth;
-
-       struct wpa_ssid ssid;
-       u8 supp_ie[80];
-       size_t supp_ie_len;
-};
-
-
-static int supp_get_bssid(void *ctx, u8 *bssid)
-{
-       struct wpa *wpa = ctx;
-       wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
-       os_memcpy(bssid, wpa->auth_addr, ETH_ALEN);
-       return 0;
-}
-
-
-static void supp_set_state(void *ctx, enum wpa_states state)
-{
-       wpa_printf(MSG_DEBUG, "SUPP: %s(state=%d)", __func__, state);
-}
-
-
-static void auth_eapol_rx(void *eloop_data, void *user_ctx)
-{
-       struct wpa *wpa = eloop_data;
-
-       wpa_printf(MSG_DEBUG, "AUTH: RX EAPOL frame");
-       wpa_receive(wpa->auth_group, wpa->auth, wpa->supp_eapol,
-                   wpa->supp_eapol_len);
-}
-
-
-static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
-                          size_t len)
-{
-       struct wpa *wpa = ctx;
-
-       wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x "
-                  "len=%lu)",
-                  __func__, MAC2STR(dest), proto, (unsigned long) len);
-
-       os_free(wpa->supp_eapol);
-       wpa->supp_eapol = os_malloc(len);
-       if (wpa->supp_eapol == NULL)
-               return -1;
-       os_memcpy(wpa->supp_eapol, buf, len);
-       wpa->supp_eapol_len = len;
-       eloop_register_timeout(0, 0, auth_eapol_rx, wpa, NULL);
-
-       return 0;
-}
-
-
-static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data,
-                            u16 data_len, size_t *msg_len, void **data_pos)
-{
-       struct ieee802_1x_hdr *hdr;
-
-       wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)",
-                  __func__, type, data_len);
-
-       *msg_len = sizeof(*hdr) + data_len;
-       hdr = os_malloc(*msg_len);
-       if (hdr == NULL)
-               return NULL;
-
-       hdr->version = 2;
-       hdr->type = type;
-       hdr->length = host_to_be16(data_len);
-
-       if (data)
-               os_memcpy(hdr + 1, data, data_len);
-       else
-               os_memset(hdr + 1, 0, data_len);
-
-       if (data_pos)
-               *data_pos = hdr + 1;
-
-       return (u8 *) hdr;
-}
-
-
-static int supp_get_beacon_ie(void *ctx)
-{
-       struct wpa *wpa = ctx;
-       const u8 *ie;
-       size_t ielen;
-
-       wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
-
-       ie = wpa_auth_get_wpa_ie(wpa->auth_group, &ielen);
-       if (ie == NULL || ielen < 1)
-               return -1;
-       if (ie[0] == WLAN_EID_RSN)
-               return wpa_sm_set_ap_rsn_ie(wpa->supp, ie, 2 + ie[1]);
-       return wpa_sm_set_ap_wpa_ie(wpa->supp, ie, 2 + ie[1]);
-}
-
-
-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)
-{
-       wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d "
-                  "set_tx=%d)",
-                  __func__, alg, MAC2STR(addr), key_idx, set_tx);
-       wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len);
-       wpa_hexdump(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
-       return 0;
-}
-
-
-static int supp_mlme_setprotection(void *ctx, const u8 *addr,
-                                  int protection_type, int key_type)
-{
-       wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d "
-                  "key_type=%d)",
-                  __func__, MAC2STR(addr), protection_type, key_type);
-       return 0;
-}
-
-
-static void supp_cancel_auth_timeout(void *ctx)
-{
-       wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
-}
-
-
-static int supp_init(struct wpa *wpa)
-{
-       struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx));
-       if (ctx == NULL)
-               return -1;
-
-       ctx->ctx = wpa;
-       ctx->msg_ctx = wpa;
-       ctx->set_state = supp_set_state;
-       ctx->get_bssid = supp_get_bssid;
-       ctx->ether_send = supp_ether_send;
-       ctx->get_beacon_ie = supp_get_beacon_ie;
-       ctx->alloc_eapol = supp_alloc_eapol;
-       ctx->set_key = supp_set_key;
-       ctx->mlme_setprotection = supp_mlme_setprotection;
-       ctx->cancel_auth_timeout = supp_cancel_auth_timeout;
-       wpa->supp = wpa_sm_init(ctx);
-       if (wpa->supp == NULL) {
-               wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
-               return -1;
-       }
-
-       wpa_sm_set_own_addr(wpa->supp, wpa->supp_addr);
-       wpa_sm_set_param(wpa->supp, WPA_PARAM_RSN_ENABLED, 1);
-       wpa_sm_set_param(wpa->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN);
-       wpa_sm_set_param(wpa->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP);
-       wpa_sm_set_param(wpa->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
-       wpa_sm_set_param(wpa->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK);
-       wpa_sm_set_pmk(wpa->supp, wpa->psk, PMK_LEN);
-
-       wpa->supp_ie_len = sizeof(wpa->supp_ie);
-       if (wpa_sm_set_assoc_wpa_ie_default(wpa->supp, wpa->supp_ie,
-                                           &wpa->supp_ie_len) < 0) {
-               wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()"
-                          " failed");
-               return -1;
-       }
-
-       wpa_sm_notify_assoc(wpa->supp, wpa->auth_addr);
-
-       return 0;
-}
-
-
-static void auth_logger(void *ctx, const u8 *addr, logger_level level,
-                       const char *txt)
-{
-       if (addr)
-               wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s",
-                          MAC2STR(addr), txt);
-       else
-               wpa_printf(MSG_DEBUG, "AUTH: %s", txt);
-}
-
-
-static void supp_eapol_rx(void *eloop_data, void *user_ctx)
-{
-       struct wpa *wpa = eloop_data;
-
-       wpa_printf(MSG_DEBUG, "SUPP: RX EAPOL frame");
-       wpa_sm_rx_eapol(wpa->supp, wpa->auth_addr, wpa->auth_eapol,
-                       wpa->auth_eapol_len);
-}
-
-
-static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
-                          size_t data_len, int encrypt)
-{
-       struct wpa *wpa = ctx;
-
-       wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu "
-                  "encrypt=%d)",
-                  __func__, MAC2STR(addr), (unsigned long) data_len, encrypt);
-
-       os_free(wpa->auth_eapol);
-       wpa->auth_eapol = os_malloc(data_len);
-       if (wpa->auth_eapol == NULL)
-               return -1;
-       os_memcpy(wpa->auth_eapol_dst, addr, ETH_ALEN);
-       os_memcpy(wpa->auth_eapol, data, data_len);
-       wpa->auth_eapol_len = data_len;
-       eloop_register_timeout(0, 0, supp_eapol_rx, wpa, NULL);
-
-       return 0;
-}
-
-
-static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk)
-{
-       struct wpa *wpa = ctx;
-       wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
-                  __func__, MAC2STR(addr), prev_psk);
-       if (prev_psk)
-               return NULL;
-       return wpa->psk;
-}
-
-
-static int auth_init_group(struct wpa *wpa)
-{
-       struct wpa_auth_config conf;
-       struct wpa_auth_callbacks cb;
-
-       wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
-
-       os_memset(&conf, 0, sizeof(conf));
-       conf.wpa = 2;
-       conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK;
-       conf.wpa_pairwise = WPA_CIPHER_CCMP;
-       conf.rsn_pairwise = WPA_CIPHER_CCMP;
-       conf.wpa_group = WPA_CIPHER_CCMP;
-       conf.eapol_version = 2;
-
-       os_memset(&cb, 0, sizeof(cb));
-       cb.ctx = wpa;
-       cb.logger = auth_logger;
-       cb.send_eapol = auth_send_eapol;
-       cb.get_psk = auth_get_psk;
-
-       wpa->auth_group = wpa_init(wpa->auth_addr, &conf, &cb);
-       if (wpa->auth_group == NULL) {
-               wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
-               return -1;
-       }
-
-       return 0;
-}
-
-
-static int auth_init(struct wpa *wpa)
-{
-       wpa->auth = wpa_auth_sta_init(wpa->auth_group, wpa->supp_addr, NULL);
-       if (wpa->auth == NULL) {
-               wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed");
-               return -1;
-       }
-
-       if (wpa_validate_wpa_ie(wpa->auth_group, wpa->auth, wpa->supp_ie,
-                               wpa->supp_ie_len, NULL, 0) != WPA_IE_OK) {
-               wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
-               return -1;
-       }
-
-       wpa_auth_sm_event(wpa->auth, WPA_ASSOC);
-
-       wpa_auth_sta_associated(wpa->auth_group, wpa->auth);
-
-       return 0;
-}
-
-
-static void deinit(struct wpa *wpa)
-{
-       wpa_auth_sta_deinit(wpa->auth);
-       wpa_sm_deinit(wpa->supp);
-       wpa_deinit(wpa->auth_group);
-       os_free(wpa->auth_eapol);
-       wpa->auth_eapol = NULL;
-       os_free(wpa->supp_eapol);
-       wpa->supp_eapol = NULL;
-}
-
-
-int main(int argc, char *argv[])
-{
-       struct wpa wpa;
-
-       if (os_program_init())
-               return -1;
-
-       os_memset(&wpa, 0, sizeof(wpa));
-       os_memset(wpa.auth_addr, 0x12, ETH_ALEN);
-       os_memset(wpa.supp_addr, 0x32, ETH_ALEN);
-       os_memset(wpa.psk, 0x44, PMK_LEN);
-
-       wpa_debug_level = 0;
-       wpa_debug_show_keys = 1;
-
-       if (eloop_init()) {
-               wpa_printf(MSG_ERROR, "Failed to initialize event loop");
-               return -1;
-       }
-
-       if (auth_init_group(&wpa) < 0)
-               return -1;
-
-       if (supp_init(&wpa) < 0)
-               return -1;
-
-       if (auth_init(&wpa) < 0)
-               return -1;
-
-       wpa_printf(MSG_DEBUG, "Starting eloop");
-       eloop_run();
-       wpa_printf(MSG_DEBUG, "eloop done");
-
-       deinit(&wpa);
-
-       eloop_destroy();
-
-       os_program_deinit();
-
-       return 0;
-}
index 5171b16..0d15ad0 100644 (file)
@@ -88,7 +88,7 @@ enum ts_dir_idx {
  */
 struct wmm_ac_addts_request {
        /*
-        * dialog token - Used to link the recived ADDTS response with this
+        * dialog token - Used to link the received ADDTS response with this
         * saved ADDTS request when ADDTS response is being handled
         */
        u8 dialog_token;
index 954de67..1b3409c 100644 (file)
@@ -24,6 +24,7 @@
 #define MAX_TFS_IE_LEN  1024
 #define WNM_MAX_NEIGHBOR_REPORT 10
 
+#define WNM_SCAN_RESULT_AGE 2 /* 2 seconds */
 
 /* get the TFS IE from driver */
 static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf,
@@ -37,12 +38,14 @@ static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf,
 
 /* set the TFS IE to driver */
 static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s,
-                                  const u8 *addr, u8 *buf, u16 *buf_len,
+                                  const u8 *addr, const u8 *buf, u16 buf_len,
                                   enum wnm_oper oper)
 {
+       u16 len = buf_len;
+
        wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
 
-       return wpa_drv_wnm_oper(wpa_s, oper, addr, buf, buf_len);
+       return wpa_drv_wnm_oper(wpa_s, oper, addr, (u8 *) buf, &len);
 }
 
 
@@ -137,6 +140,8 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
        if (res < 0)
                wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request "
                           "(action=%d, intval=%d)", action, intval);
+       else
+               wpa_s->wnmsleep_used = 1;
 
        os_free(wnmsleep_ie);
        os_free(wnmtfs_ie);
@@ -147,8 +152,8 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
 
 
 static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s,
-                                        u8 *tfsresp_ie_start,
-                                        u8 *tfsresp_ie_end)
+                                        const u8 *tfsresp_ie_start,
+                                        const u8 *tfsresp_ie_end)
 {
        wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM,
                         wpa_s->bssid, NULL, NULL);
@@ -164,7 +169,7 @@ static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s,
                /* pass the TFS Resp IE(s) to driver for processing */
                if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid,
                                            tfsresp_ie_start,
-                                           &tfsresp_ie_len,
+                                           tfsresp_ie_len,
                                            WNM_SLEEP_TFS_RESP_IE_SET))
                        wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE");
        }
@@ -187,8 +192,14 @@ static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s,
        end = ptr + key_len_total;
        wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total);
 
-       while (ptr + 1 < end) {
-               if (ptr + 2 + ptr[1] > end) {
+       if (key_len_total && !wpa_sm_pmf_enabled(wpa_s->wpa)) {
+               wpa_msg(wpa_s, MSG_INFO,
+                       "WNM: Ignore Key Data in WNM-Sleep Mode Response - PMF not enabled");
+               return;
+       }
+
+       while (end - ptr > 1) {
+               if (2 + ptr[1] > end - ptr) {
                        wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element "
                                   "length");
                        if (end > ptr) {
@@ -239,14 +250,20 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
         * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data |
         * WNM-Sleep Mode IE | TFS Response IE
         */
-       u8 *pos = (u8 *) frm; /* point to payload after the action field */
+       const u8 *pos = frm; /* point to payload after the action field */
        u16 key_len_total;
        struct wnm_sleep_element *wnmsleep_ie = NULL;
        /* multiple TFS Resp IE (assuming consecutive) */
-       u8 *tfsresp_ie_start = NULL;
-       u8 *tfsresp_ie_end = NULL;
+       const u8 *tfsresp_ie_start = NULL;
+       const u8 *tfsresp_ie_end = NULL;
        size_t left;
 
+       if (!wpa_s->wnmsleep_used) {
+               wpa_printf(MSG_DEBUG,
+                          "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode has not been used in this association");
+               return;
+       }
+
        if (len < 3)
                return;
        key_len_total = WPA_GET_LE16(frm + 1);
@@ -259,14 +276,14 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
                return;
        }
        pos += 3 + key_len_total;
-       while (pos - frm < len) {
+       while (pos - frm + 1 < len) {
                u8 ie_len = *(pos + 1);
-               if (pos + 2 + ie_len > frm + len) {
+               if (2 + ie_len > frm + len - pos) {
                        wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len);
                        break;
                }
                wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len);
-               if (*pos == WLAN_EID_WNMSLEEP)
+               if (*pos == WLAN_EID_WNMSLEEP && ie_len >= 4)
                        wnmsleep_ie = (struct wnm_sleep_element *) pos;
                else if (*pos == WLAN_EID_TFS_RESP) {
                        if (!tfsresp_ie_start)
@@ -413,6 +430,7 @@ static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan)
 {
        struct wpa_bss *bss = wpa_s->current_bss;
        const char *country = NULL;
+       int freq;
 
        if (bss) {
                const u8 *elem = wpa_bss_get_ie(bss, WLAN_EID_COUNTRY);
@@ -421,7 +439,21 @@ static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan)
                        country = (const char *) (elem + 2);
        }
 
-       return ieee80211_chan_to_freq(country, op_class, chan);
+       freq = ieee80211_chan_to_freq(country, op_class, chan);
+       if (freq <= 0 && op_class == 0) {
+               /*
+                * Some APs do not advertise correct operating class
+                * information. Try to determine the most likely operating
+                * frequency based on the channel number.
+                */
+               if (chan >= 1 && chan <= 13)
+                       freq = 2407 + chan * 5;
+               else if (chan == 14)
+                       freq = 2484;
+               else if (chan >= 36 && chan <= 169)
+                       freq = 5000 + chan * 5;
+       }
+       return freq;
 }
 
 
@@ -468,7 +500,7 @@ static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
 
 
 static struct wpa_bss *
-compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
+compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs)
 {
 
        u8 i;
@@ -476,7 +508,7 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
        struct wpa_bss *target;
 
        if (!bss)
-               return 0;
+               return NULL;
 
        wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d",
                   MAC2STR(wpa_s->bssid), bss->level);
@@ -501,6 +533,19 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
                        continue;
                }
 
+               if (age_secs) {
+                       struct os_reltime now;
+
+                       if (os_get_reltime(&now) == 0 &&
+                           os_reltime_expired(&now, &target->last_update,
+                                              age_secs)) {
+                               wpa_printf(MSG_DEBUG,
+                                          "Candidate BSS is more than %ld seconds old",
+                                          age_secs);
+                               continue;
+                       }
+               }
+
                if (bss->ssid_len != target->ssid_len ||
                    os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) {
                        /*
@@ -515,6 +560,25 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
                        continue;
                }
 
+               if (wpa_s->current_ssid &&
+                   !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid,
+                                       1)) {
+                       wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
+                                  " (pref %d) does not match the current network profile",
+                                  MAC2STR(nei->bssid),
+                                  nei->preference_present ? nei->preference :
+                                  -1);
+                       continue;
+               }
+
+               if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) {
+                       wpa_printf(MSG_DEBUG,
+                                  "MBO: Candidate BSS " MACSTR
+                                  " retry delay is not over yet",
+                                  MAC2STR(nei->bssid));
+                       continue;
+               }
+
                if (target->level < bss->level && target->level < -80) {
                        wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
                                   " (pref %d) does not have sufficient signal level (%d)",
@@ -536,12 +600,190 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
 }
 
 
+static int wpa_bss_ies_eq(struct wpa_bss *a, struct wpa_bss *b, u8 eid)
+{
+       const u8 *ie_a, *ie_b;
+
+       if (!a || !b)
+               return 0;
+
+       ie_a = wpa_bss_get_ie(a, eid);
+       ie_b = wpa_bss_get_ie(b, eid);
+
+       if (!ie_a || !ie_b || ie_a[1] != ie_b[1])
+               return 0;
+
+       return os_memcmp(ie_a, ie_b, ie_a[1]) == 0;
+}
+
+
+static u32 wnm_get_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+       u32 info = 0;
+
+       info |= NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH;
+
+       /*
+        * Leave the security and key scope bits unset to indicate that the
+        * security information is not available.
+        */
+
+       if (bss->caps & WLAN_CAPABILITY_SPECTRUM_MGMT)
+               info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
+       if (bss->caps & WLAN_CAPABILITY_QOS)
+               info |= NEI_REP_BSSID_INFO_QOS;
+       if (bss->caps & WLAN_CAPABILITY_APSD)
+               info |= NEI_REP_BSSID_INFO_APSD;
+       if (bss->caps & WLAN_CAPABILITY_RADIO_MEASUREMENT)
+               info |= NEI_REP_BSSID_INFO_RM;
+       if (bss->caps & WLAN_CAPABILITY_DELAYED_BLOCK_ACK)
+               info |= NEI_REP_BSSID_INFO_DELAYED_BA;
+       if (bss->caps & WLAN_CAPABILITY_IMM_BLOCK_ACK)
+               info |= NEI_REP_BSSID_INFO_IMM_BA;
+       if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_MOBILITY_DOMAIN))
+               info |= NEI_REP_BSSID_INFO_MOBILITY_DOMAIN;
+       if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_HT_CAP))
+               info |= NEI_REP_BSSID_INFO_HT;
+
+       return info;
+}
+
+
+static int wnm_add_nei_rep(u8 *buf, size_t len, const u8 *bssid, u32 bss_info,
+                          u8 op_class, u8 chan, u8 phy_type, u8 pref)
+{
+       u8 *pos = buf;
+
+       if (len < 18) {
+               wpa_printf(MSG_DEBUG,
+                          "WNM: Not enough room for Neighbor Report element");
+               return -1;
+       }
+
+       *pos++ = WLAN_EID_NEIGHBOR_REPORT;
+       /* length: 13 for basic neighbor report + 3 for preference subelement */
+       *pos++ = 16;
+       os_memcpy(pos, bssid, ETH_ALEN);
+       pos += ETH_ALEN;
+       WPA_PUT_LE32(pos, bss_info);
+       pos += 4;
+       *pos++ = op_class;
+       *pos++ = chan;
+       *pos++ = phy_type;
+       *pos++ = WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE;
+       *pos++ = 1;
+       *pos++ = pref;
+       return pos - buf;
+}
+
+
+static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s,
+                              struct wpa_bss *bss, u8 *buf, size_t len,
+                              u8 pref)
+{
+       const u8 *ie;
+       u8 op_class, chan;
+       int sec_chan = 0, vht = 0;
+       enum phy_type phy_type;
+       u32 info;
+       struct ieee80211_ht_operation *ht_oper = NULL;
+       struct ieee80211_vht_operation *vht_oper = NULL;
+
+       ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION);
+       if (ie && ie[1] >= 2) {
+               ht_oper = (struct ieee80211_ht_operation *) (ie + 2);
+
+               if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+                       sec_chan = 1;
+               else if (ht_oper->ht_param &
+                        HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+                       sec_chan = -1;
+       }
+
+       ie = wpa_bss_get_ie(bss, WLAN_EID_VHT_OPERATION);
+       if (ie && ie[1] >= 1) {
+               vht_oper = (struct ieee80211_vht_operation *) (ie + 2);
+
+               if (vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80MHZ ||
+                   vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_160MHZ ||
+                   vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80P80MHZ)
+                       vht = vht_oper->vht_op_info_chwidth;
+       }
+
+       if (ieee80211_freq_to_channel_ext(bss->freq, sec_chan, vht, &op_class,
+                                         &chan) == NUM_HOSTAPD_MODES) {
+               wpa_printf(MSG_DEBUG,
+                          "WNM: Cannot determine operating class and channel");
+               return -2;
+       }
+
+       phy_type = ieee80211_get_phy_type(bss->freq, (ht_oper != NULL),
+                                         (vht_oper != NULL));
+       if (phy_type == PHY_TYPE_UNSPECIFIED) {
+               wpa_printf(MSG_DEBUG,
+                          "WNM: Cannot determine BSS phy type for Neighbor Report");
+               return -2;
+       }
+
+       info = wnm_get_bss_info(wpa_s, bss);
+
+       return wnm_add_nei_rep(buf, len, bss->bssid, info, op_class, chan,
+                              phy_type, pref);
+}
+
+
+static int wnm_add_cand_list(struct wpa_supplicant *wpa_s, u8 *buf, size_t len)
+{
+       u8 *pos = buf;
+       unsigned int i, pref = 255;
+       struct os_reltime now;
+       struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+       if (!ssid)
+               return 0;
+
+       /*
+        * TODO: Define when scan results are no longer valid for the candidate
+        * list.
+        */
+       os_get_reltime(&now);
+       if (os_reltime_expired(&now, &wpa_s->last_scan, 10))
+               return 0;
+
+       wpa_printf(MSG_DEBUG,
+                  "WNM: Add candidate list to BSS Transition Management Response frame");
+       for (i = 0; i < wpa_s->last_scan_res_used && pref; i++) {
+               struct wpa_bss *bss = wpa_s->last_scan_res[i];
+               int res;
+
+               if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1)) {
+                       res = wnm_nei_rep_add_bss(wpa_s, bss, pos, len, pref--);
+                       if (res == -2)
+                               continue; /* could not build entry for BSS */
+                       if (res < 0)
+                               break; /* no more room for candidates */
+                       if (pref == 1)
+                               break;
+
+                       pos += res;
+                       len -= res;
+               }
+       }
+
+       wpa_hexdump(MSG_DEBUG,
+                   "WNM: BSS Transition Management Response candidate list",
+                   buf, pos - buf);
+
+       return pos - buf;
+}
+
+
 static void wnm_send_bss_transition_mgmt_resp(
        struct wpa_supplicant *wpa_s, u8 dialog_token,
        enum bss_trans_mgmt_status_code status, u8 delay,
        const u8 *target_bssid)
 {
-       u8 buf[1000], *pos;
+       u8 buf[2000], *pos;
        struct ieee80211_mgmt *mgmt;
        size_t len;
        int res;
@@ -581,6 +823,17 @@ static void wnm_send_bss_transition_mgmt_resp(
                pos += ETH_ALEN;
        }
 
+       if (status == WNM_BSS_TM_ACCEPT)
+               pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos);
+
+#ifdef CONFIG_MBO
+       if (status != WNM_BSS_TM_ACCEPT) {
+               pos += wpas_mbo_ie_bss_trans_reject(
+                       wpa_s, pos, buf + sizeof(buf) - pos,
+                       MBO_TRANSITION_REJECT_REASON_UNSPECIFIED);
+       }
+#endif /* CONFIG_MBO */
+
        len = pos - (u8 *) &mgmt->u.action.category;
 
        res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
@@ -593,6 +846,41 @@ static void wnm_send_bss_transition_mgmt_resp(
 }
 
 
+static void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s,
+                              struct wpa_bss *bss, struct wpa_ssid *ssid,
+                              int after_new_scan)
+{
+       wpa_dbg(wpa_s, MSG_DEBUG,
+               "WNM: Transition to BSS " MACSTR
+               " based on BSS Transition Management Request (old BSSID "
+               MACSTR " after_new_scan=%d)",
+               MAC2STR(bss->bssid), MAC2STR(wpa_s->bssid), after_new_scan);
+
+       /* Send the BSS Management Response - Accept */
+       if (wpa_s->wnm_reply) {
+               wpa_s->wnm_reply = 0;
+               wpa_printf(MSG_DEBUG,
+                          "WNM: Sending successful BSS Transition Management Response");
+               wnm_send_bss_transition_mgmt_resp(wpa_s,
+                                                 wpa_s->wnm_dialog_token,
+                                                 WNM_BSS_TM_ACCEPT,
+                                                 0, bss->bssid);
+       }
+
+       if (bss == wpa_s->current_bss) {
+               wpa_printf(MSG_DEBUG,
+                          "WNM: Already associated with the preferred candidate");
+               wnm_deallocate_memory(wpa_s);
+               return;
+       }
+
+       wpa_s->reassociate = 1;
+       wpa_printf(MSG_DEBUG, "WNM: Issuing connect");
+       wpa_supplicant_connect(wpa_s, bss, ssid);
+       wnm_deallocate_memory(wpa_s);
+}
+
+
 int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
 {
        struct wpa_bss *bss;
@@ -602,6 +890,8 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
        if (!wpa_s->wnm_neighbor_report_elements)
                return 0;
 
+       wpa_dbg(wpa_s, MSG_DEBUG,
+               "WNM: Process scan results for BSS Transition Management");
        if (os_reltime_before(&wpa_s->wnm_cand_valid_until,
                              &wpa_s->scan_trigger_time)) {
                wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it");
@@ -617,7 +907,7 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
        }
 
        /* Compare the Neighbor Report and scan results */
-       bss = compare_scan_neighbor_results(wpa_s);
+       bss = compare_scan_neighbor_results(wpa_s, 0);
        if (!bss) {
                wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found");
                status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES;
@@ -625,24 +915,7 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
        }
 
        /* Associate to the network */
-       /* Send the BSS Management Response - Accept */
-       if (wpa_s->wnm_reply) {
-               wpa_s->wnm_reply = 0;
-               wnm_send_bss_transition_mgmt_resp(wpa_s,
-                                                 wpa_s->wnm_dialog_token,
-                                                 WNM_BSS_TM_ACCEPT,
-                                                 0, bss->bssid);
-       }
-
-       if (bss == wpa_s->current_bss) {
-               wpa_printf(MSG_DEBUG,
-                          "WNM: Already associated with the preferred candidate");
-               return 1;
-       }
-
-       wpa_s->reassociate = 1;
-       wpa_supplicant_connect(wpa_s, bss, ssid);
-       wnm_deallocate_memory(wpa_s);
+       wnm_bss_tm_connect(wpa_s, bss, ssid, 1);
        return 1;
 
 send_bss_resp_fail:
@@ -783,14 +1056,90 @@ static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s)
 }
 
 
+static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_scan_results *scan_res;
+       struct wpa_bss *bss;
+       struct wpa_ssid *ssid = wpa_s->current_ssid;
+       u8 i, found = 0;
+       size_t j;
+
+       wpa_dbg(wpa_s, MSG_DEBUG,
+               "WNM: Fetch current scan results from the driver for checking transition candidates");
+       scan_res = wpa_drv_get_scan_results2(wpa_s);
+       if (!scan_res) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Failed to get scan results");
+               return 0;
+       }
+
+       if (scan_res->fetch_time.sec == 0)
+               os_get_reltime(&scan_res->fetch_time);
+
+       filter_scan_res(wpa_s, scan_res);
+
+       for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+               struct neighbor_report *nei;
+
+               nei = &wpa_s->wnm_neighbor_report_elements[i];
+               if (nei->preference_present && nei->preference == 0)
+                       continue;
+
+               for (j = 0; j < scan_res->num; j++) {
+                       struct wpa_scan_res *res;
+                       const u8 *ssid_ie;
+
+                       res = scan_res->res[j];
+                       if (os_memcmp(nei->bssid, res->bssid, ETH_ALEN) != 0 ||
+                           res->age > WNM_SCAN_RESULT_AGE * 1000)
+                               continue;
+                       bss = wpa_s->current_bss;
+                       ssid_ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
+                       if (bss && ssid_ie &&
+                           (bss->ssid_len != ssid_ie[1] ||
+                            os_memcmp(bss->ssid, ssid_ie + 2,
+                                      bss->ssid_len) != 0))
+                               continue;
+
+                       /* Potential candidate found */
+                       found = 1;
+                       scan_snr(res);
+                       scan_est_throughput(wpa_s, res);
+                       wpa_bss_update_scan_res(wpa_s, res,
+                                               &scan_res->fetch_time);
+               }
+       }
+
+       wpa_scan_results_free(scan_res);
+       if (!found) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "WNM: No transition candidate matches existing scan results");
+               return 0;
+       }
+
+       bss = compare_scan_neighbor_results(wpa_s, WNM_SCAN_RESULT_AGE);
+       if (!bss) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "WNM: Comparison of scan results against transition candidates did not find matches");
+               return 0;
+       }
+
+       /* Associate to the network */
+       wnm_bss_tm_connect(wpa_s, bss, ssid, 0);
+       return 1;
+}
+
+
 static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
                                             const u8 *pos, const u8 *end,
                                             int reply)
 {
        unsigned int beacon_int;
        u8 valid_int;
+#ifdef CONFIG_MBO
+       const u8 *vendor;
+#endif /* CONFIG_MBO */
 
-       if (pos + 5 > end)
+       if (end - pos < 5)
                return;
 
        if (wpa_s->current_bss)
@@ -810,10 +1159,23 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
                   wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
                   wpa_s->wnm_dissoc_timer, valid_int);
 
+#if defined(CONFIG_MBO) && defined(CONFIG_TESTING_OPTIONS)
+       if (wpa_s->reject_btm_req_reason) {
+               wpa_printf(MSG_INFO,
+                          "WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d",
+                          wpa_s->reject_btm_req_reason);
+               wnm_send_bss_transition_mgmt_resp(wpa_s,
+                                                 wpa_s->wnm_dialog_token,
+                                                 wpa_s->reject_btm_req_reason,
+                                                 0, NULL);
+               return;
+       }
+#endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */
+
        pos += 5;
 
        if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
-               if (pos + 12 > end) {
+               if (end - pos < 12) {
                        wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request");
                        return;
                }
@@ -824,7 +1186,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
        if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
                char url[256];
 
-               if (pos + 1 > end || pos + 1 + pos[0] > end) {
+               if (end - pos < 1 || 1 + pos[0] > end - pos) {
                        wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
                                   "Management Request (URL)");
                        return;
@@ -849,6 +1211,12 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
                }
        }
 
+#ifdef CONFIG_MBO
+       vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC);
+       if (vendor)
+               wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]);
+#endif /* CONFIG_MBO */
+
        if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
                unsigned int valid_ms;
 
@@ -860,7 +1228,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
                if (wpa_s->wnm_neighbor_report_elements == NULL)
                        return;
 
-               while (pos + 2 <= end &&
+               while (end - pos >= 2 &&
                       wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT)
                {
                        u8 tag = *pos++;
@@ -868,7 +1236,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
 
                        wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u",
                                   tag);
-                       if (pos + len > end) {
+                       if (len > end - pos) {
                                wpa_printf(MSG_DEBUG, "WNM: Truncated request");
                                return;
                        }
@@ -877,11 +1245,22 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
                                rep = &wpa_s->wnm_neighbor_report_elements[
                                        wpa_s->wnm_num_neighbor_report];
                                wnm_parse_neighbor_report(wpa_s, pos, len, rep);
+                               wpa_s->wnm_num_neighbor_report++;
                        }
 
                        pos += len;
-                       wpa_s->wnm_num_neighbor_report++;
                }
+
+               if (!wpa_s->wnm_num_neighbor_report) {
+                       wpa_printf(MSG_DEBUG,
+                                  "WNM: Candidate list included bit is set, but no candidates found");
+                       wnm_send_bss_transition_mgmt_resp(
+                               wpa_s, wpa_s->wnm_dialog_token,
+                               WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES,
+                               0, NULL);
+                       return;
+               }
+
                wnm_sort_cand_list(wpa_s);
                wnm_dump_cand_list(wpa_s);
                valid_ms = valid_int * beacon_int * 128 / 125;
@@ -895,6 +1274,20 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
                wpa_s->wnm_cand_valid_until.usec %= 1000000;
                os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN);
 
+               /*
+                * Fetch the latest scan results from the kernel and check for
+                * candidates based on those results first. This can help in
+                * finding more up-to-date information should the driver has
+                * done some internal scanning operations after the last scan
+                * result update in wpa_supplicant.
+                */
+               if (wnm_fetch_scan_results(wpa_s) > 0)
+                       return;
+
+               /*
+                * Try to use previously received scan results, if they are
+                * recent enough to use for a connection.
+                */
                if (wpa_s->last_scan_res_used > 0) {
                        struct os_reltime now;
 
@@ -910,6 +1303,14 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
                }
 
                wnm_set_scan_freqs(wpa_s);
+               if (wpa_s->wnm_num_neighbor_report == 1) {
+                       os_memcpy(wpa_s->next_scan_bssid,
+                                 wpa_s->wnm_neighbor_report_elements[0].bssid,
+                                 ETH_ALEN);
+                       wpa_printf(MSG_DEBUG,
+                                  "WNM: Scan only for a specific BSSID since there is only a single candidate "
+                                  MACSTR, MAC2STR(wpa_s->next_scan_bssid));
+               }
                wpa_supplicant_req_scan(wpa_s, 0, 0);
        } else if (reply) {
                enum bss_trans_mgmt_status_code status;
@@ -927,16 +1328,17 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
 
 
 int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
-                                      u8 query_reason)
+                                      u8 query_reason, int cand_list)
 {
-       u8 buf[1000], *pos;
+       u8 buf[2000], *pos;
        struct ieee80211_mgmt *mgmt;
        size_t len;
        int ret;
 
        wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to "
-                  MACSTR " query_reason=%u",
-                  MAC2STR(wpa_s->bssid), query_reason);
+                  MACSTR " query_reason=%u%s",
+                  MAC2STR(wpa_s->bssid), query_reason,
+                  cand_list ? " candidate list" : "");
 
        mgmt = (struct ieee80211_mgmt *) buf;
        os_memset(&buf, 0, sizeof(buf));
@@ -951,6 +1353,9 @@ int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
        mgmt->u.action.u.bss_tm_query.query_reason = query_reason;
        pos = mgmt->u.action.u.bss_tm_query.variable;
 
+       if (cand_list)
+               pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos);
+
        len = pos - (u8 *) &mgmt->u.action.category;
 
        ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
@@ -971,7 +1376,7 @@ static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s,
        pos = data;
        end = data + len;
 
-       while (pos + 1 < end) {
+       while (end - pos > 1) {
                ie = *pos++;
                ie_len = *pos++;
                wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u",
@@ -1009,7 +1414,7 @@ static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s,
                                url = NULL;
                                osu_method = 1;
                        } else {
-                               if (pos + url_len + 1 > ie_end) {
+                               if (url_len + 1 > ie_end - pos) {
                                        wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)",
                                                   url_len,
                                                   (int) (ie_end - pos));
@@ -1048,7 +1453,7 @@ static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s,
                                   "Imminent - Reason Code %u   "
                                   "Re-Auth Delay %u  URL Length %u",
                                   code, reauth_delay, url_len);
-                       if (pos + url_len > ie_end)
+                       if (url_len > ie_end - pos)
                                break;
                        url = os_malloc(url_len + 1);
                        if (url == NULL)
index 8de4348..81d8153 100644 (file)
@@ -56,7 +56,7 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
                              const struct ieee80211_mgmt *mgmt, size_t len);
 
 int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
-                                      u8 query_reason);
+                                      u8 query_reason, int cand_list);
 void wnm_deallocate_memory(struct wpa_supplicant *wpa_s);
 
 
index 7ddae3d..a848b77 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -14,6 +14,7 @@
 #include <dirent.h>
 #endif /* CONFIG_CTRL_IFACE_UNIX */
 
+#include "common/cli.h"
 #include "common/wpa_ctrl.h"
 #include "utils/common.h"
 #include "utils/eloop.h"
 
 static const char *const wpa_cli_version =
 "wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
-
-
-static const char *const wpa_cli_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"See README for more details.\n";
-
-static const char *const wpa_cli_full_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"\n"
-"Redistribution and use in source and binary forms, with or without\n"
-"modification, are permitted provided that the following conditions are\n"
-"met:\n"
-"\n"
-"1. Redistributions of source code must retain the above copyright\n"
-"   notice, this list of conditions and the following disclaimer.\n"
-"\n"
-"2. Redistributions in binary form must reproduce the above copyright\n"
-"   notice, this list of conditions and the following disclaimer in the\n"
-"   documentation and/or other materials provided with the distribution.\n"
-"\n"
-"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
-"   names of its contributors may be used to endorse or promote products\n"
-"   derived from this software without specific prior written permission.\n"
-"\n"
-"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
-"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
-"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
-"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
-"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
-"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
-"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
-"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
-"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
-"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
-"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
-"\n";
+"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
+
+#define VENDOR_ELEM_FRAME_ID \
+       "  0: Probe Req (P2P), 1: Probe Resp (P2P) , 2: Probe Resp (GO), " \
+       "3: Beacon (GO), 4: PD Req, 5: PD Resp, 6: GO Neg Req, " \
+       "7: GO Neg Resp, 8: GO Neg Conf, 9: Inv Req, 10: Inv Resp, " \
+       "11: Assoc Req (P2P), 12: Assoc Resp (P2P)"
 
 static struct wpa_ctrl *ctrl_conn;
 static struct wpa_ctrl *mon_conn;
@@ -84,11 +55,6 @@ static int ping_interval = 5;
 static int interactive = 0;
 static char *ifname_prefix = NULL;
 
-struct cli_txt_entry {
-       struct dl_list list;
-       char *txt;
-};
-
 static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */
 static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */
 static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
@@ -124,168 +90,6 @@ static void usage(void)
 }
 
 
-static void cli_txt_list_free(struct cli_txt_entry *e)
-{
-       dl_list_del(&e->list);
-       os_free(e->txt);
-       os_free(e);
-}
-
-
-static void cli_txt_list_flush(struct dl_list *list)
-{
-       struct cli_txt_entry *e;
-       while ((e = dl_list_first(list, struct cli_txt_entry, list)))
-               cli_txt_list_free(e);
-}
-
-
-static struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list,
-                                              const char *txt)
-{
-       struct cli_txt_entry *e;
-       dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
-               if (os_strcmp(e->txt, txt) == 0)
-                       return e;
-       }
-       return NULL;
-}
-
-
-static void cli_txt_list_del(struct dl_list *txt_list, const char *txt)
-{
-       struct cli_txt_entry *e;
-       e = cli_txt_list_get(txt_list, txt);
-       if (e)
-               cli_txt_list_free(e);
-}
-
-
-static void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt)
-{
-       u8 addr[ETH_ALEN];
-       char buf[18];
-       if (hwaddr_aton(txt, addr) < 0)
-               return;
-       os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
-       cli_txt_list_del(txt_list, buf);
-}
-
-
-#ifdef CONFIG_P2P
-static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt,
-                                 int separator)
-{
-       const char *end;
-       char *buf;
-       end = os_strchr(txt, separator);
-       if (end == NULL)
-               end = txt + os_strlen(txt);
-       buf = dup_binstr(txt, end - txt);
-       if (buf == NULL)
-               return;
-       cli_txt_list_del(txt_list, buf);
-       os_free(buf);
-}
-#endif /* CONFIG_P2P */
-
-
-static int cli_txt_list_add(struct dl_list *txt_list, const char *txt)
-{
-       struct cli_txt_entry *e;
-       e = cli_txt_list_get(txt_list, txt);
-       if (e)
-               return 0;
-       e = os_zalloc(sizeof(*e));
-       if (e == NULL)
-               return -1;
-       e->txt = os_strdup(txt);
-       if (e->txt == NULL) {
-               os_free(e);
-               return -1;
-       }
-       dl_list_add(txt_list, &e->list);
-       return 0;
-}
-
-
-#ifdef CONFIG_P2P
-static int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt)
-{
-       u8 addr[ETH_ALEN];
-       char buf[18];
-       if (hwaddr_aton(txt, addr) < 0)
-               return -1;
-       os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
-       return cli_txt_list_add(txt_list, buf);
-}
-#endif /* CONFIG_P2P */
-
-
-static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt,
-                                int separator)
-{
-       const char *end;
-       char *buf;
-       int ret;
-       end = os_strchr(txt, separator);
-       if (end == NULL)
-               end = txt + os_strlen(txt);
-       buf = dup_binstr(txt, end - txt);
-       if (buf == NULL)
-               return -1;
-       ret = cli_txt_list_add(txt_list, buf);
-       os_free(buf);
-       return ret;
-}
-
-
-static char ** cli_txt_list_array(struct dl_list *txt_list)
-{
-       unsigned int i, count = dl_list_len(txt_list);
-       char **res;
-       struct cli_txt_entry *e;
-
-       res = os_calloc(count + 1, sizeof(char *));
-       if (res == NULL)
-               return NULL;
-
-       i = 0;
-       dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
-               res[i] = os_strdup(e->txt);
-               if (res[i] == NULL)
-                       break;
-               i++;
-       }
-
-       return res;
-}
-
-
-static int get_cmd_arg_num(const char *str, int pos)
-{
-       int arg = 0, i;
-
-       for (i = 0; i <= pos; i++) {
-               if (str[i] != ' ') {
-                       arg++;
-                       while (i <= pos && str[i] != ' ')
-                               i++;
-               }
-       }
-
-       if (arg > 0)
-               arg--;
-       return arg;
-}
-
-
-static int str_starts(const char *src, const char *match)
-{
-       return os_strncmp(src, match, os_strlen(match)) == 0;
-}
-
-
 static int wpa_cli_show_event(const char *event)
 {
        const char *start;
@@ -452,36 +256,6 @@ static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
 }
 
 
-static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
-                    char *argv[])
-{
-       int i, res;
-       char *pos, *end;
-
-       pos = buf;
-       end = buf + buflen;
-
-       res = os_snprintf(pos, end - pos, "%s", cmd);
-       if (os_snprintf_error(end - pos, res))
-               goto fail;
-       pos += res;
-
-       for (i = 0; i < argc; i++) {
-               res = os_snprintf(pos, end - pos, " %s", argv[i]);
-               if (os_snprintf_error(end - pos, res))
-                       goto fail;
-               pos += res;
-       }
-
-       buf[buflen - 1] = '\0';
-       return 0;
-
-fail:
-       printf("Too long command\n");
-       return -1;
-}
-
-
 static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args,
                       int argc, char *argv[])
 {
@@ -581,7 +355,7 @@ static char ** wpa_cli_complete_help(const char *str, int pos)
 
 static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-       printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
+       printf("%s\n\n%s\n", wpa_cli_version, cli_full_license);
        return 0;
 }
 
@@ -677,7 +451,10 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
                "tdls_external_control", "osu_dir", "wowlan_triggers",
                "p2p_search_delay", "mac_addr", "rand_addr_lifetime",
                "preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
-               "reassoc_same_bss_optim", "wps_priority"
+               "reassoc_same_bss_optim", "wps_priority",
+#ifdef CONFIG_TESTING_OPTIONS
+               "ignore_auth_resp",
+#endif /* CONFIG_TESTING_OPTIONS */
        };
        int i, num_fields = ARRAY_SIZE(fields);
 
@@ -705,6 +482,13 @@ static int wpa_cli_cmd_dump(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+static int wpa_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
+                                   char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
+}
+
+
 static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        return wpa_cli_cmd(ctrl, "GET", 1, argc, argv);
@@ -1548,7 +1332,7 @@ static const char *network_fields[] = {
        "ssid", "scan_ssid", "bssid", "bssid_blacklist",
        "bssid_whitelist", "psk", "proto", "key_mgmt",
        "bg_scan_period", "pairwise", "group", "auth_alg", "scan_freq",
-       "freq_list",
+       "freq_list", "max_oper_chwidth",
 #ifdef IEEE8021X_EAPOL
        "eap", "identity", "anonymous_identity", "password", "ca_cert",
        "ca_path", "client_cert", "private_key", "private_key_passwd",
@@ -1606,7 +1390,7 @@ static const char *network_fields[] = {
 #ifdef CONFIG_HS20
        "update_identifier",
 #endif /* CONFIG_HS20 */
-       "mac_addr"
+       "mac_addr", "pbss", "wps_disabled"
 };
 
 
@@ -1764,6 +1548,13 @@ static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static int wpa_cli_cmd_abort_scan(struct wpa_ctrl *ctrl, int argc,
+                                 char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "ABORT_SCAN");
+}
+
+
 static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        return wpa_cli_cmd(ctrl, "BSS", 1, argc, argv);
@@ -1804,6 +1595,48 @@ static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static char ** wpa_cli_complete_get_capability(const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       const char *fields[] = {
+               "eap", "pairwise", "group", "group_mgmt", "key_mgmt",
+               "proto", "auth_alg", "modes", "channels", "freq",
+#ifdef CONFIG_TDLS
+               "tdls",
+#endif /* CONFIG_TDLS */
+#ifdef CONFIG_ERP
+               "erp",
+#endif /* CONFIG_ERP */
+#ifdef CONFIG_FIPS
+               "fips",
+#endif /* CONFIG_FIPS */
+#ifdef CONFIG_ACS
+               "acs",
+#endif /* CONFIG_ACS */
+       };
+       int i, num_fields = ARRAY_SIZE(fields);
+       char **res = NULL;
+
+       if (arg == 1) {
+               res = os_calloc(num_fields + 1, sizeof(char *));
+               if (res == NULL)
+                       return NULL;
+               for (i = 0; i < num_fields; i++) {
+                       res[i] = os_strdup(fields[i]);
+                       if (res[i] == NULL)
+                               return res;
+               }
+       }
+       if (arg == 2) {
+               res = os_calloc(1 + 1, sizeof(char *));
+               if (res == NULL)
+                       return NULL;
+               res[0] = os_strdup("strict");
+       }
+       return res;
+}
+
+
 static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
 {
        printf("Available interfaces:\n");
@@ -1866,14 +1699,15 @@ static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
 
        /*
         * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
-        * <driver_param>TAB<bridge_name>[TAB<create>]
+        * <driver_param>TAB<bridge_name>[TAB<create>[TAB<type>]]
         */
        res = os_snprintf(cmd, sizeof(cmd),
-                         "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s\t%s",
+                         "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s\t%s\t%s",
                          argv[0],
                          argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
                          argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "",
-                         argc > 5 ? argv[5] : "", argc > 6 ? argv[6] : "");
+                         argc > 5 ? argv[5] : "", argc > 6 ? argv[6] : "",
+                         argc > 7 ? argv[7] : "");
        if (os_snprintf_error(sizeof(cmd), res))
                return -1;
        cmd[sizeof(cmd) - 1] = '\0';
@@ -1913,6 +1747,12 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
                printf("Not connected to hostapd - command dropped.\n");
                return -1;
        }
+       if (ifname_prefix) {
+               os_snprintf(buf, sizeof(buf), "IFNAME=%s %s",
+                           ifname_prefix, cmd);
+               buf[sizeof(buf) - 1] = '\0';
+               cmd = buf;
+       }
        len = sizeof(buf) - 1;
        ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
                               wpa_cli_msg_cb);
@@ -2022,6 +1862,20 @@ static int wpa_cli_cmd_mesh_group_remove(struct wpa_ctrl *ctrl, int argc,
        return wpa_cli_cmd(ctrl, "MESH_GROUP_REMOVE", 1, argc, argv);
 }
 
+
+static int wpa_cli_cmd_mesh_peer_remove(struct wpa_ctrl *ctrl, int argc,
+                                       char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "MESH_PEER_REMOVE", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_mesh_peer_add(struct wpa_ctrl *ctrl, int argc,
+                                    char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "MESH_PEER_ADD", 1, argc, argv);
+}
+
 #endif /* CONFIG_MESH */
 
 
@@ -2141,6 +1995,13 @@ static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static int wpa_cli_cmd_p2p_group_member(struct wpa_ctrl *ctrl, int argc,
+                                       char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "P2P_GROUP_MEMBER", 1, argc, argv);
+}
+
+
 static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc,
                                     char *argv[])
 {
@@ -2477,6 +2338,27 @@ static int wpa_cli_cmd_p2p_remove_client(struct wpa_ctrl *ctrl, int argc,
        return wpa_cli_cmd(ctrl, "P2P_REMOVE_CLIENT", 1, argc, argv);
 }
 
+
+static int wpa_cli_cmd_vendor_elem_add(struct wpa_ctrl *ctrl, int argc,
+                                      char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "VENDOR_ELEM_ADD", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_vendor_elem_get(struct wpa_ctrl *ctrl, int argc,
+                                      char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "VENDOR_ELEM_GET", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_vendor_elem_remove(struct wpa_ctrl *ctrl, int argc,
+                                         char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "VENDOR_ELEM_REMOVE", 2, argc, argv);
+}
+
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_WIFI_DISPLAY
@@ -2719,6 +2601,13 @@ static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static int wpa_cli_cmd_signal_monitor(struct wpa_ctrl *ctrl, int argc,
+                                  char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "SIGNAL_MONITOR", 0, argc, argv);
+}
+
+
 static int wpa_cli_cmd_pktcnt_poll(struct wpa_ctrl *ctrl, int argc,
                                   char *argv[])
 {
@@ -2823,6 +2712,20 @@ static int wpa_cli_cmd_get_pref_freq_list(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static int wpa_cli_cmd_p2p_lo_start(struct wpa_ctrl *ctrl, int argc,
+                                   char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "P2P_LO_START", 4, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_lo_stop(struct wpa_ctrl *ctrl, int argc,
+                                  char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "P2P_LO_STOP", 0, argc, argv);
+}
+
+
 enum wpa_cli_cmd_flags {
        cli_cmd_flag_none               = 0x00,
        cli_cmd_flag_sensitive          = 0x01
@@ -2880,6 +2783,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
        { "get", wpa_cli_cmd_get, wpa_cli_complete_get,
          cli_cmd_flag_none,
          "<name> = get information" },
+       { "driver_flags", wpa_cli_cmd_driver_flags, NULL,
+         cli_cmd_flag_none,
+         "= list driver flags" },
        { "logon", wpa_cli_cmd_logon, NULL,
          cli_cmd_flag_none,
          "= IEEE 802.1X EAPOL state machine logon" },
@@ -3001,11 +2907,14 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
        { "scan_results", wpa_cli_cmd_scan_results, NULL,
          cli_cmd_flag_none,
          "= get latest scan results" },
+       { "abort_scan", wpa_cli_cmd_abort_scan, NULL,
+         cli_cmd_flag_none,
+         "= request ongoing scan to be aborted" },
        { "bss", wpa_cli_cmd_bss, wpa_cli_complete_bss,
          cli_cmd_flag_none,
          "<<idx> | <bssid>> = get detailed scan result info" },
-       { "get_capability", wpa_cli_cmd_get_capability, NULL,
-         cli_cmd_flag_none,
+       { "get_capability", wpa_cli_cmd_get_capability,
+         wpa_cli_complete_get_capability, cli_cmd_flag_none,
          "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels/freq/modes> "
          "= get capabilities" },
        { "reconfigure", wpa_cli_cmd_reconfigure, NULL,
@@ -3017,8 +2926,10 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
        { "interface_add", wpa_cli_cmd_interface_add, NULL,
          cli_cmd_flag_none,
          "<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n"
-         "  <bridge_name> = adds new interface, all parameters but <ifname>\n"
-         "  are optional" },
+         "  <bridge_name> <create> <type> = adds new interface, all "
+         "parameters but\n"
+         "  <ifname> are optional. Supported types are station ('sta') and "
+         "AP ('ap')" },
        { "interface_remove", wpa_cli_cmd_interface_remove, NULL,
          cli_cmd_flag_none,
          "<ifname> = removes the interface" },
@@ -3157,6 +3068,12 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
        { "mesh_group_remove", wpa_cli_cmd_mesh_group_remove, NULL,
          cli_cmd_flag_none,
          "<ifname> = Remove mesh group interface" },
+       { "mesh_peer_remove", wpa_cli_cmd_mesh_peer_remove, NULL,
+         cli_cmd_flag_none,
+         "<addr> = Remove a mesh peer" },
+       { "mesh_peer_add", wpa_cli_cmd_mesh_peer_add, NULL,
+         cli_cmd_flag_none,
+         "<addr> [duration=<seconds>] = Add a mesh peer" },
 #endif /* CONFIG_MESH */
 #ifdef CONFIG_P2P
        { "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
@@ -3180,6 +3097,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
          "<ifname> = remove P2P group interface (terminate group if GO)" },
        { "p2p_group_add", wpa_cli_cmd_p2p_group_add, NULL, cli_cmd_flag_none,
          "[ht40] = add a new P2P group (local end as GO)" },
+       { "p2p_group_member", wpa_cli_cmd_p2p_group_member, NULL,
+         cli_cmd_flag_none,
+         "<dev_addr> = Get peer interface address on local GO using peer Device Address" },
        { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc,
          wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
          "<addr> <method> = request provisioning discovery" },
@@ -3248,6 +3168,18 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
        { "p2p_remove_client", wpa_cli_cmd_p2p_remove_client,
          wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
          "<address|iface=address> = remove a peer from all groups" },
+       { "vendor_elem_add", wpa_cli_cmd_vendor_elem_add, NULL,
+         cli_cmd_flag_none,
+         "<frame id> <hexdump of elem(s)> = add vendor specific IEs to frame(s)\n"
+         VENDOR_ELEM_FRAME_ID },
+       { "vendor_elem_get", wpa_cli_cmd_vendor_elem_get, NULL,
+         cli_cmd_flag_none,
+         "<frame id> = get vendor specific IE(s) to frame(s)\n"
+         VENDOR_ELEM_FRAME_ID },
+       { "vendor_elem_remove", wpa_cli_cmd_vendor_elem_remove, NULL,
+         cli_cmd_flag_none,
+         "<frame id> <hexdump of elem(s)> = remove vendor specific IE(s) in frame(s)\n"
+         VENDOR_ELEM_FRAME_ID },
 #endif /* CONFIG_P2P */
 #ifdef CONFIG_WIFI_DISPLAY
        { "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL,
@@ -3336,6 +3268,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
        { "signal_poll", wpa_cli_cmd_signal_poll, NULL,
          cli_cmd_flag_none,
          "= get signal parameters" },
+       { "signal_monitor", wpa_cli_cmd_signal_monitor, NULL,
+         cli_cmd_flag_none,
+         "= set signal monitor parameters" },
        { "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL,
          cli_cmd_flag_none,
          "= get TX/RX packet counters" },
@@ -3350,7 +3285,7 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
        { "wnm_sleep", wpa_cli_cmd_wnm_sleep, NULL, cli_cmd_flag_none,
          "<enter/exit> [interval=#] = enter/exit WNM-Sleep mode" },
        { "wnm_bss_query", wpa_cli_cmd_wnm_bss_query, NULL, cli_cmd_flag_none,
-         "<query reason> = Send BSS Transition Management Query" },
+         "<query reason> [list] = Send BSS Transition Management Query" },
 #endif /* CONFIG_WNM */
        { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
          "<params..> = Sent unprocessed command" },
@@ -3367,8 +3302,7 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
        },
        { "neighbor_rep_request",
          wpa_cli_cmd_neighbor_rep_request, NULL, cli_cmd_flag_none,
-         "[ssid=<SSID>] = Trigger request to AP for neighboring AP report "
-         "(with optional given SSID, default: current SSID)"
+         "[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)"
        },
        { "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none,
          "= flush ERP keys" },
@@ -3380,6 +3314,12 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
        { "get_pref_freq_list", wpa_cli_cmd_get_pref_freq_list, NULL,
          cli_cmd_flag_none,
          "<interface type> = retrieve preferred freq list for the specified interface type" },
+       { "p2p_lo_start", wpa_cli_cmd_p2p_lo_start, NULL,
+         cli_cmd_flag_none,
+         "<freq> <period> <interval> <count> = start P2P listen offload" },
+       { "p2p_lo_stop", wpa_cli_cmd_p2p_lo_stop, NULL,
+         cli_cmd_flag_none,
+         "= stop P2P listen offload" },
        { NULL, NULL, NULL, cli_cmd_flag_none, NULL }
 };
 
@@ -3578,12 +3518,6 @@ static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
-static int str_match(const char *a, const char *b)
-{
-       return os_strncmp(a, b, os_strlen(b)) == 0;
-}
-
-
 static int wpa_cli_exec(const char *program, const char *arg1,
                        const char *arg2)
 {
@@ -3591,6 +3525,10 @@ static int wpa_cli_exec(const char *program, const char *arg1,
        size_t len;
        int res;
 
+       /* If no interface is specified, set the global */
+       if (!arg1)
+               arg1 = "global";
+
        len = os_strlen(arg1) + os_strlen(arg2) + 2;
        arg = os_malloc(len);
        if (arg == NULL)
@@ -3635,7 +3573,7 @@ static void wpa_cli_action_process(const char *msg)
                        pos = prev;
        }
 
-       if (str_match(pos, WPA_EVENT_CONNECTED)) {
+       if (str_starts(pos, WPA_EVENT_CONNECTED)) {
                int new_id = -1;
                os_unsetenv("WPA_ID");
                os_unsetenv("WPA_ID_STR");
@@ -3671,44 +3609,48 @@ static void wpa_cli_action_process(const char *msg)
                        wpa_cli_last_id = new_id;
                        wpa_cli_exec(action_file, ifname, "CONNECTED");
                }
-       } else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
+       } else if (str_starts(pos, WPA_EVENT_DISCONNECTED)) {
                if (wpa_cli_connected) {
                        wpa_cli_connected = 0;
                        wpa_cli_exec(action_file, ifname, "DISCONNECTED");
                }
-       } else if (str_match(pos, MESH_GROUP_STARTED)) {
+       } else if (str_starts(pos, AP_EVENT_ENABLED)) {
+               wpa_cli_exec(action_file, ctrl_ifname, pos);
+       } else if (str_starts(pos, AP_EVENT_DISABLED)) {
+               wpa_cli_exec(action_file, ctrl_ifname, pos);
+       } else if (str_starts(pos, MESH_GROUP_STARTED)) {
                wpa_cli_exec(action_file, ctrl_ifname, pos);
-       } else if (str_match(pos, MESH_GROUP_REMOVED)) {
+       } else if (str_starts(pos, MESH_GROUP_REMOVED)) {
                wpa_cli_exec(action_file, ctrl_ifname, pos);
-       } else if (str_match(pos, MESH_PEER_CONNECTED)) {
+       } else if (str_starts(pos, MESH_PEER_CONNECTED)) {
                wpa_cli_exec(action_file, ctrl_ifname, pos);
-       } else if (str_match(pos, MESH_PEER_DISCONNECTED)) {
+       } else if (str_starts(pos, MESH_PEER_DISCONNECTED)) {
                wpa_cli_exec(action_file, ctrl_ifname, pos);
-       } else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) {
+       } else if (str_starts(pos, P2P_EVENT_GROUP_STARTED)) {
                wpa_cli_exec(action_file, ifname, pos);
-       } else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) {
+       } else if (str_starts(pos, P2P_EVENT_GROUP_REMOVED)) {
                wpa_cli_exec(action_file, ifname, pos);
-       } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
+       } else if (str_starts(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
                wpa_cli_exec(action_file, ifname, pos);
-       } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
+       } else if (str_starts(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
                wpa_cli_exec(action_file, ifname, pos);
-       } else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) {
+       } else if (str_starts(pos, P2P_EVENT_GO_NEG_FAILURE)) {
                wpa_cli_exec(action_file, ifname, pos);
-       } else if (str_match(pos, WPS_EVENT_SUCCESS)) {
+       } else if (str_starts(pos, WPS_EVENT_SUCCESS)) {
                wpa_cli_exec(action_file, ifname, pos);
-       } else if (str_match(pos, WPS_EVENT_FAIL)) {
+       } else if (str_starts(pos, WPS_EVENT_FAIL)) {
                wpa_cli_exec(action_file, ifname, pos);
-       } else if (str_match(pos, AP_STA_CONNECTED)) {
+       } else if (str_starts(pos, AP_STA_CONNECTED)) {
                wpa_cli_exec(action_file, ifname, pos);
-       } else if (str_match(pos, AP_STA_DISCONNECTED)) {
+       } else if (str_starts(pos, AP_STA_DISCONNECTED)) {
                wpa_cli_exec(action_file, ifname, pos);
-       } else if (str_match(pos, ESS_DISASSOC_IMMINENT)) {
+       } else if (str_starts(pos, ESS_DISASSOC_IMMINENT)) {
                wpa_cli_exec(action_file, ifname, pos);
-       } else if (str_match(pos, HS20_SUBSCRIPTION_REMEDIATION)) {
+       } else if (str_starts(pos, HS20_SUBSCRIPTION_REMEDIATION)) {
                wpa_cli_exec(action_file, ifname, pos);
-       } else if (str_match(pos, HS20_DEAUTH_IMMINENT_NOTICE)) {
+       } else if (str_starts(pos, HS20_DEAUTH_IMMINENT_NOTICE)) {
                wpa_cli_exec(action_file, ifname, pos);
-       } else if (str_match(pos, WPA_EVENT_TERMINATING)) {
+       } else if (str_starts(pos, WPA_EVENT_TERMINATING)) {
                printf("wpa_supplicant is terminating - stop monitoring\n");
                wpa_cli_quit = 1;
        }
@@ -3818,7 +3760,7 @@ static int check_terminating(const char *msg)
                        pos = msg;
        }
 
-       if (str_match(pos, WPA_EVENT_TERMINATING) && ctrl_conn) {
+       if (str_starts(pos, WPA_EVENT_TERMINATING) && ctrl_conn) {
                edit_clear_line();
                printf("\rConnection to wpa_supplicant lost - trying to "
                       "reconnect\n");
@@ -3869,37 +3811,6 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
        }
 }
 
-#define max_args 10
-
-static int tokenize_cmd(char *cmd, char *argv[])
-{
-       char *pos;
-       int argc = 0;
-
-       pos = cmd;
-       for (;;) {
-               while (*pos == ' ')
-                       pos++;
-               if (*pos == '\0')
-                       break;
-               argv[argc] = pos;
-               argc++;
-               if (argc == max_args)
-                       break;
-               if (*pos == '"') {
-                       char *pos2 = os_strrchr(pos, '"');
-                       if (pos2)
-                               pos = pos2 + 1;
-               }
-               while (*pos != '\0' && *pos != ' ')
-                       pos++;
-               if (*pos == ' ')
-                       *pos++ = '\0';
-       }
-
-       return argc;
-}
-
 
 static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx)
 {
@@ -4084,7 +3995,7 @@ static void try_connection(void *eloop_ctx, void *timeout_ctx)
        if (ctrl_ifname == NULL)
                ctrl_ifname = wpa_cli_get_default_ifname();
 
-       if (!wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
+       if (wpa_cli_open_connection(ctrl_ifname, 1)) {
                if (!warning_displayed) {
                        printf("Could not connect to wpa_supplicant: "
                               "%s - re-trying\n",
@@ -4309,7 +4220,7 @@ int main(int argc, char *argv[])
        interactive = (argc == optind) && (action_file == NULL);
 
        if (interactive)
-               printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
+               printf("%s\n\n%s\n\n", wpa_cli_version, cli_license);
 
        if (eloop_init())
                return -1;
@@ -4373,7 +4284,7 @@ int main(int argc, char *argv[])
                        }
                }
 
-               if (daemonize && os_daemonize(pid_file))
+               if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
                        return -1;
 
                if (action_file)
index 850ec40..511df4f 100644 (file)
@@ -29,6 +29,8 @@ struct wpa_priv_interface {
        char *sock_name;
        int fd;
 
+       void *ctx;
+
        const struct wpa_driver_ops *driver;
        void *drv_priv;
        void *drv_global_priv;
@@ -40,6 +42,10 @@ struct wpa_priv_interface {
        struct sockaddr_un l2_addr;
 };
 
+struct wpa_priv_global {
+       struct wpa_priv_interface *interfaces;
+};
+
 
 static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
                                  struct sockaddr_un *from)
@@ -65,7 +71,8 @@ static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
 
        if (iface->driver->init2) {
                if (iface->driver->global_init) {
-                       iface->drv_global_priv = iface->driver->global_init();
+                       iface->drv_global_priv =
+                               iface->driver->global_init(iface->ctx);
                        if (!iface->drv_global_priv) {
                                wpa_printf(MSG_INFO,
                                           "Failed to initialize driver global context");
@@ -638,7 +645,7 @@ static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface)
 
 
 static struct wpa_priv_interface *
-wpa_priv_interface_init(const char *dir, const char *params)
+wpa_priv_interface_init(void *ctx, const char *dir, const char *params)
 {
        struct wpa_priv_interface *iface;
        char *pos;
@@ -654,6 +661,7 @@ wpa_priv_interface_init(const char *dir, const char *params)
        if (iface == NULL)
                return NULL;
        iface->fd = -1;
+       iface->ctx = ctx;
 
        len = pos - params;
        iface->driver_name = dup_binstr(params, len);
@@ -1002,6 +1010,37 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 }
 
 
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+                                union wpa_event_data *data)
+{
+       struct wpa_priv_global *global = ctx;
+       struct wpa_priv_interface *iface;
+
+       if (event != EVENT_INTERFACE_STATUS)
+               return;
+
+       for (iface = global->interfaces; iface; iface = iface->next) {
+               if (os_strcmp(iface->ifname, data->interface_status.ifname) ==
+                   0)
+                       break;
+       }
+       if (iface && iface->driver->get_ifindex) {
+               unsigned int ifindex;
+
+               ifindex = iface->driver->get_ifindex(iface->drv_priv);
+               if (ifindex != data->interface_status.ifindex) {
+                       wpa_printf(MSG_DEBUG,
+                                  "%s: interface status ifindex %d mismatch (%d)",
+                                  iface->ifname, ifindex,
+                                  data->interface_status.ifindex);
+                       return;
+               }
+       }
+       if (iface)
+               wpa_supplicant_event(iface, event, data);
+}
+
+
 void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
                             const u8 *buf, size_t len)
 {
@@ -1060,7 +1099,7 @@ static void wpa_priv_fd_workaround(void)
 static void usage(void)
 {
        printf("wpa_priv v" VERSION_STR "\n"
-              "Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi> and "
+              "Copyright (c) 2007-2016, Jouni Malinen <j@w1.fi> and "
               "contributors\n"
               "\n"
               "usage:\n"
@@ -1077,13 +1116,17 @@ int main(int argc, char *argv[])
        char *pid_file = NULL;
        int daemonize = 0;
        char *ctrl_dir = "/var/run/wpa_priv";
-       struct wpa_priv_interface *interfaces = NULL, *iface;
+       struct wpa_priv_global global;
+       struct wpa_priv_interface *iface;
 
        if (os_program_init())
                return -1;
 
        wpa_priv_fd_workaround();
 
+       os_memset(&global, 0, sizeof(global));
+       global.interfaces = NULL;
+
        for (;;) {
                c = getopt(argc, argv, "Bc:dP:");
                if (c < 0)
@@ -1121,14 +1164,14 @@ int main(int argc, char *argv[])
 
        for (i = optind; i < argc; i++) {
                wpa_printf(MSG_DEBUG, "Adding driver:interface %s", argv[i]);
-               iface = wpa_priv_interface_init(ctrl_dir, argv[i]);
+               iface = wpa_priv_interface_init(&global, ctrl_dir, argv[i]);
                if (iface == NULL)
                        goto out;
-               iface->next = interfaces;
-               interfaces = iface;
+               iface->next = global.interfaces;
+               global.interfaces = iface;
        }
 
-       if (daemonize && os_daemonize(pid_file))
+       if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
                goto out;
 
        eloop_register_signal_terminate(wpa_priv_terminate, NULL);
@@ -1137,7 +1180,7 @@ int main(int argc, char *argv[])
        ret = 0;
 
 out:
-       iface = interfaces;
+       iface = global.interfaces;
        while (iface) {
                struct wpa_priv_interface *prev = iface;
                iface = iface->next;
index ef55fdc..7361ee9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * 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"
+#ifdef CONFIG_MATCH_IFACE
+#include <net/if.h>
+#include <fnmatch.h>
+#endif /* CONFIG_MATCH_IFACE */
 
 #include "common.h"
 #include "crypto/random.h"
@@ -58,7 +62,7 @@
 
 const char *const wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> and contributors";
 
 const char *const wpa_supplicant_license =
 "This software may be distributed under the terms of the BSD license.\n"
@@ -188,7 +192,9 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_supplicant *wpa_s = eloop_ctx;
        const u8 *bssid = wpa_s->bssid;
-       if (is_zero_ether_addr(bssid))
+       if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+           (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+            wpa_s->wpa_state == WPA_ASSOCIATING))
                bssid = wpa_s->pending_bssid;
        wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
                MAC2STR(bssid));
@@ -397,6 +403,18 @@ void free_hw_features(struct wpa_supplicant *wpa_s)
 }
 
 
+static 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) {
+               dl_list_del(&bss->list);
+               os_free(bss);
+       }
+}
+
+
 static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 {
        int i;
@@ -536,6 +554,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        wpa_s->last_scan_res = NULL;
 
 #ifdef CONFIG_HS20
+       if (wpa_s->drv_priv)
+               wpa_drv_configure_frame_filters(wpa_s, 0);
        hs20_deinit(wpa_s);
 #endif /* CONFIG_HS20 */
 
@@ -545,6 +565,21 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        }
 
        wmm_ac_notify_disassoc(wpa_s);
+
+       wpa_s->sched_scan_plans_num = 0;
+       os_free(wpa_s->sched_scan_plans);
+       wpa_s->sched_scan_plans = NULL;
+
+#ifdef CONFIG_MBO
+       wpa_s->non_pref_chan_num = 0;
+       os_free(wpa_s->non_pref_chan);
+       wpa_s->non_pref_chan = NULL;
+#endif /* CONFIG_MBO */
+
+       free_bss_tmp_disallowed(wpa_s);
+
+       wpabuf_free(wpa_s->lci);
+       wpa_s->lci = NULL;
 }
 
 
@@ -963,6 +998,11 @@ static void wpa_supplicant_reconfig(int sig, void *signal_ctx)
                        wpa_supplicant_terminate_proc(global);
                }
        }
+
+       if (wpa_debug_reopen_file() < 0) {
+               /* Ignore errors since we cannot really do much to fix this */
+               wpa_printf(MSG_DEBUG, "Could not reopen debug log file");
+       }
 }
 
 
@@ -1150,6 +1190,10 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                        return -1;
        }
 
+#ifdef CONFIG_NO_WPA
+       wpa_s->group_cipher = WPA_CIPHER_NONE;
+       wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
+#else /* CONFIG_NO_WPA */
        sel = ie.group_cipher & ssid->group_cipher;
        wpa_s->group_cipher = wpa_pick_group_cipher(sel);
        if (wpa_s->group_cipher < 0) {
@@ -1169,6 +1213,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        }
        wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK %s",
                wpa_cipher_txt(wpa_s->pairwise_cipher));
+#endif /* CONFIG_NO_WPA */
 
        sel = ie.key_mgmt & ssid->key_mgmt;
 #ifdef CONFIG_SAE
@@ -1279,7 +1324,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                int psk_set = 0;
 
                if (ssid->psk_set) {
-                       wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL);
+                       wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL,
+                                      NULL);
                        psk_set = 1;
                }
 #ifndef CONFIG_NO_PBKDF2
@@ -1290,7 +1336,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                                    4096, psk, PMK_LEN);
                        wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
                                        psk, PMK_LEN);
-                       wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+                       wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, NULL);
                        psk_set = 1;
                        os_memset(psk, 0, sizeof(psk));
                }
@@ -1328,7 +1374,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                                wpa_hexdump_key(MSG_MSGDUMP, "PSK (from "
                                                "external passphrase)",
                                                psk, PMK_LEN);
-                               wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+                               wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
+                                              NULL);
                                psk_set = 1;
                                os_memset(psk, 0, sizeof(psk));
                        } else
@@ -1341,7 +1388,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                                        ext_password_free(pw);
                                        return -1;
                                }
-                               wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+                               wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
+                                              NULL);
                                psk_set = 1;
                                os_memset(psk, 0, sizeof(psk));
                        } else {
@@ -1404,9 +1452,20 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
                if (wpa_s->conf->hs20)
                        *pos |= 0x40; /* Bit 46 - WNM-Notification */
 #endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+               *pos |= 0x40; /* Bit 46 - WNM-Notification */
+#endif /* CONFIG_MBO */
                break;
        case 6: /* Bits 48-55 */
                break;
+       case 7: /* Bits 56-63 */
+               break;
+       case 8: /* Bits 64-71 */
+               if (wpa_s->conf->ftm_responder)
+                       *pos |= 0x40; /* Bit 70 - FTM responder */
+               if (wpa_s->conf->ftm_initiator)
+                       *pos |= 0x80; /* Bit 71 - FTM initiator */
+               break;
        }
 }
 
@@ -1416,6 +1475,9 @@ int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen)
        u8 *pos = buf;
        u8 len = 6, i;
 
+       if (len < 9 &&
+           (wpa_s->conf->ftm_initiator || wpa_s->conf->ftm_responder))
+               len = 9;
        if (len < wpa_s->extended_capa_len)
                len = wpa_s->extended_capa_len;
        if (buflen < (size_t) len + 2) {
@@ -1586,6 +1648,15 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        struct wpa_connect_work *cwork;
        int rand_style;
 
+       wpa_s->own_disconnect_req = 0;
+
+       /*
+        * If we are starting a new connection, any previously pending EAPOL
+        * RX cannot be valid anymore.
+        */
+       wpabuf_free(wpa_s->pending_eapol_rx);
+       wpa_s->pending_eapol_rx = NULL;
+
        if (ssid->mac_addr == -1)
                rand_style = wpa_s->conf->mac_addr;
        else
@@ -1593,9 +1664,11 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 
        wmm_ac_clear_saved_tspecs(wpa_s);
        wpa_s->reassoc_same_bss = 0;
+       wpa_s->reassoc_same_ess = 0;
 
        if (wpa_s->last_ssid == ssid) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
+               wpa_s->reassoc_same_ess = 1;
                if (wpa_s->current_bss && wpa_s->current_bss == bss) {
                        wmm_ac_save_tspecs(wpa_s);
                        wpa_s->reassoc_same_bss = 1;
@@ -1661,10 +1734,9 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                        return;
                }
                wpa_s->current_bss = bss;
-               wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_STARTED
-                            "ssid=\"%s\" id=%d",
-                            wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
-                            ssid->id);
+               wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_STARTED "ssid=\"%s\" id=%d",
+                       wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+                       ssid->id);
 #else /* CONFIG_MESH */
                wpa_msg(wpa_s, MSG_ERROR,
                        "mesh mode support not included in the build");
@@ -1694,6 +1766,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                return;
        }
 
+       wpas_abort_ongoing_scan(wpa_s);
+
        cwork = os_zalloc(sizeof(*cwork));
        if (cwork == NULL)
                return;
@@ -1715,6 +1789,36 @@ static int bss_is_ibss(struct wpa_bss *bss)
 }
 
 
+static int drv_supports_vht(struct wpa_supplicant *wpa_s,
+                           const struct wpa_ssid *ssid)
+{
+       enum hostapd_hw_mode hw_mode;
+       struct hostapd_hw_modes *mode = NULL;
+       u8 channel;
+       int i;
+
+#ifdef CONFIG_HT_OVERRIDES
+       if (ssid->disable_ht)
+               return 0;
+#endif /* CONFIG_HT_OVERRIDES */
+
+       hw_mode = ieee80211_freq_to_chan(ssid->frequency, &channel);
+       if (hw_mode == NUM_HOSTAPD_MODES)
+               return 0;
+       for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
+               if (wpa_s->hw.modes[i].mode == hw_mode) {
+                       mode = &wpa_s->hw.modes[i];
+                       break;
+               }
+       }
+
+       if (!mode)
+               return 0;
+
+       return mode->vht_capab != 0;
+}
+
+
 void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
                          const struct wpa_ssid *ssid,
                          struct hostapd_freq_params *freq)
@@ -1727,8 +1831,10 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
        struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL;
        u8 channel;
        int i, chan_idx, ht40 = -1, res, obss_scan = 1;
-       unsigned int j;
+       unsigned int j, k;
        struct hostapd_freq_params vht_freq;
+       int chwidth, seg0, seg1;
+       u32 vht_caps = 0;
 
        freq->freq = ssid->frequency;
 
@@ -1780,6 +1886,13 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
        if (!mode)
                return;
 
+#ifdef CONFIG_HT_OVERRIDES
+       if (ssid->disable_ht) {
+               freq->ht_enabled = 0;
+               return;
+       }
+#endif /* CONFIG_HT_OVERRIDES */
+
        freq->ht_enabled = ht_supported(mode);
        if (!freq->ht_enabled)
                return;
@@ -1801,6 +1914,11 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
        if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
                return;
 
+#ifdef CONFIG_HT_OVERRIDES
+       if (ssid->disable_ht40)
+               return;
+#endif /* CONFIG_HT_OVERRIDES */
+
        /* Check/setup HT40+/HT40- */
        for (j = 0; j < ARRAY_SIZE(ht40plus); j++) {
                if (ht40plus[j] == channel) {
@@ -1825,22 +1943,16 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
 
        freq->channel = pri_chan->chan;
 
-       switch (ht40) {
-       case -1:
+       if (ht40 == -1) {
                if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
                        return;
-               freq->sec_channel_offset = -1;
-               break;
-       case 1:
+       } else {
                if (!(pri_chan->flag & HOSTAPD_CHAN_HT40PLUS))
                        return;
-               freq->sec_channel_offset = 1;
-               break;
-       default:
-               break;
        }
+       freq->sec_channel_offset = ht40;
 
-       if (freq->sec_channel_offset && obss_scan) {
+       if (obss_scan) {
                struct wpa_scan_results *scan_res;
 
                scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
@@ -1878,12 +1990,12 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
                   "IBSS/mesh: setup freq channel %d, sec_channel_offset %d",
                   freq->channel, freq->sec_channel_offset);
 
-       /* Not sure if mesh is ready for VHT */
-       if (ssid->mode != WPAS_MODE_IBSS)
+       if (!drv_supports_vht(wpa_s, ssid))
                return;
 
        /* For IBSS check VHT_IBSS flag */
-       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS))
+       if (ssid->mode == WPAS_MODE_IBSS &&
+           !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS))
                return;
 
        vht_freq = *freq;
@@ -1914,12 +2026,55 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
                        return;
        }
 
+       chwidth = VHT_CHANWIDTH_80MHZ;
+       seg0 = vht80[j] + 6;
+       seg1 = 0;
+
+       if (ssid->max_oper_chwidth == VHT_CHANWIDTH_80P80MHZ) {
+               /* setup center_freq2, bandwidth */
+               for (k = 0; k < ARRAY_SIZE(vht80); k++) {
+                       /* Only accept 80 MHz segments separated by a gap */
+                       if (j == k || abs(vht80[j] - vht80[k]) == 16)
+                               continue;
+                       for (i = vht80[k]; i < vht80[k] + 16; i += 4) {
+                               struct hostapd_channel_data *chan;
+
+                               chan = hw_get_channel_chan(mode, i, NULL);
+                               if (!chan)
+                                       continue;
+
+                               if (chan->flag & (HOSTAPD_CHAN_DISABLED |
+                                                 HOSTAPD_CHAN_NO_IR |
+                                                 HOSTAPD_CHAN_RADAR))
+                                       continue;
+
+                               /* Found a suitable second segment for 80+80 */
+                               chwidth = VHT_CHANWIDTH_80P80MHZ;
+                               vht_caps |=
+                                       VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+                               seg1 = vht80[k] + 6;
+                       }
+
+                       if (chwidth == VHT_CHANWIDTH_80P80MHZ)
+                               break;
+               }
+       } else if (ssid->max_oper_chwidth == VHT_CHANWIDTH_160MHZ) {
+               if (freq->freq == 5180) {
+                       chwidth = VHT_CHANWIDTH_160MHZ;
+                       vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+                       seg0 = 50;
+               } else if (freq->freq == 5520) {
+                       chwidth = VHT_CHANWIDTH_160MHZ;
+                       vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+                       seg0 = 114;
+               }
+       }
+
        if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
                                    freq->channel, freq->ht_enabled,
                                    vht_freq.vht_enabled,
                                    freq->sec_channel_offset,
-                                   VHT_CHANWIDTH_80MHZ,
-                                   vht80[j] + 6, 0, 0) != 0)
+                                   chwidth, seg0, seg1, vht_caps) != 0)
                return;
 
        *freq = vht_freq;
@@ -1944,6 +2099,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        int wep_keys_set = 0;
        int assoc_failed = 0;
        struct wpa_ssid *old_ssid;
+       u8 prev_bssid[ETH_ALEN];
 #ifdef CONFIG_HT_OVERRIDES
        struct ieee80211_ht_capabilities htcaps;
        struct ieee80211_ht_capabilities htcaps_mask;
@@ -1952,6 +2108,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        struct ieee80211_vht_capabilities vhtcaps;
        struct ieee80211_vht_capabilities vhtcaps_mask;
 #endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_MBO
+       const u8 *mbo = NULL;
+#endif /* CONFIG_MBO */
 
        if (deinit) {
                if (work->started) {
@@ -1974,6 +2133,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                return;
        }
 
+       os_memcpy(prev_bssid, wpa_s->bssid, ETH_ALEN);
        os_memset(&params, 0, sizeof(params));
        wpa_s->reassociate = 0;
        wpa_s->eap_expected_failure = 0;
@@ -2015,7 +2175,10 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        } else {
                wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
                        wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
-               os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+               if (bss)
+                       os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+               else
+                       os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
        }
        if (!wpa_s->pno)
                wpa_supplicant_cancel_sched_scan(wpa_s);
@@ -2136,25 +2299,21 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
 #endif /* CONFIG_P2P */
 
-#ifdef CONFIG_HS20
-       if (is_hs20_network(wpa_s, ssid, bss)) {
-               struct wpabuf *hs20;
-               hs20 = wpabuf_alloc(20);
-               if (hs20) {
-                       int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
-                       size_t len;
-
-                       wpas_hs20_add_indication(hs20, pps_mo_id);
-                       len = sizeof(wpa_ie) - wpa_ie_len;
-                       if (wpabuf_len(hs20) <= len) {
-                               os_memcpy(wpa_ie + wpa_ie_len,
-                                         wpabuf_head(hs20), wpabuf_len(hs20));
-                               wpa_ie_len += wpabuf_len(hs20);
-                       }
-                       wpabuf_free(hs20);
+#ifdef CONFIG_MBO
+       if (bss) {
+               mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
+               if (mbo) {
+                       int len;
+
+                       len = wpas_mbo_supp_op_class_ie(wpa_s, bss->freq,
+                                                       wpa_ie + wpa_ie_len,
+                                                       sizeof(wpa_ie) -
+                                                       wpa_ie_len);
+                       if (len > 0)
+                               wpa_ie_len += len;
                }
        }
-#endif /* CONFIG_HS20 */
+#endif /* CONFIG_MBO */
 
        /*
         * Workaround: Add Extended Capabilities element only if the AP
@@ -2164,6 +2323,11 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
         * element in all cases, it is justifiable to skip it to avoid
         * interoperability issues.
         */
+       if (ssid->p2p_group)
+               wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
+       else
+               wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+
        if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
                u8 ext_capab[18];
                int ext_capab_len;
@@ -2180,6 +2344,29 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                }
        }
 
+#ifdef CONFIG_HS20
+       if (is_hs20_network(wpa_s, ssid, bss)) {
+               struct wpabuf *hs20;
+
+               hs20 = wpabuf_alloc(20);
+               if (hs20) {
+                       int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
+                       size_t len;
+
+                       wpas_hs20_add_indication(hs20, pps_mo_id);
+                       len = sizeof(wpa_ie) - wpa_ie_len;
+                       if (wpabuf_len(hs20) <= len) {
+                               os_memcpy(wpa_ie + wpa_ie_len,
+                                         wpabuf_head(hs20), wpabuf_len(hs20));
+                               wpa_ie_len += wpabuf_len(hs20);
+                       }
+                       wpabuf_free(hs20);
+
+                       hs20_configure_frame_filters(wpa_s);
+               }
+       }
+#endif /* CONFIG_HS20 */
+
        if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
                struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
                size_t len;
@@ -2204,6 +2391,17 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        }
 #endif /* CONFIG_FST */
 
+#ifdef CONFIG_MBO
+       if (mbo) {
+               int len;
+
+               len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
+                                 sizeof(wpa_ie) - wpa_ie_len);
+               if (len >= 0)
+                       wpa_ie_len += len;
+       }
+#endif /* CONFIG_MBO */
+
        wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
        use_crypt = 1;
        cipher_pairwise = wpa_s->pairwise_cipher;
@@ -2256,9 +2454,11 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                }
                params.bssid_hint = bss->bssid;
                params.freq_hint = bss->freq;
+               params.pbss = bss_is_pbss(bss);
        } else {
                params.ssid = ssid->ssid;
                params.ssid_len = ssid->ssid_len;
+               params.pbss = (ssid->pbss != 2) ? ssid->pbss : 0;
        }
 
        if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set &&
@@ -2342,8 +2542,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
 
        params.p2p = ssid->p2p_group;
 
-       if (wpa_s->parent->set_sta_uapsd)
-               params.uapsd = wpa_s->parent->sta_uapsd;
+       if (wpa_s->p2pdev->set_sta_uapsd)
+               params.uapsd = wpa_s->p2pdev->sta_uapsd;
        else
                params.uapsd = -1;
 
@@ -2384,6 +2584,10 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        }
 #endif /* CONFIG_P2P */
 
+       if (wpa_s->reassoc_same_ess && !is_zero_ether_addr(prev_bssid) &&
+           wpa_s->current_ssid)
+               params.prev_bssid = prev_bssid;
+
        ret = wpa_drv_associate(wpa_s, &params);
        if (ret < 0) {
                wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
@@ -2451,8 +2655,14 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        }
        old_ssid = wpa_s->current_ssid;
        wpa_s->current_ssid = ssid;
-       if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set)
+
+       if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
                wpa_s->current_bss = bss;
+#ifdef CONFIG_HS20
+               hs20_configure_frame_filters(wpa_s);
+#endif /* CONFIG_HS20 */
+       }
+
        wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
        wpa_supplicant_initiate_eapol(wpa_s);
        if (old_ssid != wpa_s->current_ssid)
@@ -2497,12 +2707,12 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
                reason_code, wpa_supplicant_state_txt(wpa_s->wpa_state));
 
-       if (!is_zero_ether_addr(wpa_s->bssid))
-               addr = wpa_s->bssid;
-       else if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
-                (wpa_s->wpa_state == WPA_AUTHENTICATING ||
-                 wpa_s->wpa_state == WPA_ASSOCIATING))
+       if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+           (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+            wpa_s->wpa_state == WPA_ASSOCIATING))
                addr = wpa_s->pending_bssid;
+       else if (!is_zero_ether_addr(wpa_s->bssid))
+               addr = wpa_s->bssid;
        else if (wpa_s->wpa_state == WPA_ASSOCIATING) {
                /*
                 * When using driver-based BSS selection, we may not know the
@@ -2520,8 +2730,8 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_MESH
        if (wpa_s->ifmsh) {
-               wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s",
-                            wpa_s->ifname);
+               wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s",
+                       wpa_s->ifname);
                wpa_supplicant_leave_mesh(wpa_s);
        }
 #endif /* CONFIG_MESH */
@@ -2559,6 +2769,95 @@ static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
 
 
 /**
+ * wpa_supplicant_add_network - Add a new network
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: The new network configuration or %NULL if operation failed
+ *
+ * This function performs the following operations:
+ * 1. Adds a new network.
+ * 2. Send network addition notification.
+ * 3. Marks the network disabled.
+ * 4. Set network default parameters.
+ */
+struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_ssid *ssid;
+
+       ssid = wpa_config_add_network(wpa_s->conf);
+       if (!ssid)
+               return NULL;
+       wpas_notify_network_added(wpa_s, ssid);
+       ssid->disabled = 1;
+       wpa_config_set_network_defaults(ssid);
+
+       return ssid;
+}
+
+
+/**
+ * wpa_supplicant_remove_network - Remove a configured network based on id
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @id: Unique network id to search for
+ * Returns: 0 on success, or -1 if the network was not found, -2 if the network
+ * could not be removed
+ *
+ * This function performs the following operations:
+ * 1. Removes the network.
+ * 2. Send network removal notification.
+ * 3. Update internal state machines.
+ * 4. Stop any running sched scans.
+ */
+int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
+{
+       struct wpa_ssid *ssid;
+       int was_disabled;
+
+       ssid = wpa_config_get_network(wpa_s->conf, id);
+       if (!ssid)
+               return -1;
+       wpas_notify_network_removed(wpa_s, ssid);
+
+       if (wpa_s->last_ssid == ssid)
+               wpa_s->last_ssid = NULL;
+
+       if (ssid == wpa_s->current_ssid || !wpa_s->current_ssid) {
+#ifdef CONFIG_SME
+               wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+               /*
+                * Invalidate the EAP session cache if the current or
+                * previously used network is removed.
+                */
+               eapol_sm_invalidate_cached_session(wpa_s->eapol);
+       }
+
+       if (ssid == wpa_s->current_ssid) {
+               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);
+       }
+
+       was_disabled = ssid->disabled;
+
+       if (wpa_config_remove_network(wpa_s->conf, id) < 0)
+               return -2;
+
+       if (!was_disabled && wpa_s->sched_scanning) {
+               wpa_printf(MSG_DEBUG,
+                          "Stop ongoing sched_scan to remove network from filters");
+               wpa_supplicant_cancel_sched_scan(wpa_s);
+               wpa_supplicant_req_scan(wpa_s, 0, 0);
+       }
+
+       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
@@ -2688,7 +2987,8 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
                        wpas_notify_network_enabled_changed(wpa_s, other_ssid);
        }
 
-       if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid) {
+       if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid &&
+           wpa_s->wpa_state >= WPA_AUTHENTICATING) {
                /* We are already associated with the selected network */
                wpa_printf(MSG_DEBUG, "Already associated with the "
                           "selected network - do nothing");
@@ -2717,6 +3017,7 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
        if (wpa_s->connect_without_scan ||
            wpa_supplicant_fast_associate(wpa_s) != 1) {
                wpa_s->scan_req = NORMAL_SCAN_REQ;
+               wpas_scan_reset_sched_scan(wpa_s);
                wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
        }
 
@@ -2994,7 +3295,7 @@ static int select_driver(struct wpa_supplicant *wpa_s, int i)
        struct wpa_global *global = wpa_s->global;
 
        if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) {
-               global->drv_priv[i] = wpa_drivers[i]->global_init();
+               global->drv_priv[i] = wpa_drivers[i]->global_init(global);
                if (global->drv_priv[i] == NULL) {
                        wpa_printf(MSG_ERROR, "Failed to initialize driver "
                                   "'%s'", wpa_drivers[i]->name);
@@ -3077,6 +3378,13 @@ 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);
 
+#ifdef CONFIG_TESTING_OPTIONS
+       if (wpa_s->ignore_auth_resp) {
+               wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!");
+               return;
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
+
 #ifdef CONFIG_PEERKEY
        if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid &&
            wpa_s->current_ssid->peerkey &&
@@ -3361,8 +3669,11 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
        wpa_s->scan_interval = 5;
        wpa_s->new_connection = 1;
        wpa_s->parent = parent ? parent : wpa_s;
+       wpa_s->p2pdev = wpa_s->parent;
        wpa_s->sched_scanning = 0;
 
+       dl_list_init(&wpa_s->bss_tmp_disallowed);
+
        return wpa_s;
 }
 
@@ -3614,8 +3925,8 @@ void wpa_supplicant_apply_vht_overrides(
        if (!vhtcaps || !vhtcaps_mask)
                return;
 
-       vhtcaps->vht_capabilities_info = ssid->vht_capa;
-       vhtcaps_mask->vht_capabilities_info = ssid->vht_capa_mask;
+       vhtcaps->vht_capabilities_info = host_to_le32(ssid->vht_capa);
+       vhtcaps_mask->vht_capabilities_info = host_to_le32(ssid->vht_capa_mask);
 
 #ifdef CONFIG_HT_OVERRIDES
        /* if max ampdu is <= 3, we have to make the HT cap the same */
@@ -3637,15 +3948,17 @@ void wpa_supplicant_apply_vht_overrides(
 #define OVERRIDE_MCS(i)                                                        \
        if (ssid->vht_tx_mcs_nss_ ##i >= 0) {                           \
                vhtcaps_mask->vht_supported_mcs_set.tx_map |=           \
-                       3 << 2 * (i - 1);                               \
+                       host_to_le16(3 << 2 * (i - 1));                 \
                vhtcaps->vht_supported_mcs_set.tx_map |=                \
-                       ssid->vht_tx_mcs_nss_ ##i << 2 * (i - 1);       \
+                       host_to_le16(ssid->vht_tx_mcs_nss_ ##i <<       \
+                                    2 * (i - 1));                      \
        }                                                               \
        if (ssid->vht_rx_mcs_nss_ ##i >= 0) {                           \
                vhtcaps_mask->vht_supported_mcs_set.rx_map |=           \
-                       3 << 2 * (i - 1);                               \
+                       host_to_le16(3 << 2 * (i - 1));                 \
                vhtcaps->vht_supported_mcs_set.rx_map |=                \
-                       ssid->vht_rx_mcs_nss_ ##i << 2 * (i - 1);       \
+                       host_to_le16(ssid->vht_rx_mcs_nss_ ##i <<       \
+                                    2 * (i - 1));                      \
        }
 
        OVERRIDE_MCS(1);
@@ -3817,8 +4130,9 @@ static void wpas_fst_update_mb_ie_cb(void *ctx, const u8 *addr,
 }
 
 
-const u8 * wpas_fst_get_peer_first(void *ctx, struct fst_get_peer_ctx **get_ctx,
-                                  Boolean mb_only)
+static const u8 * wpas_fst_get_peer_first(void *ctx,
+                                         struct fst_get_peer_ctx **get_ctx,
+                                         Boolean mb_only)
 {
        struct wpa_supplicant *wpa_s = ctx;
 
@@ -3830,8 +4144,9 @@ const u8 * wpas_fst_get_peer_first(void *ctx, struct fst_get_peer_ctx **get_ctx,
 }
 
 
-const u8 * wpas_fst_get_peer_next(void *ctx, struct fst_get_peer_ctx **get_ctx,
-                                 Boolean mb_only)
+static const u8 * wpas_fst_get_peer_next(void *ctx,
+                                        struct fst_get_peer_ctx **get_ctx,
+                                        Boolean mb_only)
 {
        return NULL;
 }
@@ -3870,6 +4185,55 @@ static int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s,
 }
 
 
+enum wpa_radio_work_band wpas_freq_to_band(int freq)
+{
+       if (freq < 3000)
+               return BAND_2_4_GHZ;
+       if (freq > 50000)
+               return BAND_60_GHZ;
+       return BAND_5_GHZ;
+}
+
+
+unsigned int wpas_get_bands(struct wpa_supplicant *wpa_s, const int *freqs)
+{
+       int i;
+       unsigned int band = 0;
+
+       if (freqs) {
+               /* freqs are specified for the radio work */
+               for (i = 0; freqs[i]; i++)
+                       band |= wpas_freq_to_band(freqs[i]);
+       } else {
+               /*
+                * freqs are not specified, implies all
+                * the supported freqs by HW
+                */
+               for (i = 0; i < wpa_s->hw.num_modes; i++) {
+                       if (wpa_s->hw.modes[i].num_channels != 0) {
+                               if (wpa_s->hw.modes[i].mode ==
+                                   HOSTAPD_MODE_IEEE80211B ||
+                                   wpa_s->hw.modes[i].mode ==
+                                   HOSTAPD_MODE_IEEE80211G)
+                                       band |= BAND_2_4_GHZ;
+                               else if (wpa_s->hw.modes[i].mode ==
+                                        HOSTAPD_MODE_IEEE80211A)
+                                       band |= BAND_5_GHZ;
+                               else if (wpa_s->hw.modes[i].mode ==
+                                        HOSTAPD_MODE_IEEE80211AD)
+                                       band |= BAND_60_GHZ;
+                               else if (wpa_s->hw.modes[i].mode ==
+                                        HOSTAPD_MODE_IEEE80211ANY)
+                                       band = BAND_2_4_GHZ | BAND_5_GHZ |
+                                               BAND_60_GHZ;
+                       }
+               }
+       }
+
+       return band;
+}
+
+
 static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s,
                                              const char *rn)
 {
@@ -3922,11 +4286,103 @@ static void radio_work_free(struct wpa_radio_work *work)
        }
 #endif /* CONFIG_P2P */
 
+       if (work->started) {
+               work->wpa_s->radio->num_active_works--;
+               wpa_dbg(work->wpa_s, MSG_DEBUG,
+                       "radio_work_free('%s'@%p: num_active_works --> %u",
+                       work->type, work,
+                       work->wpa_s->radio->num_active_works);
+       }
+
        dl_list_del(&work->list);
        os_free(work);
 }
 
 
+static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
+{
+       struct wpa_radio_work *active_work = NULL;
+       struct wpa_radio_work *tmp;
+
+       /* Get the active work to know the type and band. */
+       dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) {
+               if (tmp->started) {
+                       active_work = tmp;
+                       break;
+               }
+       }
+
+       if (!active_work) {
+               /* No active work, start one */
+               radio->num_active_works = 0;
+               dl_list_for_each(tmp, &radio->work, struct wpa_radio_work,
+                                list) {
+                       if (os_strcmp(tmp->type, "scan") == 0 &&
+                           radio->external_scan_running &&
+                           (((struct wpa_driver_scan_params *)
+                             tmp->ctx)->only_new_results ||
+                            tmp->wpa_s->clear_driver_scan_cache))
+                               continue;
+                       return tmp;
+               }
+               return NULL;
+       }
+
+       if (os_strcmp(active_work->type, "sme-connect") == 0 ||
+           os_strcmp(active_work->type, "connect") == 0) {
+               /*
+                * If the active work is either connect or sme-connect,
+                * do not parallelize them with other radio works.
+                */
+               wpa_dbg(active_work->wpa_s, MSG_DEBUG,
+                       "Do not parallelize radio work with %s",
+                       active_work->type);
+               return NULL;
+       }
+
+       dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) {
+               if (tmp->started)
+                       continue;
+
+               /*
+                * If connect or sme-connect are enqueued, parallelize only
+                * those operations ahead of them in the queue.
+                */
+               if (os_strcmp(tmp->type, "connect") == 0 ||
+                   os_strcmp(tmp->type, "sme-connect") == 0)
+                       break;
+
+               /*
+                * Check that the radio works are distinct and
+                * on different bands.
+                */
+               if (os_strcmp(active_work->type, tmp->type) != 0 &&
+                   (active_work->bands != tmp->bands)) {
+                       /*
+                        * If a scan has to be scheduled through nl80211 scan
+                        * interface and if an external scan is already running,
+                        * do not schedule the scan since it is likely to get
+                        * rejected by kernel.
+                        */
+                       if (os_strcmp(tmp->type, "scan") == 0 &&
+                           radio->external_scan_running &&
+                           (((struct wpa_driver_scan_params *)
+                             tmp->ctx)->only_new_results ||
+                            tmp->wpa_s->clear_driver_scan_cache))
+                               continue;
+
+                       wpa_dbg(active_work->wpa_s, MSG_DEBUG,
+                               "active_work:%s new_work:%s",
+                               active_work->type, tmp->type);
+                       return tmp;
+               }
+       }
+
+       /* Did not find a radio work to schedule in parallel. */
+       return NULL;
+}
+
+
 static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_radio *radio = eloop_ctx;
@@ -3935,26 +4391,48 @@ static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
        struct wpa_supplicant *wpa_s;
 
        work = dl_list_first(&radio->work, struct wpa_radio_work, list);
-       if (work == NULL)
+       if (work == NULL) {
+               radio->num_active_works = 0;
                return;
-
-       if (work->started)
-               return; /* already started and still in progress */
+       }
 
        wpa_s = dl_list_first(&radio->ifaces, struct wpa_supplicant,
                              radio_list);
-       if (wpa_s && wpa_s->radio->external_scan_running) {
-               wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
-               return;
+
+       if (!(wpa_s &&
+             wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS)) {
+               if (work->started)
+                       return; /* already started and still in progress */
+
+               if (wpa_s && wpa_s->radio->external_scan_running) {
+                       wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
+                       return;
+               }
+       } else {
+               work = NULL;
+               if (radio->num_active_works < MAX_ACTIVE_WORKS) {
+                       /* get the work to schedule next */
+                       work = radio_work_get_next_work(radio);
+               }
+               if (!work)
+                       return;
        }
 
+       wpa_s = work->wpa_s;
        os_get_reltime(&now);
        os_reltime_sub(&now, &work->time, &diff);
-       wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting radio work '%s'@%p after %ld.%06ld second wait",
+       wpa_dbg(wpa_s, MSG_DEBUG,
+               "Starting radio work '%s'@%p after %ld.%06ld second wait",
                work->type, work, diff.sec, diff.usec);
        work->started = 1;
        work->time = now;
+       radio->num_active_works++;
+
        work->cb(work, 0);
+
+       if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS) &&
+           radio->num_active_works < MAX_ACTIVE_WORKS)
+               radio_work_check_next(wpa_s);
 }
 
 
@@ -4062,6 +4540,7 @@ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
                   void (*cb)(struct wpa_radio_work *work, int deinit),
                   void *ctx)
 {
+       struct wpa_radio *radio = wpa_s->radio;
        struct wpa_radio_work *work;
        int was_empty;
 
@@ -4076,6 +4555,16 @@ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
        work->cb = cb;
        work->ctx = ctx;
 
+       if (freq)
+               work->bands = wpas_freq_to_band(freq);
+       else if (os_strcmp(type, "scan") == 0 ||
+                os_strcmp(type, "p2p-scan") == 0)
+               work->bands = wpas_get_bands(wpa_s,
+                                            ((struct wpa_driver_scan_params *)
+                                             ctx)->freqs);
+       else
+               work->bands = wpas_get_bands(wpa_s, NULL);
+
        was_empty = dl_list_empty(&wpa_s->radio->work);
        if (next)
                dl_list_add(&wpa_s->radio->work, &work->list);
@@ -4084,6 +4573,12 @@ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
        if (was_empty) {
                wpa_dbg(wpa_s, MSG_DEBUG, "First radio work item in the queue - schedule start immediately");
                radio_work_check_next(wpa_s);
+       } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS)
+                  && radio->num_active_works < MAX_ACTIVE_WORKS) {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "Try to schedule a radio work (num_active_works=%u)",
+                       radio->num_active_works);
+               radio_work_check_next(wpa_s);
        }
 
        return 0;
@@ -4339,6 +4834,11 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
                wpa_s->max_scan_ssids = capa.max_scan_ssids;
                wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
+               wpa_s->max_sched_scan_plans = capa.max_sched_scan_plans;
+               wpa_s->max_sched_scan_plan_interval =
+                       capa.max_sched_scan_plan_interval;
+               wpa_s->max_sched_scan_plan_iterations =
+                       capa.max_sched_scan_plan_iterations;
                wpa_s->sched_scan_supported = capa.sched_scan_supported;
                wpa_s->max_match_sets = capa.max_match_sets;
                wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
@@ -4478,6 +4978,17 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
 
        wpas_rrm_reset(wpa_s);
 
+       wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);
+
+#ifdef CONFIG_HS20
+       hs20_init(wpa_s);
+#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+       wpas_mbo_update_non_pref_chan(wpa_s, wpa_s->conf->non_pref_chan);
+#endif /* CONFIG_MBO */
+
+       wpa_supplicant_set_default_scan_ies(wpa_s);
+
        return 0;
 }
 
@@ -4493,6 +5004,8 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
 
        iface = global->ifaces;
        while (iface) {
+               if (iface->p2pdev == wpa_s)
+                       iface->p2pdev = iface->parent;
                if (iface == wpa_s || iface->parent != wpa_s) {
                        iface = iface->next;
                        continue;
@@ -4563,6 +5076,74 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
 }
 
 
+#ifdef CONFIG_MATCH_IFACE
+
+/**
+ * wpa_supplicant_match_iface - Match an interface description to a name
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @ifname: Name of the interface to match
+ * Returns: Pointer to the created interface description or %NULL on failure
+ */
+struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
+                                                 const char *ifname)
+{
+       int i;
+       struct wpa_interface *iface, *miface;
+
+       for (i = 0; i < global->params.match_iface_count; i++) {
+               miface = &global->params.match_ifaces[i];
+               if (!miface->ifname ||
+                   fnmatch(miface->ifname, ifname, 0) == 0) {
+                       iface = os_zalloc(sizeof(*iface));
+                       if (!iface)
+                               return NULL;
+                       *iface = *miface;
+                       iface->ifname = ifname;
+                       return iface;
+               }
+       }
+
+       return NULL;
+}
+
+
+/**
+ * wpa_supplicant_match_existing - Match existing interfaces
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_supplicant_match_existing(struct wpa_global *global)
+{
+       struct if_nameindex *ifi, *ifp;
+       struct wpa_supplicant *wpa_s;
+       struct wpa_interface *iface;
+
+       ifp = if_nameindex();
+       if (!ifp) {
+               wpa_printf(MSG_ERROR, "if_nameindex: %s", strerror(errno));
+               return -1;
+       }
+
+       for (ifi = ifp; ifi->if_name; ifi++) {
+               wpa_s = wpa_supplicant_get_iface(global, ifi->if_name);
+               if (wpa_s)
+                       continue;
+               iface = wpa_supplicant_match_iface(global, ifi->if_name);
+               if (iface) {
+                       wpa_s = wpa_supplicant_add_iface(global, iface, NULL);
+                       os_free(iface);
+                       if (wpa_s)
+                               wpa_s->matched = 1;
+               }
+       }
+
+       if_freenameindex(ifp);
+       return 0;
+}
+
+#endif /* CONFIG_MATCH_IFACE */
+
+
 /**
  * wpa_supplicant_add_iface - Add a new network interface
  * @global: Pointer to global data from wpa_supplicant_init()
@@ -4864,6 +5445,18 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
        if (params->override_ctrl_interface)
                global->params.override_ctrl_interface =
                        os_strdup(params->override_ctrl_interface);
+#ifdef CONFIG_MATCH_IFACE
+       global->params.match_iface_count = params->match_iface_count;
+       if (params->match_iface_count) {
+               global->params.match_ifaces =
+                       os_calloc(params->match_iface_count,
+                                 sizeof(struct wpa_interface));
+               os_memcpy(global->params.match_ifaces,
+                         params->match_ifaces,
+                         params->match_iface_count *
+                         sizeof(struct wpa_interface));
+       }
+#endif /* CONFIG_MATCH_IFACE */
 #ifdef CONFIG_P2P
        if (params->conf_p2p_dev)
                global->params.conf_p2p_dev =
@@ -4939,12 +5532,18 @@ int wpa_supplicant_run(struct wpa_global *global)
        struct wpa_supplicant *wpa_s;
 
        if (global->params.daemonize &&
-           wpa_supplicant_daemon(global->params.pid_file))
+           (wpa_supplicant_daemon(global->params.pid_file) ||
+            eloop_sock_requeue()))
+               return -1;
+
+#ifdef CONFIG_MATCH_IFACE
+       if (wpa_supplicant_match_existing(global))
                return -1;
+#endif
 
        if (global->params.wait_for_monitor) {
                for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
-                       if (wpa_s->ctrl_iface)
+                       if (wpa_s->ctrl_iface && !wpa_s->p2p_mgmt)
                                wpa_supplicant_ctrl_iface_wait(
                                        wpa_s->ctrl_iface);
        }
@@ -5010,6 +5609,9 @@ void wpa_supplicant_deinit(struct wpa_global *global)
        os_free(global->params.ctrl_interface_group);
        os_free(global->params.override_driver);
        os_free(global->params.override_ctrl_interface);
+#ifdef CONFIG_MATCH_IFACE
+       os_free(global->params.match_ifaces);
+#endif /* CONFIG_MATCH_IFACE */
 #ifdef CONFIG_P2P
        os_free(global->params.conf_p2p_dev);
 #endif /* CONFIG_P2P */
@@ -5042,6 +5644,9 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
        if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND)
                wpas_init_ext_pw(wpa_s);
 
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_SCHED_SCAN_PLANS)
+               wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);
+
 #ifdef CONFIG_WPS
        wpas_wps_update_config(wpa_s);
 #endif /* CONFIG_WPS */
@@ -5281,6 +5886,16 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
                if (wpa_s->wpa_state == WPA_SCANNING && !wpa_s->scanning)
                        wpa_supplicant_req_scan(wpa_s, 0, 0);
                break;
+       case WPA_CTRL_REQ_EXT_CERT_CHECK:
+               if (eap->pending_ext_cert_check != PENDING_CHECK)
+                       return -1;
+               if (os_strcmp(value, "good") == 0)
+                       eap->pending_ext_cert_check = EXT_CERT_CHECK_GOOD;
+               else if (os_strcmp(value, "bad") == 0)
+                       eap->pending_ext_cert_check = EXT_CERT_CHECK_BAD;
+               else
+                       return -1;
+               break;
        default:
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
                return -1;
@@ -5350,6 +5965,19 @@ int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
                        return NO_MGMT_FRAME_PROTECTION;
                }
 
+               if (ssid &&
+                   (ssid->key_mgmt &
+                    ~(WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPS |
+                      WPA_KEY_MGMT_IEEE8021X_NO_WPA)) == 0) {
+                       /*
+                        * Do not use the default PMF value for non-RSN networks
+                        * since PMF is available only with RSN and pmf=2
+                        * configuration would otherwise prevent connections to
+                        * all open networks.
+                        */
+                       return NO_MGMT_FRAME_PROTECTION;
+               }
+
                return wpa_s->conf->pmf;
        }
 
@@ -5508,6 +6136,27 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s)
 }
 
 
+/**
+ * wpas_request_disconnection - Request disconnection
+ * @wpa_s: Pointer to the network interface
+ *
+ * This function is used to request disconnection from the currently connected
+ * network. This will stop any ongoing scans and initiate deauthentication.
+ */
+void wpas_request_disconnection(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_SME
+       wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+       wpa_s->reassociate = 0;
+       wpa_s->disconnected = 1;
+       wpa_supplicant_cancel_sched_scan(wpa_s);
+       wpa_supplicant_cancel_scan(wpa_s);
+       wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+       eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+}
+
+
 void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
                    struct wpa_used_freq_data *freqs_data,
                    unsigned int len)
@@ -5690,11 +6339,19 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
 #define ECANCELED -1
 #endif
 
+/* Measurement Request element + Location Subject + Maximum Age subelement */
+#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4)
+/* Measurement Request element + Location Civic Request */
+#define MEASURE_REQUEST_CIVIC_LEN (3 + 5)
+
+
 /**
  * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP
  * @wpa_s: Pointer to wpa_supplicant
  * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE
  *       is sent in the request.
+ * @lci: if set, neighbor request will include LCI request
+ * @civic: if set, neighbor request will include civic location request
  * @cb: Callback function to be called once the requested report arrives, or
  *     timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds.
  *     In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's
@@ -5708,7 +6365,8 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
  * Request must contain a callback function.
  */
 int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
-                                      const struct wpa_ssid *ssid,
+                                      const struct wpa_ssid_value *ssid,
+                                      int lci, int civic,
                                       void (*cb)(void *ctx,
                                                  struct wpabuf *neighbor_rep),
                                       void *cb_ctx)
@@ -5749,7 +6407,9 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
        }
 
        /* 3 = action category + action code + dialog token */
-       buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0));
+       buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0) +
+                          (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");
@@ -5769,6 +6429,72 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
                wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len);
        }
 
+       if (lci) {
+               /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
+               wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+               wpabuf_put_u8(buf, MEASURE_REQUEST_LCI_LEN);
+
+               /*
+                * Measurement token; nonzero number that is unique among the
+                * Measurement Request elements in a particular frame.
+                */
+               wpabuf_put_u8(buf, 1); /* Measurement Token */
+
+               /*
+                * Parallel, Enable, Request, and Report bits are 0, Duration is
+                * reserved.
+                */
+               wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
+               wpabuf_put_u8(buf, MEASURE_TYPE_LCI); /* Measurement Type */
+
+               /* IEEE P802.11-REVmc/D5.0 9.4.2.21.10 - LCI request */
+               /* Location Subject */
+               wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
+
+               /* Optional Subelements */
+               /*
+                * IEEE P802.11-REVmc/D5.0 Figure 9-170
+                * The Maximum Age subelement is required, otherwise the AP can
+                * send only data that was determined after receiving the
+                * request. Setting it here to unlimited age.
+                */
+               wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE);
+               wpabuf_put_u8(buf, 2);
+               wpabuf_put_le16(buf, 0xffff);
+       }
+
+       if (civic) {
+               /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
+               wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+               wpabuf_put_u8(buf, MEASURE_REQUEST_CIVIC_LEN);
+
+               /*
+                * Measurement token; nonzero number that is unique among the
+                * Measurement Request elements in a particular frame.
+                */
+               wpabuf_put_u8(buf, 2); /* Measurement Token */
+
+               /*
+                * Parallel, Enable, Request, and Report bits are 0, Duration is
+                * reserved.
+                */
+               wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
+               /* Measurement Type */
+               wpabuf_put_u8(buf, MEASURE_TYPE_LOCATION_CIVIC);
+
+               /* IEEE P802.11-REVmc/D5.0 9.4.2.21.14:
+                * Location Civic request */
+               /* Location Subject */
+               wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
+               wpabuf_put_u8(buf, 0); /* Civic Location Type: IETF RFC 4776 */
+               /* Location Service Interval Units: Seconds */
+               wpabuf_put_u8(buf, 0);
+               /* Location Service Interval: 0 - Only one report is requested
+                */
+               wpabuf_put_le16(buf, 0);
+               /* No optional subelements */
+       }
+
        wpa_s->rrm.next_neighbor_rep_token++;
 
        if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
@@ -5791,6 +6517,147 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
 }
 
 
+static struct wpabuf * wpas_rrm_build_lci_report(struct wpa_supplicant *wpa_s,
+                                                const u8 *request, size_t len,
+                                                struct wpabuf *report)
+{
+       u8 token, type, subject;
+       u16 max_age = 0;
+       struct os_reltime t, diff;
+       unsigned long diff_l;
+       u8 *ptoken;
+       const u8 *subelem;
+
+       if (!wpa_s->lci || len < 3 + 4)
+               return report;
+
+       token = *request++;
+       /* Measurement request mode isn't used */
+       request++;
+       type = *request++;
+       subject = *request++;
+
+       wpa_printf(MSG_DEBUG,
+                  "Measurement request token %u type %u location subject %u",
+                  token, type, subject);
+
+       if (type != MEASURE_TYPE_LCI || subject != LOCATION_SUBJECT_REMOTE) {
+               wpa_printf(MSG_INFO,
+                          "Not building LCI report - bad type or location subject");
+               return report;
+       }
+
+       /* Subelements are formatted exactly like elements */
+       subelem = get_ie(request, len, LCI_REQ_SUBELEM_MAX_AGE);
+       if (subelem && subelem[1] == 2)
+               max_age = WPA_GET_LE16(subelem + 2);
+
+       if (os_get_reltime(&t))
+               return report;
+
+       os_reltime_sub(&t, &wpa_s->lci_time, &diff);
+       /* LCI age is calculated in 10th of a second units. */
+       diff_l = diff.sec * 10 + diff.usec / 100000;
+
+       if (max_age != 0xffff && max_age < diff_l)
+               return report;
+
+       if (wpabuf_resize(&report, 2 + wpabuf_len(wpa_s->lci)))
+               return report;
+
+       wpabuf_put_u8(report, WLAN_EID_MEASURE_REPORT);
+       wpabuf_put_u8(report, wpabuf_len(wpa_s->lci));
+       /* We'll override user's measurement token */
+       ptoken = wpabuf_put(report, 0);
+       wpabuf_put_buf(report, wpa_s->lci);
+       *ptoken = token;
+
+       return report;
+}
+
+
+void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
+                                              const u8 *src,
+                                              const u8 *frame, size_t len)
+{
+       struct wpabuf *buf, *report;
+       u8 token;
+       const u8 *ie, *end;
+
+       if (wpa_s->wpa_state != WPA_COMPLETED) {
+               wpa_printf(MSG_INFO,
+                          "RRM: Ignoring radio measurement request: Not associated");
+               return;
+       }
+
+       if (!wpa_s->rrm.rrm_used) {
+               wpa_printf(MSG_INFO,
+                          "RRM: Ignoring radio measurement request: Not RRM network");
+               return;
+       }
+
+       if (len < 3) {
+               wpa_printf(MSG_INFO,
+                          "RRM: Ignoring too short radio measurement request");
+               return;
+       }
+
+       end = frame + len;
+
+       token = *frame++;
+
+       /* Ignore number of repetitions because it's not used in LCI request */
+       frame += 2;
+
+       report = NULL;
+       while ((ie = get_ie(frame, end - frame, WLAN_EID_MEASURE_REQUEST)) &&
+              ie[1] >= 3) {
+               u8 msmt_type;
+
+               msmt_type = ie[4];
+               wpa_printf(MSG_DEBUG, "RRM request %d", msmt_type);
+
+               switch (msmt_type) {
+               case MEASURE_TYPE_LCI:
+                       report = wpas_rrm_build_lci_report(wpa_s, ie + 2, ie[1],
+                                                          report);
+                       break;
+               default:
+                       wpa_printf(MSG_INFO,
+                                  "RRM: Unsupported radio measurement request %d",
+                                  msmt_type);
+                       break;
+               }
+
+               frame = ie + ie[1] + 2;
+       }
+
+       if (!report)
+               return;
+
+       buf = wpabuf_alloc(3 + wpabuf_len(report));
+       if (!buf) {
+               wpabuf_free(report);
+               return;
+       }
+
+       wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+       wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REPORT);
+       wpabuf_put_u8(buf, token);
+
+       wpabuf_put_buf(buf, report);
+       wpabuf_free(report);
+
+       if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
+                               wpa_s->own_addr, wpa_s->bssid,
+                               wpabuf_head(buf), wpabuf_len(buf), 0)) {
+               wpa_printf(MSG_ERROR,
+                          "RRM: Radio measurement report failed: Sending Action frame failed");
+       }
+       wpabuf_free(buf);
+}
+
+
 void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
                                              const u8 *src,
                                              const u8 *frame, size_t len,
@@ -5868,3 +6735,175 @@ void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
        }
        wpabuf_free(buf);
 }
+
+
+struct wpa_supplicant *
+wpas_vendor_elem(struct wpa_supplicant *wpa_s, enum wpa_vendor_elem_frame frame)
+{
+       switch (frame) {
+#ifdef CONFIG_P2P
+       case VENDOR_ELEM_PROBE_REQ_P2P:
+       case VENDOR_ELEM_PROBE_RESP_P2P:
+       case VENDOR_ELEM_PROBE_RESP_P2P_GO:
+       case VENDOR_ELEM_BEACON_P2P_GO:
+       case VENDOR_ELEM_P2P_PD_REQ:
+       case VENDOR_ELEM_P2P_PD_RESP:
+       case VENDOR_ELEM_P2P_GO_NEG_REQ:
+       case VENDOR_ELEM_P2P_GO_NEG_RESP:
+       case VENDOR_ELEM_P2P_GO_NEG_CONF:
+       case VENDOR_ELEM_P2P_INV_REQ:
+       case VENDOR_ELEM_P2P_INV_RESP:
+       case VENDOR_ELEM_P2P_ASSOC_REQ:
+       case VENDOR_ELEM_P2P_ASSOC_RESP:
+               return wpa_s->p2pdev;
+#endif /* CONFIG_P2P */
+       default:
+               return wpa_s;
+       }
+}
+
+
+void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s)
+{
+       unsigned int i;
+       char buf[30];
+
+       wpa_printf(MSG_DEBUG, "Update vendor elements");
+
+       for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
+               if (wpa_s->vendor_elem[i]) {
+                       int res;
+
+                       res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
+                       if (!os_snprintf_error(sizeof(buf), res)) {
+                               wpa_hexdump_buf(MSG_DEBUG, buf,
+                                               wpa_s->vendor_elem[i]);
+                       }
+               }
+       }
+
+#ifdef CONFIG_P2P
+       if (wpa_s->parent == wpa_s &&
+           wpa_s->global->p2p &&
+           !wpa_s->global->p2p_disabled)
+               p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem);
+#endif /* CONFIG_P2P */
+}
+
+
+int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame,
+                           const u8 *elem, size_t len)
+{
+       u8 *ie, *end;
+
+       ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]);
+       end = ie + wpabuf_len(wpa_s->vendor_elem[frame]);
+
+       for (; ie + 1 < end; ie += 2 + ie[1]) {
+               if (ie + len > end)
+                       break;
+               if (os_memcmp(ie, elem, len) != 0)
+                       continue;
+
+               if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) {
+                       wpabuf_free(wpa_s->vendor_elem[frame]);
+                       wpa_s->vendor_elem[frame] = NULL;
+               } else {
+                       os_memmove(ie, ie + len, end - (ie + len));
+                       wpa_s->vendor_elem[frame]->used -= len;
+               }
+               wpas_vendor_elem_update(wpa_s);
+               return 0;
+       }
+
+       return -1;
+}
+
+
+struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
+                                  u16 num_modes, enum hostapd_hw_mode mode)
+{
+       u16 i;
+
+       for (i = 0; i < num_modes; i++) {
+               if (modes[i].mode == mode)
+                       return &modes[i];
+       }
+
+       return NULL;
+}
+
+
+static struct
+wpa_bss_tmp_disallowed * wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s,
+                                                const u8 *bssid)
+{
+       struct wpa_bss_tmp_disallowed *bss;
+
+       dl_list_for_each(bss, &wpa_s->bss_tmp_disallowed,
+                        struct wpa_bss_tmp_disallowed, list) {
+               if (os_memcmp(bssid, bss->bssid, ETH_ALEN) == 0)
+                       return bss;
+       }
+
+       return NULL;
+}
+
+
+void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                         unsigned int sec)
+{
+       struct wpa_bss_tmp_disallowed *bss;
+       struct os_reltime until;
+
+       os_get_reltime(&until);
+       until.sec += sec;
+
+       bss = wpas_get_disallowed_bss(wpa_s, bssid);
+       if (bss) {
+               bss->disallowed_until = until;
+               return;
+       }
+
+       bss = os_malloc(sizeof(*bss));
+       if (!bss) {
+               wpa_printf(MSG_DEBUG,
+                          "Failed to allocate memory for temp disallow BSS");
+               return;
+       }
+
+       bss->disallowed_until = until;
+       os_memcpy(bss->bssid, bssid, ETH_ALEN);
+       dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list);
+}
+
+
+int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+       struct wpa_bss_tmp_disallowed *bss = NULL, *tmp, *prev;
+       struct os_reltime now, age;
+
+       os_get_reltime(&now);
+
+       dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed,
+                        struct wpa_bss_tmp_disallowed, list) {
+               if (!os_reltime_before(&now, &tmp->disallowed_until)) {
+                       /* This BSS is not disallowed anymore */
+                       dl_list_del(&tmp->list);
+                       os_free(tmp);
+                       continue;
+               }
+               if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) {
+                       bss = tmp;
+                       break;
+               }
+       }
+       if (!bss)
+               return 0;
+
+       os_reltime_sub(&bss->disallowed_until, &now, &age);
+       wpa_printf(MSG_DEBUG,
+                  "BSS " MACSTR " disabled for %ld.%0ld seconds",
+                  MAC2STR(bss->bssid), age.sec, age.usec);
+       return 1;
+}
index 6fe67e4..b3138e3 100644 (file)
@@ -118,6 +118,25 @@ eapol_version=1
 # networks are found, a new IBSS or AP mode network is created.
 ap_scan=1
 
+# Whether to force passive scan for network connection
+#
+# By default, scans will send out Probe Request frames on channels that allow
+# active scanning. This advertise the local station to the world. Normally this
+# is fine, but users may wish to do passive scanning where the radio should only
+# listen quietly for Beacon frames and not send any Probe Request frames. Actual
+# functionality may be driver dependent.
+#
+# This parameter can be used to force only passive scanning to be used
+# for network connection cases. It should be noted that this will slow
+# down scan operations and reduce likelihood of finding the AP. In
+# addition, some use cases will override this due to functional
+# requirements, e.g., for finding an AP that uses hidden SSID
+# (scan_ssid=1) or P2P device discovery.
+#
+# 0:  Do normal scans (allow active scans) (default)
+# 1:  Do passive scans.
+#passive_scan=0
+
 # MPM residency
 # By default, wpa_supplicant implements the mesh peering manager (MPM) for an
 # open mesh. However, if the driver can implement the MPM, you may set this to
@@ -149,10 +168,13 @@ ap_scan=1
 fast_reauth=1
 
 # OpenSSL Engine support
-# These options can be used to load OpenSSL engines.
+# These options can be used to load OpenSSL engines in special or legacy
+# modes.
 # The two engines that are supported currently are shown below:
 # They are both from the opensc project (http://www.opensc.org/)
-# By default no engines are loaded.
+# By default the PKCS#11 engine is loaded if the client_cert or
+# private_key option appear to be a PKCS#11 URI, and these options
+# should not need to be used explicitly.
 # make the opensc engine available
 #opensc_engine_path=/usr/lib/opensc/engine_opensc.so
 # make the pkcs11 engine available
@@ -178,7 +200,7 @@ fast_reauth=1
 #load_dynamic_eap=/usr/lib/wpa_supplicant/eap_md5.so
 
 # Driver interface parameters
-# This field can be used to configure arbitrary driver interace parameters. The
+# This field can be used to configure arbitrary driver interface parameters. The
 # format is specific to the selected driver interface. This field is not used
 # in most cases.
 #driver_param="field=value"
@@ -295,7 +317,9 @@ fast_reauth=1
 # up to the limit of 300 seconds (3, 9, 27 ... 300)
 # For periodic module, parameters would be <fixed interval>
 #autoscan=periodic:30
-# So a delay of 30 seconds will be applied between each scan
+# So a delay of 30 seconds will be applied between each scan.
+# Note: If sched_scan_plans are configured and supported by the driver,
+# autoscan is ignored.
 
 # filter_ssids - SSID-based scan result filtering
 # 0 = do not filter scan results (default)
@@ -339,10 +363,12 @@ fast_reauth=1
 
 # Protected Management Frames default
 # This parameter can be used to set the default behavior for the ieee80211w
-# parameter. By default, PMF is disabled unless enabled with the global pmf=1/2
-# parameter or with the per-network ieee80211w=1/2 parameter. With pmf=1/2, PMF
-# is enabled/required by default, but can be disabled with the per-network
-# ieee80211w parameter.
+# parameter for RSN networks. By default, PMF is disabled unless enabled with
+# the global pmf=1/2 parameter or with the per-network ieee80211w=1/2 parameter.
+# With pmf=1/2, PMF is enabled/required by default, but can be disabled with the
+# per-network ieee80211w parameter. This global default value does not apply
+# for non-RSN networks (key_mgmt=NONE) since PMF is available only when using
+# RSN.
 #pmf=0
 
 # Enabled SAE finite cyclic groups in preference order
@@ -417,6 +443,28 @@ fast_reauth=1
 #     matching network block
 #auto_interworking=0
 
+# GAS Address3 field behavior
+# 0 = P2P specification (Address3 = AP BSSID); default
+# 1 = IEEE 802.11 standard compliant (Address3 = Wildcard BSSID when
+#     sent to not-associated AP; if associated, AP BSSID)
+#gas_address3=0
+
+# Publish fine timing measurement (FTM) responder functionality in
+# the Extended Capabilities element bit 70.
+# Controls whether FTM responder functionality will be published by AP/STA.
+# Note that actual FTM responder operation is managed outside wpa_supplicant.
+# 0 = Do not publish; default
+# 1 = Publish
+#ftm_responder=0
+
+# Publish fine timing measurement (FTM) initiator functionality in
+# the Extended Capabilities element bit 71.
+# Controls whether FTM initiator functionality will be published by AP/STA.
+# Note that actual FTM initiator operation is managed outside wpa_supplicant.
+# 0 = Do not publish; default
+# 1 = Publish
+#ftm_initiator=0
+
 # credential block
 #
 # Each credential used for automatic network selection is configured as a set
@@ -451,6 +499,10 @@ fast_reauth=1
 #      (EAP-TLS). Full path to the file should be used since working
 #      directory may change when wpa_supplicant is run in the background.
 #
+#      Certificates from PKCS#11 tokens can be referenced by a PKCS#11 URI.
+#
+#      For example: private_key="pkcs11:manufacturer=piv_II;id=%01"
+#
 #      Alternatively, a named configuration blob can be used by setting
 #      this to blob://blob_name.
 #
@@ -461,6 +513,9 @@ fast_reauth=1
 #      used since working directory may change when wpa_supplicant is run
 #      in the background.
 #
+#      Keys in PKCS#11 tokens can be referenced by a PKCS#11 URI.
+#      For example: private_key="pkcs11:manufacturer=piv_II;id=%01"
+#
 #      Windows certificate store can be used by leaving client_cert out and
 #      configuring private_key in one of the following formats:
 #
@@ -565,6 +620,8 @@ fast_reauth=1
 #      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
+#      3 = require valid OCSP stapling response for all not-trusted
+#          certificates in the server certificate chain
 #
 # sim_num: Identifier for which SIM to use in multi-SIM devices
 #
@@ -597,6 +654,41 @@ fast_reauth=1
 # Hotspot 2.0
 # hs20=1
 
+# Scheduled scan plans
+#
+# A space delimited list of scan plans. Each scan plan specifies the scan
+# interval and number of iterations, delimited by a colon. The last scan plan
+# will run infinitely and thus must specify only the interval and not the number
+# of iterations.
+#
+# The driver advertises the maximum number of scan plans supported. If more scan
+# plans than supported are configured, only the first ones are set (up to the
+# maximum supported). The last scan plan that specifies only the interval is
+# always set as the last plan.
+#
+# If the scan interval or the number of iterations for a scan plan exceeds the
+# maximum supported, it will be set to the maximum supported value.
+#
+# Format:
+# sched_scan_plans=<interval:iterations> <interval:iterations> ... <interval>
+#
+# Example:
+# sched_scan_plans=10:100 20:200 30
+
+# Multi Band Operation (MBO) non-preferred channels
+# A space delimited list of non-preferred channels where each channel is a colon
+# delimited list of values.
+# Format:
+# non_pref_chan=<oper_class>:<chan>:<preference>:<reason>
+# Example:
+# non_pref_chan="81:5:10:2 81:1:0:2 81:9:0:2"
+
+# MBO Cellular Data Capabilities
+# 1 = Cellular data connection available
+# 2 = Cellular data connection not available
+# 3 = Not cellular capable (default)
+#mbo_cell_capa=3
+
 # network block
 #
 # Each network (usually AP's sharing the same SSID) is configured as a separate
@@ -658,6 +750,17 @@ fast_reauth=1
 # an IBSS network with the configured SSID is already present, the frequency of
 # the network will be used instead of this configured value.
 #
+# pbss: Whether to use PBSS. Relevant to IEEE 802.11ad networks only.
+# 0 = do not use PBSS
+# 1 = use PBSS
+# 2 = don't care (not allowed in AP mode)
+# Used together with mode configuration. When mode is AP, it means to start a
+# PCP instead of a regular AP. When mode is infrastructure it means connect
+# to a PCP instead of AP. In this mode you can also specify 2 (don't care)
+# which means connect to either PCP or AP.
+# P2P_GO and P2P_GROUP_FORMATION modes must use PBSS in IEEE 802.11ad network.
+# For more details, see IEEE Std 802.11ad-2012.
+#
 # scan_freq: List of frequencies to scan
 # Space-separated list of frequencies in MHz to scan when searching for this
 # BSS. If the subset of channels used by the network is known, this option can
@@ -706,8 +809,19 @@ fast_reauth=1
 # IEEE8021X = IEEE 802.1X using EAP authentication and (optionally) dynamically
 #      generated WEP keys
 # NONE = WPA is not used; plaintext or static WEP could be used
+# WPA-NONE = WPA-None for IBSS (deprecated; use proto=RSN key_mgmt=WPA-PSK
+#      instead)
+# FT-PSK = Fast BSS Transition (IEEE 802.11r) with pre-shared key
+# FT-EAP = Fast BSS Transition (IEEE 802.11r) with EAP authentication
 # WPA-PSK-SHA256 = Like WPA-PSK but using stronger SHA256-based algorithms
 # WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms
+# SAE = Simultaneous authentication of equals; pre-shared key/password -based
+#      authentication with stronger security than WPA-PSK especially when using
+#      not that strong password
+# FT-SAE = SAE with FT
+# WPA-EAP-SUITE-B = Suite B 128-bit level
+# WPA-EAP-SUITE-B-192 = Suite B 192-bit level
+# OSEN = Hotspot 2.0 Rel 2 online signup connection
 # If not set, this defaults to: WPA-PSK WPA-EAP
 #
 # ieee80211w: whether management frame protection is enabled
@@ -798,9 +912,13 @@ 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.
 #
+# 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.
+#
 # Following fields are only used with internal EAP implementation.
 # eap: space-separated list of accepted EAP methods
-#      MD5 = EAP-MD5 (unsecure and does not generate keying material ->
+#      MD5 = EAP-MD5 (insecure and does not generate keying material ->
 #                      cannot be used with WPA; to be used as a Phase 2 method
 #                      with EAP-PEAP or EAP-TTLS)
 #       MSCHAPV2 = EAP-MSCHAPv2 (cannot be used separately with WPA; to be used
@@ -891,23 +1009,23 @@ fast_reauth=1
 #      automatically converted into DH params.
 # subject_match: Substring to be matched against the subject of the
 #      authentication server certificate. If this string is set, the server
-#      sertificate is only accepted if it contains this string in the subject.
+#      certificate is only accepted if it contains this string in the subject.
 #      The subject string is in following format:
 #      /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@example.com
-#      Note: Since this is a substring match, this cannot be used securily to
+#      Note: Since this is a substring match, this cannot be used securely to
 #      do a suffix match against a possible domain name in the CN entry. For
 #      such a use case, domain_suffix_match or domain_match should be used
 #      instead.
 # altsubject_match: Semicolon separated string of entries to be matched against
 #      the alternative subject name of the authentication server certificate.
-#      If this string is set, the server sertificate is only accepted if it
+#      If this string is set, the server certificate is only accepted if it
 #      contains one of the entries in an alternative subject name extension.
 #      altSubjectName string is in following format: TYPE:VALUE
 #      Example: EMAIL:server@example.com
 #      Example: DNS:server.example.com;DNS:server2.example.com
 #      Following types are supported: EMAIL, DNS, URI
 # domain_suffix_match: Constraint for server domain name. If set, this FQDN is
-#      used as a suffix match requirement for the AAAserver certificate in
+#      used as a suffix match requirement for the AAA server certificate in
 #      SubjectAltName dNSName element(s). If a matching dNSName is found, this
 #      constraint is met. If no dNSName values are present, this constraint is
 #      matched against SubjectName CN using same suffix match comparison.
@@ -995,6 +1113,12 @@ fast_reauth=1
 #      that have issues interoperating with updated TLS version)
 # tls_disable_tlsv1_2=1 - disable use of TLSv1.2 (a workaround for AAA servers
 #      that have issues interoperating with updated TLS version)
+# tls_ext_cert_check=0 - No external server certificate validation (default)
+# tls_ext_cert_check=1 - External server certificate validation enabled; this
+#      requires an external program doing validation of server certificate
+#      chain when receiving CTRL-RSP-EXT_CERT_CHECK event from the control
+#      interface and report the result of the validation with
+#      CTRL-RSP_EXT_CERT_CHECK.
 #
 # Following certificate/private key fields are used in inner Phase2
 # authentication when using EAP-TTLS or EAP-PEAP.
@@ -1026,6 +1150,8 @@ fast_reauth=1
 #      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
+#      3 = require valid OCSP stapling response for all not-trusted
+#          certificates in the server certificate chain
 #
 # openssl_ciphers: OpenSSL specific cipher configuration
 #      This can be used to override the global openssl_ciphers configuration
@@ -1059,6 +1185,9 @@ fast_reauth=1
 # number of authentication servers. Strict EAP conformance mode can be
 # configured by disabling workarounds with eap_workaround=0.
 
+# update_identifier: PPS MO ID
+#      (Hotspot 2.0 PerProviderSubscription/UpdateIdentifier)
+
 # Station inactivity limit
 #
 # If a station does not send anything in ap_max_inactivity seconds, an
@@ -1082,6 +1211,11 @@ fast_reauth=1
 # Beacon interval (default: 100 TU)
 #beacon_int=100
 
+# WPS in AP mode
+# 0 = WPS enabled and configured (default)
+# 1 = WPS disabled
+#wps_disabled=0
+
 # MAC address policy
 # 0 = use permanent MAC address
 # 1 = use random MAC address for each ESS connection
@@ -1144,13 +1278,13 @@ fast_reauth=1
 ##### Fast Session Transfer (FST) support #####################################
 #
 # The options in this section are only available when the build configuration
-# option CONFIG_FST is set while compiling hostapd. They allow this interface
-# to be a part of FST setup.
+# option CONFIG_FST is set while compiling wpa_supplicant. They allow this
+# interface to be a part of FST setup.
 #
 # FST is the transfer of a session from a channel to another channel, in the
 # same or different frequency bands.
 #
-# For detals, see IEEE Std 802.11ad-2012.
+# For details, see IEEE Std 802.11ad-2012.
 
 # Identifier of an FST Group  the interface belongs to.
 #fst_group_id=bond0
@@ -1483,22 +1617,10 @@ network={
        group=CCMP TKIP
        identity="user@example.com"
        ca_cert="/etc/cert/ca.pem"
-       client_cert="/etc/cert/user.pem"
-
-       engine=1
-
-       # The engine configured here must be available. Look at
-       # OpenSSL engine support in the global section.
-       # The key available through the engine must be the private key
-       # matching the client certificate configured above.
-
-       # use the opensc engine
-       #engine_id="opensc"
-       #key_id="45"
 
-       # use the pkcs11 engine
-       engine_id="pkcs11"
-       key_id="id_45"
+       # Certificate and/or key identified by PKCS#11 URI (RFC7512)
+       client_cert="pkcs11:manufacturer=piv_II;id=%01"
+       private_key="pkcs11:manufacturer=piv_II;id=%01"
 
        # Optional PIN configuration; this can be left out and PIN will be
        # asked through the control interface
index 58df48c..ef9273d 100644 (file)
@@ -44,6 +44,7 @@ struct wpa_driver_associate_params;
 struct ctrl_iface_priv;
 struct ctrl_iface_global_priv;
 struct wpas_dbus_priv;
+struct wpas_binder_priv;
 
 /**
  * struct wpa_interface - Parameters for wpa_supplicant_add_iface()
@@ -228,6 +229,17 @@ struct wpa_params {
        char *conf_p2p_dev;
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_MATCH_IFACE
+       /**
+        * match_ifaces - Interface descriptions to match
+        */
+       struct wpa_interface *match_ifaces;
+
+       /**
+        * match_iface_count - Number of defined matching interfaces
+        */
+       int match_iface_count;
+#endif /* CONFIG_MATCH_IFACE */
 };
 
 struct p2p_srv_bonjour {
@@ -253,6 +265,7 @@ struct wpa_global {
        struct wpa_params params;
        struct ctrl_iface_global_priv *ctrl_iface;
        struct wpas_dbus_priv *dbus;
+       struct wpas_binder_priv *binder;
        void **drv_priv;
        size_t drv_count;
        struct os_time suspend_time;
@@ -278,6 +291,7 @@ struct wpa_global {
        unsigned int p2p_24ghz_social_channels:1;
        unsigned int pending_p2ps_group:1;
        unsigned int pending_group_iface_for_p2ps:1;
+       unsigned int pending_p2ps_group_freq;
 
 #ifdef CONFIG_WIFI_DISPLAY
        int wifi_display;
@@ -300,10 +314,14 @@ struct wpa_radio {
        char name[16]; /* from driver_ops get_radio_name() or empty if not
                        * available */
        unsigned int external_scan_running:1;
+       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 */
 };
 
+#define MAX_ACTIVE_WORKS 2
+
+
 /**
  * struct wpa_radio_work - Radio work item
  */
@@ -316,6 +334,7 @@ struct wpa_radio_work {
        void *ctx;
        unsigned int started:1;
        struct os_reltime time;
+       unsigned int bands;
 };
 
 int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
@@ -347,6 +366,9 @@ struct wpa_external_work {
        unsigned int timeout;
 };
 
+enum wpa_radio_work_band wpas_freq_to_band(int freq);
+unsigned int wpas_get_bands(struct wpa_supplicant *wpa_s, const int *freqs);
+
 /**
  * offchannel_send_action_result - Result of offchannel send Action frame
  */
@@ -371,11 +393,6 @@ struct wps_ap_info {
        u8 uuid[WPS_UUID_LEN];
 };
 
-struct wpa_ssid_value {
-       u8 ssid[SSID_MAX_LEN];
-       size_t ssid_len;
-};
-
 #define WPA_FREQ_USED_BY_INFRA_STATION BIT(0)
 #define WPA_FREQ_USED_BY_P2P_CLIENT BIT(1)
 
@@ -414,6 +431,21 @@ enum wpa_supplicant_test_failure {
        WPAS_TEST_FAILURE_SCAN_TRIGGER,
 };
 
+struct icon_entry {
+       struct dl_list list;
+       u8 bssid[ETH_ALEN];
+       u8 dialog_token;
+       char *file_name;
+       u8 *image;
+       size_t image_len;
+};
+
+struct wpa_bss_tmp_disallowed {
+       struct dl_list list;
+       u8 bssid[ETH_ALEN];
+       struct os_reltime disallowed_until;
+};
+
 /**
  * struct wpa_supplicant - Internal data for wpa_supplicant interface
  *
@@ -427,12 +459,16 @@ struct wpa_supplicant {
        struct wpa_radio *radio; /* shared radio context */
        struct dl_list radio_list; /* list head: struct wpa_radio::ifaces */
        struct wpa_supplicant *parent;
+       struct wpa_supplicant *p2pdev;
        struct wpa_supplicant *next;
        struct l2_packet_data *l2;
        struct l2_packet_data *l2_br;
        unsigned char own_addr[ETH_ALEN];
        unsigned char perm_addr[ETH_ALEN];
        char ifname[100];
+#ifdef CONFIG_MATCH_IFACE
+       int matched;
+#endif /* CONFIG_MATCH_IFACE */
 #ifdef CONFIG_CTRL_IFACE_DBUS
        char *dbus_path;
 #endif /* CONFIG_CTRL_IFACE_DBUS */
@@ -443,6 +479,9 @@ struct wpa_supplicant {
        char *preq_notify_peer;
 #endif /* CONFIG_AP */
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
+#ifdef CONFIG_CTRL_IFACE_BINDER
+       const void *binder_object_key;
+#endif /* CONFIG_CTRL_IFACE_BINDER */
        char bridge_ifname[16];
 
        char *confname;
@@ -455,7 +494,8 @@ struct wpa_supplicant {
        u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
                                     * field contains the target BSSID. */
        int reassociate; /* reassociation requested */
-       int reassoc_same_bss; /* reassociating to the same bss */
+       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
                           * before this has been cleared */
        struct wpa_ssid *current_ssid;
@@ -500,9 +540,10 @@ struct wpa_supplicant {
 
        struct wpa_ssid *prev_sched_ssid; /* last SSID used in sched scan */
        int sched_scan_timeout;
-       int sched_scan_interval;
        int first_sched_scan;
        int sched_scan_timed_out;
+       struct sched_scan_plan *sched_scan_plans;
+       size_t sched_scan_plans_num;
 
        void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
                                 struct wpa_scan_results *scan_res);
@@ -533,6 +574,7 @@ struct wpa_supplicant {
        struct wpa_radio_work *scan_work;
        int scanning;
        int sched_scanning;
+       unsigned int sched_scan_stop_req:1;
        int new_connection;
 
        int eapol_received; /* number of EAPOL packets received after the
@@ -613,6 +655,7 @@ struct wpa_supplicant {
 #define MAX_SCAN_ID 16
        int scan_id[MAX_SCAN_ID];
        unsigned int scan_id_count;
+       u8 next_scan_bssid[ETH_ALEN];
 
        struct wpa_ssid_value *ssids_from_scan_req;
        unsigned int num_ssids_from_scan_req;
@@ -634,6 +677,9 @@ struct wpa_supplicant {
 
        int max_scan_ssids;
        int max_sched_scan_ssids;
+       unsigned int max_sched_scan_plans;
+       unsigned int max_sched_scan_plan_interval;
+       unsigned int max_sched_scan_plan_iterations;
        int sched_scan_supported;
        unsigned int max_match_sets;
        unsigned int max_remain_on_chan;
@@ -658,6 +704,7 @@ struct wpa_supplicant {
        unsigned int reattach:1; /* reassociation to the same BSS requested */
        unsigned int mac_addr_changed:1;
        unsigned int added_vif:1;
+       unsigned int wnmsleep_used:1;
 
        struct os_reltime last_mac_addr_change;
        int last_mac_addr_style;
@@ -722,7 +769,7 @@ struct wpa_supplicant {
        int mesh_if_idx;
        unsigned int mesh_if_created:1;
        unsigned int mesh_ht_enabled:1;
-       int mesh_auth_block_duration; /* sec */
+       unsigned int mesh_vht_enabled:1;
 #endif /* CONFIG_MESH */
 
        unsigned int off_channel_freq;
@@ -844,6 +891,10 @@ struct wpa_supplicant {
        int *p2p_group_common_freqs;
        unsigned int p2p_group_common_freqs_num;
        u8 p2ps_join_addr[ETH_ALEN];
+
+       unsigned int p2p_go_max_oper_chwidth;
+       unsigned int p2p_go_vht_center_freq2;
+       int p2p_lo_started;
 #endif /* CONFIG_P2P */
 
        struct wpa_ssid *bgscan_ssid;
@@ -885,6 +936,7 @@ struct wpa_supplicant {
        unsigned int fetch_osu_icon_in_progress:1;
        struct wpa_bss *interworking_gas_bss;
        unsigned int osu_icon_id;
+       struct dl_list icon_head; /* struct icon_entry */
        struct osu_provider *osu_prov;
        size_t osu_prov_count;
        struct os_reltime osu_icon_fetch_start;
@@ -914,6 +966,9 @@ struct wpa_supplicant {
        /* WLAN_REASON_* reason codes. Negative if locally generated. */
        int disconnect_reason;
 
+       /* WLAN_STATUS_* status codes from (Re)Association Response frame. */
+       u16 assoc_status_code;
+
        struct ext_password_data *ext_pw;
 
        struct wpabuf *last_gas_resp, *prev_gas_resp;
@@ -969,6 +1024,10 @@ struct wpa_supplicant {
        struct l2_packet_data *l2_test;
        unsigned int extra_roc_dur;
        enum wpa_supplicant_test_failure test_failure;
+       unsigned int reject_btm_req_reason;
+       unsigned int p2p_go_csa_on_inv:1;
+       unsigned int ignore_auth_resp:1;
+       unsigned int ignore_assoc_disallow:1;
 #endif /* CONFIG_TESTING_OPTIONS */
 
        struct wmm_ac_assoc_data *wmm_ac_assoc_info;
@@ -985,6 +1044,31 @@ struct wpa_supplicant {
        const struct wpabuf *fst_ies;
        struct wpabuf *received_mb_ies;
 #endif /* CONFIG_FST */
+
+#ifdef CONFIG_MBO
+       /* Multiband operation non-preferred channel */
+       struct wpa_mbo_non_pref_channel {
+               enum mbo_non_pref_chan_reason reason;
+               u8 oper_class;
+               u8 chan;
+               u8 preference;
+       } *non_pref_chan;
+       size_t non_pref_chan_num;
+       u8 mbo_wnm_token;
+#endif /* CONFIG_MBO */
+
+       /*
+        * This should be under CONFIG_MBO, but it is left out to allow using
+        * the bss_temp_disallowed list for other purposes as well.
+        */
+       struct dl_list bss_tmp_disallowed;
+
+       /*
+        * Content of a measurement report element with type 8 (LCI),
+        * own location.
+        */
+       struct wpabuf *lci;
+       struct os_reltime lci_time;
 };
 
 
@@ -1026,6 +1110,8 @@ void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                                   int reason_code);
 
+struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id);
 void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
                                   struct wpa_ssid *ssid);
 void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
@@ -1050,6 +1136,8 @@ void free_hw_features(struct wpa_supplicant *wpa_s);
 
 void wpa_show_license(void);
 
+struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
+                                                 const char *ifname);
 struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
                                                 struct wpa_interface *iface,
                                                 struct wpa_supplicant *parent);
@@ -1079,6 +1167,7 @@ int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid);
 int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
                    size_t ssid_len);
 void wpas_request_connection(struct wpa_supplicant *wpa_s);
+void wpas_request_disconnection(struct wpa_supplicant *wpa_s);
 int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen);
 int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style);
 int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s);
@@ -1088,15 +1177,37 @@ 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);
 int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
-                                      const struct wpa_ssid *ssid,
+                                      const struct wpa_ssid_value *ssid,
+                                      int lci, int civic,
                                       void (*cb)(void *ctx,
                                                  struct wpabuf *neighbor_rep),
                                       void *cb_ctx);
+void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
+                                              const u8 *src,
+                                              const u8 *frame, size_t len);
 void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
                                              const u8 *src,
                                              const u8 *frame, size_t len,
                                              int rssi);
 
+
+/* MBO functions */
+int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len);
+const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr);
+int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
+                                 const char *non_pref_chan);
+void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie);
+int wpas_mbo_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
+                             size_t len);
+void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *ie,
+                          size_t len);
+size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos,
+                                   size_t len,
+                                   enum mbo_transition_reject_reason reason);
+void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa);
+struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s,
+                                  struct wpa_bss *bss);
+
 /**
  * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
  * @wpa_s: Pointer to wpa_supplicant data
@@ -1158,6 +1269,12 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
 
 void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx);
 
+void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s);
+struct wpa_supplicant * wpas_vendor_elem(struct wpa_supplicant *wpa_s,
+                                        enum wpa_vendor_elem_frame frame);
+int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame,
+                           const u8 *elem, size_t len);
+
 #ifdef CONFIG_FST
 
 struct fst_wpa_obj;
@@ -1167,4 +1284,18 @@ void fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant *wpa_s,
 
 #endif /* CONFIG_FST */
 
+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);
+
+void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                         unsigned int sec);
+int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid);
+
+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);
+
 #endif /* WPA_SUPPLICANT_I_H */
index 29c22ba..f84c8b9 100644 (file)
@@ -739,6 +739,8 @@ enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field)
                return WPA_CTRL_REQ_SIM;
        else if (os_strcmp(field, "PSK_PASSPHRASE") == 0)
                return WPA_CTRL_REQ_PSK_PASSPHRASE;
+       else if (os_strcmp(field, "EXT_CERT_CHECK") == 0)
+               return WPA_CTRL_REQ_EXT_CERT_CHECK;
        return WPA_CTRL_REQ_UNKNOWN;
 }
 
@@ -782,6 +784,10 @@ const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
                *txt = "PSK or passphrase";
                ret = "PSK_PASSPHRASE";
                break;
+       case WPA_CTRL_REQ_EXT_CERT_CHECK:
+               *txt = "External server certificate validation";
+               ret = "EXT_CERT_CHECK";
+               break;
        default:
                break;
        }
@@ -837,6 +843,8 @@ static void wpa_supplicant_eap_param_needed(void *ctx,
        if (ssid == NULL)
                return;
 
+       if (field == WPA_CTRL_REQ_EXT_CERT_CHECK)
+               ssid->eap.pending_ext_cert_check = PENDING_CHECK;
        wpas_notify_network_request(wpa_s, ssid, field, default_txt);
 
        field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt,
@@ -1013,7 +1021,6 @@ static void wpa_supplicant_set_rekey_offload(void *ctx,
 
        wpa_drv_set_rekey_info(wpa_s, kek, kek_len, kck, kck_len, replay_ctr);
 }
-#endif /* CONFIG_NO_WPA */
 
 
 static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk,
@@ -1028,6 +1035,7 @@ static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk,
        else
                return 0;
 }
+#endif /* CONFIG_NO_WPA */
 
 
 int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
@@ -1124,6 +1132,7 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
                        }
                }
 #endif /* CONFIG_P2P */
+               conf.wpa_rsc_relaxation = wpa_s->conf->wpa_rsc_relaxation;
        }
        wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
 }
index 354decf..d6ec8c5 100644 (file)
@@ -50,10 +50,9 @@ static int wpas_set_replay_protect(void *wpa_s, Boolean enabled, u32 window)
 }
 
 
-static int wpas_set_current_cipher_suite(void *wpa_s, const u8 *cs,
-                                        size_t cs_len)
+static int wpas_set_current_cipher_suite(void *wpa_s, u64 cs)
 {
-       return wpa_drv_set_current_cipher_suite(wpa_s, cs, cs_len);
+       return wpa_drv_set_current_cipher_suite(wpa_s, cs);
 }
 
 
@@ -109,7 +108,8 @@ static int wpas_create_receive_sc(void *wpa_s, u32 channel,
                                  enum validate_frames vf,
                                  enum confidentiality_offset co)
 {
-       return wpa_drv_create_receive_sc(wpa_s, channel, sci->addr, sci->port,
+       return wpa_drv_create_receive_sc(wpa_s, channel, sci->addr,
+                                        be_to_host16(sci->port),
                                         conf_offset_val(co), vf);
 }
 
@@ -150,7 +150,8 @@ wpas_create_transmit_sc(void *wpa_s, u32 channel,
                        const struct ieee802_1x_mka_sci *sci,
                        enum confidentiality_offset co)
 {
-       return wpa_drv_create_transmit_sc(wpa_s, channel, sci->addr, sci->port,
+       return wpa_drv_create_transmit_sc(wpa_s, channel, sci->addr,
+                                         be_to_host16(sci->port),
                                          conf_offset_val(co));
 }
 
index 6af1678..4e37591 100644 (file)
@@ -9,6 +9,7 @@
 #include "utils/includes.h"
 
 #include "utils/common.h"
+#include "utils/module_tests.h"
 #include "wpa_supplicant_i.h"
 #include "blacklist.h"
 
@@ -79,30 +80,18 @@ int wpas_module_tests(void)
                ret = -1;
 
 #ifdef CONFIG_WPS
-       {
-               int wps_module_tests(void);
-               if (wps_module_tests() < 0)
-                       ret = -1;
-       }
+       if (wps_module_tests() < 0)
+               ret = -1;
 #endif /* CONFIG_WPS */
 
-       {
-               int utils_module_tests(void);
-               if (utils_module_tests() < 0)
-                       ret = -1;
-       }
-
-       {
-               int common_module_tests(void);
-               if (common_module_tests() < 0)
-                       ret = -1;
-       }
-
-       {
-               int crypto_module_tests(void);
-               if (crypto_module_tests() < 0)
-                       ret = -1;
-       }
+       if (utils_module_tests() < 0)
+               ret = -1;
+
+       if (common_module_tests() < 0)
+               ret = -1;
+
+       if (crypto_module_tests() < 0)
+               ret = -1;
 
        return ret;
 }
index 60f761c..74a420c 100644 (file)
@@ -583,8 +583,8 @@ static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
                m2d->dev_password_id, m2d->config_error);
        wpas_notify_wps_event_m2d(wpa_s, m2d);
 #ifdef CONFIG_P2P
-       if (wpa_s->parent && wpa_s->parent != wpa_s) {
-               wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_M2D
+       if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s) {
+               wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_M2D
                        "dev_password_id=%d config_error=%d",
                        m2d->dev_password_id, m2d->config_error);
        }
@@ -617,8 +617,8 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
                        WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
                        fail->msg, fail->config_error, fail->error_indication,
                        wps_ei_str(fail->error_indication));
-               if (wpa_s->parent && wpa_s->parent != wpa_s)
-                       wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+               if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s)
+                       wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL
                                "msg=%d config_error=%d reason=%d (%s)",
                                fail->msg, fail->config_error,
                                fail->error_indication,
@@ -627,8 +627,8 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
                wpa_msg(wpa_s, MSG_INFO,
                        WPS_EVENT_FAIL "msg=%d config_error=%d",
                        fail->msg, fail->config_error);
-               if (wpa_s->parent && wpa_s->parent != wpa_s)
-                       wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+               if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s)
+                       wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL
                                "msg=%d config_error=%d",
                                fail->msg, fail->config_error);
        }
@@ -683,6 +683,13 @@ static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx)
 }
 
 
+int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s)
+{
+       return eloop_is_timeout_registered(wpas_wps_reenable_networks_cb,
+                                          wpa_s, NULL);
+}
+
+
 static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
 {
        wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
@@ -1135,6 +1142,13 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
                return -1;
        ssid->temporary = 1;
        ssid->p2p_group = p2p_group;
+       /*
+        * When starting a regular WPS process (not P2P group formation)
+        * the registrar/final station can be either AP or PCP
+        * so use a "don't care" value for the pbss flag.
+        */
+       if (!p2p_group)
+               ssid->pbss = 2;
 #ifdef CONFIG_P2P
        if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
                ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
@@ -1142,6 +1156,10 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
                        ssid->ssid_len = wpa_s->go_params->ssid_len;
                        os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
                                  ssid->ssid_len);
+                       if (wpa_s->go_params->freq > 56160) {
+                               /* P2P in 60 GHz uses PBSS */
+                               ssid->pbss = 1;
+                       }
                        wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
                                          "SSID", ssid->ssid, ssid->ssid_len);
                }
@@ -1186,6 +1204,13 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
        }
        ssid->temporary = 1;
        ssid->p2p_group = p2p_group;
+       /*
+        * When starting a regular WPS process (not P2P group formation)
+        * the registrar/final station can be either AP or PCP
+        * so use a "don't care" value for the pbss flag.
+        */
+       if (!p2p_group)
+               ssid->pbss = 2;
        if (ssid_val) {
                ssid->ssid = os_malloc(ssid_len);
                if (ssid->ssid) {
@@ -1209,6 +1234,10 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
                        ssid->ssid_len = wpa_s->go_params->ssid_len;
                        os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
                                  ssid->ssid_len);
+                       if (wpa_s->go_params->freq > 56160) {
+                               /* P2P in 60 GHz uses PBSS */
+                               ssid->pbss = 1;
+                       }
                        wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
                                          "SSID", ssid->ssid, ssid->ssid_len);
                }
@@ -1221,7 +1250,10 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
                os_snprintf(val, sizeof(val), "\"dev_pw_id=%u%s\"",
                            dev_pw_id, hash);
        } else {
-               rpin = wps_generate_pin();
+               if (wps_generate_pin(&rpin) < 0) {
+                       wpa_printf(MSG_DEBUG, "WPS: Could not generate PIN");
+                       return -1;
+               }
                os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u%s\"",
                            rpin, dev_pw_id, hash);
        }
index 3c25ca8..c8fe47e 100644 (file)
@@ -85,6 +85,7 @@ int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
 void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
                             struct wpa_scan_results *scan_res);
 void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s);
 
 #else /* CONFIG_WPS */
 
@@ -147,6 +148,12 @@ static inline void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s,
 {
 }
 
+static inline int
+wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s)
+{
+       return 0;
+}
+
 #endif /* CONFIG_WPS */
 
 #endif /* WPS_SUPPLICANT_H */
index 493af7a..9141a8d 100755 (executable)
@@ -7,13 +7,23 @@
 # See README for more details.
 
 import os
+import sys
 import time
 import wpaspy
 
 wpas_ctrl = '/var/run/wpa_supplicant'
 
-def wpas_connect():
+def wpas_connect(host=None, port=9877):
     ifaces = []
+
+    if host != None:
+        try:
+            wpas = wpaspy.Ctrl(host, port)
+            return wpas
+        except:
+            print "Could not connect to host: ", host
+            return None
+
     if os.path.isdir(wpas_ctrl):
         try:
             ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
@@ -34,15 +44,15 @@ def wpas_connect():
     return None
 
 
-def main():
+def main(host=None, port=9877):
     print "Testing wpa_supplicant control interface connection"
-    wpas = wpas_connect()
+    wpas = wpas_connect(host, port)
     if wpas is None:
         return
     print "Connected to wpa_supplicant"
     print wpas.request('PING')
 
-    mon = wpas_connect()
+    mon = wpas_connect(host, port)
     if mon is None:
         print "Could not open event monitor connection"
         return
@@ -66,4 +76,7 @@ def main():
 
 
 if __name__ == "__main__":
-    main()
+    if len(sys.argv) > 2:
+        main(host=sys.argv[1], port=int(sys.argv[2]))
+    else:
+        main()
index 2f57d74..c2aace0 100644 (file)
@@ -7,27 +7,60 @@
 # See README for more details.
 
 import os
+import stat
 import socket
 import select
 
 counter = 0
 
 class Ctrl:
-    def __init__(self, path):
+    def __init__(self, path, port=9877):
         global counter
         self.started = False
         self.attached = False
-        self.s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
-        self.dest = path
-        self.local = "/tmp/wpa_ctrl_" + str(os.getpid()) + '-' + str(counter)
-        counter += 1
-        self.s.bind(self.local)
+        self.path = path
+        self.port = port
+
         try:
-            self.s.connect(self.dest)
-        except Exception, e:
-            self.s.close()
-            os.unlink(self.local)
-            raise
+            mode = os.stat(path).st_mode
+            if stat.S_ISSOCK(mode):
+                self.udp = False
+            else:
+                self.udp = True
+        except:
+            self.udp = True
+
+        if not self.udp:
+            self.s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
+            self.dest = path
+            self.local = "/tmp/wpa_ctrl_" + str(os.getpid()) + '-' + str(counter)
+            counter += 1
+            self.s.bind(self.local)
+            try:
+                self.s.connect(self.dest)
+            except Exception, e:
+                self.s.close()
+                os.unlink(self.local)
+                raise
+        else:
+            try:
+                self.s = None
+                ai_list = socket.getaddrinfo(path, port, socket.AF_INET,
+                                             socket.SOCK_DGRAM)
+                for af, socktype, proto, cn, sockaddr in ai_list:
+                    self.sockaddr = sockaddr
+                    break
+                self.s = socket.socket(af, socktype)
+                self.s.settimeout(5)
+                self.s.sendto("GET_COOKIE", sockaddr)
+                reply, server = self.s.recvfrom(4096)
+                self.cookie = reply
+                self.port = port
+            except:
+                print "connect exception ", path, str(port)
+                if self.s != None:
+                    self.s.close()
+                raise
         self.started = True
 
     def __del__(self):
@@ -43,11 +76,15 @@ class Ctrl:
                 pass
         if self.started:
             self.s.close()
-            os.unlink(self.local)
+            if not self.udp:
+                os.unlink(self.local)
             self.started = False
 
     def request(self, cmd, timeout=10):
-        self.s.send(cmd)
+        if self.udp:
+            self.s.sendto(self.cookie + cmd, self.sockaddr)
+        else:
+            self.s.send(cmd)
         [r, w, e] = select.select([self.s], [], [], timeout)
         if r:
             return self.s.recv(4096)
@@ -73,6 +110,16 @@ class Ctrl:
             return None
         raise Exception("DETACH failed")
 
+    def terminate(self):
+        if self.attached:
+            try:
+                self.detach()
+            except Exception, e:
+                # Need to ignore this to allow the socket to be closed
+                self.attached = False
+        self.request("TERMINATE")
+        self.close()
+
     def pending(self, timeout=0):
         [r, w, e] = select.select([self.s], [], [], timeout)
         if r:
diff --git a/tests/hwsim/auth_serv/ca-key.pem b/tests/hwsim/auth_serv/ca-key.pem
new file mode 100644 (file)
index 0000000..cddf6b1
--- /dev/null
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQC+HobkeQPB0ZTV1LOxKJB2+7imzW0c0Uj0CJpn//mmVLEZKd8p
+G83xb2YB59t5zsA5KiUTJpQMLHtaLIEPlO5R0HXmRtsXRqcViw5XD7BUdmMSyoYY
+vBrDFsBwCdZrQzm4mClGrMtqrTiIOwfcgc069h32L+8d166KttHnsxUCuQIDAQAB
+AoGAEPKDr8Yh0ZsvG0iUpAwrpI+XzDavrUvypt5FdVPaGzudddLHs9BosUbu3uie
+JeOKOw5Is8ZSmCs267jf4FW0UKtgpnHGK2H0ba0iramzz07oK48V4y7C7nS3eJr/
+Oen6H9BW4DNXreFZ5yTRFOiQ4eD1pHqR/M/bBieDfRjakgECQQDfgiYYInio4TmM
+9q/h1q5T1bGgajz5U4GInd0K2diNqVoGhSTAyRRGauH+68tPQuX7WCM1VE/lZfZL
+4/dlOaRhAkEA2cHNkrFh4CAlXgtCub+psmT032AIFDEpNNT0K22XIE8savYNqs8w
+aGPurrwGQflxCB19boiaKEcW5FQDkff9WQJAbUznNiw9V1D05OOKNWXX0HWTLMBn
+WwIkOVwByZmo1fX4aXHY/FIZESqZpCFJRlSPxS9f4Gd/vs3y+T/dLupWYQJAJDGX
+RrOfDg6px1jdzVvzC8jF/r7KePi23aYrs3Ayt1cRjfG50dNAO4moqXhtHdglFnE4
+YP/ph5pRTsA8G635eQJBAKbh0zB4HqFI2PmnKsShFBPNkK5x17nAZlYNJf2Ip4Ii
+2Gjxyx4H0iBVgFYLsLB6hRBkOPpx6Jl8mJXOtFXb8lE=
+-----END RSA PRIVATE KEY-----
diff --git a/tests/hwsim/auth_serv/iCA-server/ca-and-root.pem b/tests/hwsim/auth_serv/iCA-server/ca-and-root.pem
new file mode 100644 (file)
index 0000000..d321944
--- /dev/null
@@ -0,0 +1,125 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 15624081837803162867 (0xd8d3e3a6cbe3ccf3)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=Root CA
+        Validity
+            Not Before: Dec 23 19:37:36 2015 GMT
+            Not After : Dec 22 19:37:36 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=Server Intermediate CA
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:de:58:ac:e3:d8:7e:40:f6:84:2a:49:24:49:5a:
+                    f7:c8:23:08:b9:6c:d9:07:01:69:8f:77:28:71:42:
+                    a2:eb:ae:86:10:c6:31:61:9a:14:88:44:0a:68:bf:
+                    6e:a2:46:41:e9:6f:a2:89:fb:0b:f3:e1:b8:30:bf:
+                    e5:80:5e:f9:61:8d:6e:ac:e2:f7:28:e7:9e:44:28:
+                    b8:e4:6e:87:76:a9:d7:ac:ed:11:3f:de:c3:dd:41:
+                    c3:45:82:09:c3:a7:4c:e6:df:2b:88:1e:44:ce:e2:
+                    a7:29:53:f6:13:96:ad:6c:2e:93:00:28:42:77:bc:
+                    73:6e:86:e7:5b:e8:eb:e9:37:1d:63:e7:ea:05:5a:
+                    71:28:f0:81:0b:4c:3f:dd:73:f8:db:13:a8:f0:5f:
+                    6f:6f:e5:1b:c7:94:7f:57:c5:dc:66:26:0c:5a:71:
+                    7a:e3:d2:3e:7a:a6:59:46:03:61:78:89:84:3d:ef:
+                    22:9c:f8:c2:22:75:c4:0c:ef:fb:e4:fa:6f:b8:11:
+                    db:aa:92:9b:6c:23:4e:6e:e5:55:d2:41:47:18:95:
+                    c6:7d:17:be:6d:ab:39:a1:38:61:fd:f9:22:95:69:
+                    f3:9e:28:fd:8a:c8:58:72:3c:91:c2:22:d9:fb:b2:
+                    54:0f:9a:17:27:88:df:60:f5:de:fc:95:9f:25:c6:
+                    64:81
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                84:09:8B:55:1F:7D:2F:0F:28:D7:9C:EC:54:4E:9F:11:97:55:D9:B9
+            X509v3 Authority Key Identifier: 
+                keyid:B8:92:DE:FD:8A:18:B3:30:C3:9F:55:F3:33:5D:B4:C8:29:8A:41:14
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE, pathlen:0
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+    Signature Algorithm: sha256WithRSAEncryption
+         bd:22:63:3d:a7:e5:ce:c9:f5:66:1f:77:5f:d5:24:e3:68:dc:
+         a4:07:80:3e:5e:b1:2c:96:88:39:ad:00:4c:aa:9d:0b:ed:f3:
+         6d:df:9d:2f:97:d2:77:8b:ba:d0:9c:0f:a6:5e:60:b8:0f:e1:
+         96:b1:61:25:48:69:81:64:a8:5c:82:58:0b:f3:d0:a9:4e:8b:
+         90:fc:2f:67:57:da:72:dc:3c:eb:c2:20:19:05:8d:42:0d:14:
+         cf:00:db:59:00:ea:f0:76:3e:ca:85:b1:05:e5:b8:5f:0b:46:
+         c7:3c:a1:d9:5c:4d:b9:24:e7:d6:2b:3d:0d:eb:c3:88:d8:3a:
+         f6:60
+-----BEGIN CERTIFICATE-----
+MIIC1TCCAj6gAwIBAgIJANjT46bL48zzMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNTEy
+MjMxOTM3MzZaFw0yNTEyMjIxOTM3MzZaMD4xCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+DAV3MS5maTEfMB0GA1UEAwwWU2VydmVyIEludGVybWVkaWF0ZSBDQTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAN5YrOPYfkD2hCpJJEla98gjCLls2QcB
+aY93KHFCouuuhhDGMWGaFIhECmi/bqJGQelvoon7C/PhuDC/5YBe+WGNbqzi9yjn
+nkQouORuh3ap16ztET/ew91Bw0WCCcOnTObfK4geRM7ipylT9hOWrWwukwAoQne8
+c26G51vo6+k3HWPn6gVacSjwgQtMP91z+NsTqPBfb2/lG8eUf1fF3GYmDFpxeuPS
+PnqmWUYDYXiJhD3vIpz4wiJ1xAzv++T6b7gR26qSm2wjTm7lVdJBRxiVxn0Xvm2r
+OaE4Yf35IpVp854o/YrIWHI8kcIi2fuyVA+aFyeI32D13vyVnyXGZIECAwEAAaNm
+MGQwHQYDVR0OBBYEFIQJi1UffS8PKNec7FROnxGXVdm5MB8GA1UdIwQYMBaAFLiS
+3v2KGLMww59V8zNdtMgpikEUMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/
+BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4GBAL0iYz2n5c7J9WYfd1/VJONo3KQHgD5e
+sSyWiDmtAEyqnQvt823fnS+X0neLutCcD6ZeYLgP4ZaxYSVIaYFkqFyCWAvz0KlO
+i5D8L2dX2nLcPOvCIBkFjUINFM8A21kA6vB2PsqFsQXluF8LRsc8odlcTbkk59Yr
+PQ3rw4jYOvZg
+-----END CERTIFICATE-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 15624081837803162817 (0xd8d3e3a6cbe3ccc1)
+    Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=Root CA
+        Validity
+            Not Before: Jun 29 16:41:22 2013 GMT
+            Not After : Jun 27 16:41:22 2023 GMT
+        Subject: C=FI, O=w1.fi, CN=Root CA
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (1024 bit)
+                Modulus:
+                    00:be:1e:86:e4:79:03:c1:d1:94:d5:d4:b3:b1:28:
+                    90:76:fb:b8:a6:cd:6d:1c:d1:48:f4:08:9a:67:ff:
+                    f9:a6:54:b1:19:29:df:29:1b:cd:f1:6f:66:01:e7:
+                    db:79:ce:c0:39:2a:25:13:26:94:0c:2c:7b:5a:2c:
+                    81:0f:94:ee:51:d0:75:e6:46:db:17:46:a7:15:8b:
+                    0e:57:0f:b0:54:76:63:12:ca:86:18:bc:1a:c3:16:
+                    c0:70:09:d6:6b:43:39:b8:98:29:46:ac:cb:6a:ad:
+                    38:88:3b:07:dc:81:cd:3a:f6:1d:f6:2f:ef:1d:d7:
+                    ae:8a:b6:d1:e7:b3:15:02:b9
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                B8:92:DE:FD:8A:18:B3:30:C3:9F:55:F3:33:5D:B4:C8:29:8A:41:14
+            X509v3 Authority Key Identifier: 
+                keyid:B8:92:DE:FD:8A:18:B3:30:C3:9F:55:F3:33:5D:B4:C8:29:8A:41:14
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha1WithRSAEncryption
+         1a:cf:77:60:44:43:c4:55:0e:99:e0:89:aa:b9:d3:7b:32:b7:
+         5c:9c:7c:ca:fe:8c:d4:94:c6:5e:f3:83:19:5f:29:59:68:a4:
+         4f:dc:04:2e:b8:71:c0:6d:3b:ae:01:e4:b9:88:99:cc:ce:82:
+         be:6a:28:c2:ac:6a:94:c6:87:90:ed:85:3c:10:71:c5:ff:3c:
+         70:64:e2:41:62:31:ea:86:7b:11:8c:93:ea:c6:f3:f3:4e:f9:
+         d4:f2:81:90:d7:f4:fa:a1:91:6e:d4:dd:15:3e:26:3b:ac:1e:
+         c3:c2:1f:ed:bb:34:bf:cb:b2:67:c6:c6:51:e8:51:22:b4:f3:
+         92:e8
+-----BEGIN CERTIFICATE-----
+MIICLDCCAZWgAwIBAgIJANjT46bL48zBMA0GCSqGSIb3DQEBBQUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xMzA2
+MjkxNjQxMjJaFw0yMzA2MjcxNjQxMjJaMC8xCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+DAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
+gYkCgYEAvh6G5HkDwdGU1dSzsSiQdvu4ps1tHNFI9AiaZ//5plSxGSnfKRvN8W9m
+Aefbec7AOSolEyaUDCx7WiyBD5TuUdB15kbbF0anFYsOVw+wVHZjEsqGGLwawxbA
+cAnWa0M5uJgpRqzLaq04iDsH3IHNOvYd9i/vHdeuirbR57MVArkCAwEAAaNQME4w
+HQYDVR0OBBYEFLiS3v2KGLMww59V8zNdtMgpikEUMB8GA1UdIwQYMBaAFLiS3v2K
+GLMww59V8zNdtMgpikEUMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEA
+Gs93YERDxFUOmeCJqrnTezK3XJx8yv6M1JTGXvODGV8pWWikT9wELrhxwG07rgHk
+uYiZzM6CvmoowqxqlMaHkO2FPBBxxf88cGTiQWIx6oZ7EYyT6sbz80751PKBkNf0
++qGRbtTdFT4mO6wew8If7bs0v8uyZ8bGUehRIrTzkug=
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/iCA-server/cacert.pem b/tests/hwsim/auth_serv/iCA-server/cacert.pem
new file mode 100644 (file)
index 0000000..d5532e9
--- /dev/null
@@ -0,0 +1,70 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 15624081837803162867 (0xd8d3e3a6cbe3ccf3)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=Root CA
+        Validity
+            Not Before: Dec 23 19:37:36 2015 GMT
+            Not After : Dec 22 19:37:36 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=Server Intermediate CA
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:de:58:ac:e3:d8:7e:40:f6:84:2a:49:24:49:5a:
+                    f7:c8:23:08:b9:6c:d9:07:01:69:8f:77:28:71:42:
+                    a2:eb:ae:86:10:c6:31:61:9a:14:88:44:0a:68:bf:
+                    6e:a2:46:41:e9:6f:a2:89:fb:0b:f3:e1:b8:30:bf:
+                    e5:80:5e:f9:61:8d:6e:ac:e2:f7:28:e7:9e:44:28:
+                    b8:e4:6e:87:76:a9:d7:ac:ed:11:3f:de:c3:dd:41:
+                    c3:45:82:09:c3:a7:4c:e6:df:2b:88:1e:44:ce:e2:
+                    a7:29:53:f6:13:96:ad:6c:2e:93:00:28:42:77:bc:
+                    73:6e:86:e7:5b:e8:eb:e9:37:1d:63:e7:ea:05:5a:
+                    71:28:f0:81:0b:4c:3f:dd:73:f8:db:13:a8:f0:5f:
+                    6f:6f:e5:1b:c7:94:7f:57:c5:dc:66:26:0c:5a:71:
+                    7a:e3:d2:3e:7a:a6:59:46:03:61:78:89:84:3d:ef:
+                    22:9c:f8:c2:22:75:c4:0c:ef:fb:e4:fa:6f:b8:11:
+                    db:aa:92:9b:6c:23:4e:6e:e5:55:d2:41:47:18:95:
+                    c6:7d:17:be:6d:ab:39:a1:38:61:fd:f9:22:95:69:
+                    f3:9e:28:fd:8a:c8:58:72:3c:91:c2:22:d9:fb:b2:
+                    54:0f:9a:17:27:88:df:60:f5:de:fc:95:9f:25:c6:
+                    64:81
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                84:09:8B:55:1F:7D:2F:0F:28:D7:9C:EC:54:4E:9F:11:97:55:D9:B9
+            X509v3 Authority Key Identifier: 
+                keyid:B8:92:DE:FD:8A:18:B3:30:C3:9F:55:F3:33:5D:B4:C8:29:8A:41:14
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE, pathlen:0
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+    Signature Algorithm: sha256WithRSAEncryption
+         bd:22:63:3d:a7:e5:ce:c9:f5:66:1f:77:5f:d5:24:e3:68:dc:
+         a4:07:80:3e:5e:b1:2c:96:88:39:ad:00:4c:aa:9d:0b:ed:f3:
+         6d:df:9d:2f:97:d2:77:8b:ba:d0:9c:0f:a6:5e:60:b8:0f:e1:
+         96:b1:61:25:48:69:81:64:a8:5c:82:58:0b:f3:d0:a9:4e:8b:
+         90:fc:2f:67:57:da:72:dc:3c:eb:c2:20:19:05:8d:42:0d:14:
+         cf:00:db:59:00:ea:f0:76:3e:ca:85:b1:05:e5:b8:5f:0b:46:
+         c7:3c:a1:d9:5c:4d:b9:24:e7:d6:2b:3d:0d:eb:c3:88:d8:3a:
+         f6:60
+-----BEGIN CERTIFICATE-----
+MIIC1TCCAj6gAwIBAgIJANjT46bL48zzMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNTEy
+MjMxOTM3MzZaFw0yNTEyMjIxOTM3MzZaMD4xCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+DAV3MS5maTEfMB0GA1UEAwwWU2VydmVyIEludGVybWVkaWF0ZSBDQTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAN5YrOPYfkD2hCpJJEla98gjCLls2QcB
+aY93KHFCouuuhhDGMWGaFIhECmi/bqJGQelvoon7C/PhuDC/5YBe+WGNbqzi9yjn
+nkQouORuh3ap16ztET/ew91Bw0WCCcOnTObfK4geRM7ipylT9hOWrWwukwAoQne8
+c26G51vo6+k3HWPn6gVacSjwgQtMP91z+NsTqPBfb2/lG8eUf1fF3GYmDFpxeuPS
+PnqmWUYDYXiJhD3vIpz4wiJ1xAzv++T6b7gR26qSm2wjTm7lVdJBRxiVxn0Xvm2r
+OaE4Yf35IpVp854o/YrIWHI8kcIi2fuyVA+aFyeI32D13vyVnyXGZIECAwEAAaNm
+MGQwHQYDVR0OBBYEFIQJi1UffS8PKNec7FROnxGXVdm5MB8GA1UdIwQYMBaAFLiS
+3v2KGLMww59V8zNdtMgpikEUMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/
+BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4GBAL0iYz2n5c7J9WYfd1/VJONo3KQHgD5e
+sSyWiDmtAEyqnQvt823fnS+X0neLutCcD6ZeYLgP4ZaxYSVIaYFkqFyCWAvz0KlO
+i5D8L2dX2nLcPOvCIBkFjUINFM8A21kA6vB2PsqFsQXluF8LRsc8odlcTbkk59Yr
+PQ3rw4jYOvZg
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/iCA-server/careq.pem b/tests/hwsim/auth_serv/iCA-server/careq.pem
new file mode 100644 (file)
index 0000000..70726e8
--- /dev/null
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICljCCAX4CAQAwUTELMAkGA1UEBhMCRkkxETAPBgNVBAcMCEhlbHNpbmtpMQ4w
+DAYDVQQKDAV3MS5maTEfMB0GA1UEAwwWU2VydmVyIEludGVybWVkaWF0ZSBDQTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN5YrOPYfkD2hCpJJEla98gj
+CLls2QcBaY93KHFCouuuhhDGMWGaFIhECmi/bqJGQelvoon7C/PhuDC/5YBe+WGN
+bqzi9yjnnkQouORuh3ap16ztET/ew91Bw0WCCcOnTObfK4geRM7ipylT9hOWrWwu
+kwAoQne8c26G51vo6+k3HWPn6gVacSjwgQtMP91z+NsTqPBfb2/lG8eUf1fF3GYm
+DFpxeuPSPnqmWUYDYXiJhD3vIpz4wiJ1xAzv++T6b7gR26qSm2wjTm7lVdJBRxiV
+xn0Xvm2rOaE4Yf35IpVp854o/YrIWHI8kcIi2fuyVA+aFyeI32D13vyVnyXGZIEC
+AwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQCdd8AniQQQA4urnrqdR9hQlFY5JxUU
+OtGqkRGb8pTJAfxU8hgmAhbHmPw7qhNnZNqr2i/p8A1UcwCuU7Sx2StszIjyuEQJ
+SteaUpvLUWM/KrlqBH4VTcHFGsZWEJ+gMhBJwJuET6mtZFdm84HALJClIysx973p
+d6i92H93ew3RuMF/erMnCPNjt0Pe8QWU/tpwsVD/SBGbqg8PCShqySNO9P+P1pAb
+wIPInq3ox2E6RStFnIY8MES5sTUFWAxh3MNYY8OuVcuun2R0Yk0jy/wmmaWzcXS+
+sOj48LNyptGk8SAS1Yxu8lUfj3p77eZZqUqLorj/hdoqfnMOnCx7NOww
+-----END CERTIFICATE REQUEST-----
diff --git a/tests/hwsim/auth_serv/iCA-server/index.txt b/tests/hwsim/auth_serv/iCA-server/index.txt
new file mode 100644 (file)
index 0000000..a480a97
--- /dev/null
@@ -0,0 +1,2 @@
+V      251220193736Z           8020A0407F798AB8        unknown /C=FI/O=w1.fi/CN=server.w1.fi
+R      251220193736Z   151223193736Z   8020A0407F798AB9        unknown /C=FI/O=w1.fi/CN=server-revoked.w1.fi
diff --git a/tests/hwsim/auth_serv/iCA-server/index.txt.attr b/tests/hwsim/auth_serv/iCA-server/index.txt.attr
new file mode 100644 (file)
index 0000000..8f7e63a
--- /dev/null
@@ -0,0 +1 @@
+unique_subject = yes
diff --git a/tests/hwsim/auth_serv/iCA-server/newcerts/8020A0407F798AB8.pem b/tests/hwsim/auth_serv/iCA-server/newcerts/8020A0407F798AB8.pem
new file mode 100644 (file)
index 0000000..ebcbde3
--- /dev/null
@@ -0,0 +1,84 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 9232555434986539704 (0x8020a0407f798ab8)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=Server Intermediate CA
+        Validity
+            Not Before: Dec 23 19:37:36 2015 GMT
+            Not After : Dec 20 19:37:36 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=server.w1.fi
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:e4:88:a5:93:02:5b:bc:54:68:46:fa:73:7d:33:
+                    30:47:45:5c:49:5f:3c:51:5f:9b:fe:c5:14:10:26:
+                    3d:0f:e3:c2:b2:17:84:d3:3e:12:a8:b2:7b:02:1a:
+                    8a:8b:e9:f4:41:1e:fc:f3:49:2d:c6:d4:88:27:81:
+                    d0:86:f3:b9:c0:0a:2a:28:45:00:32:c3:18:22:f6:
+                    99:37:f1:74:8d:ac:54:47:73:e5:b6:d3:e7:f8:80:
+                    99:75:f5:19:19:eb:19:70:df:92:53:b1:61:38:ff:
+                    7f:cf:8b:bd:e1:7f:50:5b:d0:95:30:a3:37:6b:8a:
+                    72:06:a7:e8:39:e2:a4:78:43:98:91:cd:30:88:34:
+                    5b:aa:9e:a2:9f:26:d5:e1:5b:86:4d:01:a4:c2:65:
+                    cd:27:94:be:e2:f5:73:5d:c4:60:98:f1:75:11:94:
+                    09:0d:9d:04:7f:ef:1a:9d:5f:f0:4a:3f:88:d7:76:
+                    2e:9b:d6:2a:c6:94:09:37:0a:37:24:92:91:9d:18:
+                    0f:ea:4e:d4:e4:9d:45:38:5a:ba:d8:df:b6:15:6f:
+                    ac:ff:6c:41:ac:d7:c0:0a:55:ec:81:ca:9a:59:40:
+                    55:8b:a4:77:13:df:fa:c3:b5:ee:ef:87:41:8d:94:
+                    d0:c0:96:41:b4:3a:04:b6:6b:6a:56:93:f4:67:7e:
+                    27:e1
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                4B:81:85:B4:88:41:0D:D4:15:D3:48:0E:F4:A9:99:14:2D:B1:DB:93
+            X509v3 Authority Key Identifier: 
+                keyid:84:09:8B:55:1F:7D:2F:0F:28:D7:9C:EC:54:4E:9F:11:97:55:D9:B9
+
+            X509v3 Subject Alternative Name: critical
+                DNS:server.w1.fi
+            X509v3 Extended Key Usage: critical
+                TLS Web Server Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: sha256WithRSAEncryption
+         49:2a:14:22:16:2c:12:f5:4e:06:f3:c2:1e:ac:54:07:5d:86:
+         16:3e:6c:a0:73:e1:a6:d7:c3:49:1f:80:0d:b6:54:22:77:ce:
+         39:dd:f6:f6:9f:62:ff:d5:27:7f:c3:92:73:b9:a7:ce:87:5a:
+         e3:bc:52:b3:0a:99:eb:91:56:b6:78:01:c3:0e:4b:ca:8a:04:
+         ee:5c:56:05:ef:7a:cb:21:f9:eb:8a:38:12:50:c7:6e:a8:1f:
+         0e:81:81:a6:2d:ea:35:94:24:db:76:77:df:ea:41:4c:af:7e:
+         29:9d:d5:e6:e3:12:78:19:92:ed:35:b9:99:19:a9:d6:cb:f8:
+         a7:21:fb:8e:a7:39:dc:e1:ab:3d:ba:12:87:ba:1c:08:e6:8a:
+         21:96:44:44:8a:61:0f:70:00:d0:cb:63:93:a4:fa:cc:75:a3:
+         fd:e8:af:33:24:80:4a:d9:b9:2a:a1:20:0b:62:0b:17:6c:9a:
+         7c:8b:fd:9e:ff:be:b2:51:5e:e9:3a:cc:28:22:63:44:69:7f:
+         6d:1f:08:14:a4:32:d0:1f:f9:c3:8d:28:1a:76:12:00:3c:b3:
+         38:13:ca:67:17:79:c6:de:5d:b7:9d:f8:e3:64:f7:b3:a0:5c:
+         e5:6e:fc:10:f3:53:d6:70:38:c2:6f:87:ab:07:1c:64:ff:30:
+         d8:3a:1e:75
+-----BEGIN CERTIFICATE-----
+MIIDiDCCAnCgAwIBAgIJAIAgoEB/eYq4MA0GCSqGSIb3DQEBCwUAMD4xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEfMB0GA1UEAwwWU2VydmVyIEludGVybWVk
+aWF0ZSBDQTAeFw0xNTEyMjMxOTM3MzZaFw0yNTEyMjAxOTM3MzZaMDQxCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEVMBMGA1UEAwwMc2VydmVyLncxLmZpMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5IilkwJbvFRoRvpzfTMwR0Vc
+SV88UV+b/sUUECY9D+PCsheE0z4SqLJ7AhqKi+n0QR7880ktxtSIJ4HQhvO5wAoq
+KEUAMsMYIvaZN/F0jaxUR3PlttPn+ICZdfUZGesZcN+SU7FhOP9/z4u94X9QW9CV
+MKM3a4pyBqfoOeKkeEOYkc0wiDRbqp6inybV4VuGTQGkwmXNJ5S+4vVzXcRgmPF1
+EZQJDZ0Ef+8anV/wSj+I13Yum9YqxpQJNwo3JJKRnRgP6k7U5J1FOFq62N+2FW+s
+/2xBrNfAClXsgcqaWUBVi6R3E9/6w7Xu74dBjZTQwJZBtDoEtmtqVpP0Z34n4QID
+AQABo4GSMIGPMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFEuBhbSIQQ3UFdNIDvSp
+mRQtsduTMB8GA1UdIwQYMBaAFIQJi1UffS8PKNec7FROnxGXVdm5MBoGA1UdEQEB
+/wQQMA6CDHNlcnZlci53MS5maTAWBgNVHSUBAf8EDDAKBggrBgEFBQcDATALBgNV
+HQ8EBAMCBaAwDQYJKoZIhvcNAQELBQADggEBAEkqFCIWLBL1Tgbzwh6sVAddhhY+
+bKBz4abXw0kfgA22VCJ3zjnd9vafYv/VJ3/DknO5p86HWuO8UrMKmeuRVrZ4AcMO
+S8qKBO5cVgXvessh+euKOBJQx26oHw6BgaYt6jWUJNt2d9/qQUyvfimd1ebjEngZ
+ku01uZkZqdbL+Kch+46nOdzhqz26Eoe6HAjmiiGWRESKYQ9wANDLY5Ok+sx1o/3o
+rzMkgErZuSqhIAtiCxdsmnyL/Z7/vrJRXuk6zCgiY0Rpf20fCBSkMtAf+cONKBp2
+EgA8szgTymcXecbeXbed+ONk97OgXOVu/BDzU9ZwOMJvh6sHHGT/MNg6HnU=
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/iCA-server/newcerts/8020A0407F798AB9.pem b/tests/hwsim/auth_serv/iCA-server/newcerts/8020A0407F798AB9.pem
new file mode 100644 (file)
index 0000000..7379785
--- /dev/null
@@ -0,0 +1,85 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 9232555434986539705 (0x8020a0407f798ab9)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=Server Intermediate CA
+        Validity
+            Not Before: Dec 23 19:37:36 2015 GMT
+            Not After : Dec 20 19:37:36 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=server-revoked.w1.fi
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:ac:5c:ae:06:36:4a:65:e0:db:0b:3c:28:13:08:
+                    8b:90:66:43:6f:c8:b2:3b:fa:41:bd:1a:10:10:fb:
+                    e9:05:6a:ba:42:90:4d:2e:cf:b1:b9:c3:73:f5:fc:
+                    ac:4c:18:e9:44:73:69:5e:2d:83:63:d1:29:e5:59:
+                    55:a8:bf:b0:1c:7a:0d:17:18:b0:38:21:af:cb:6d:
+                    a9:6b:9d:a2:88:0e:1c:ee:1a:a5:9f:3c:27:ea:fe:
+                    8f:9b:94:df:12:3c:34:bb:bf:6c:d0:6c:6b:46:ad:
+                    bc:ff:88:ae:d8:4d:8b:9f:34:50:25:c4:96:be:25:
+                    42:06:c8:b3:8e:21:a5:fd:a3:82:f9:74:78:46:56:
+                    8d:0b:f0:c4:fa:1a:0e:f5:34:22:53:fd:43:37:a3:
+                    47:fd:9f:a2:bc:d0:60:25:a8:db:93:f7:0c:88:fe:
+                    79:52:f2:07:f1:de:fc:66:6e:fe:da:10:76:6c:d0:
+                    87:8c:ef:dd:40:6d:82:7c:d1:39:b2:17:d6:07:cf:
+                    1a:5a:39:12:ed:49:4f:d9:c7:91:40:ab:73:f7:54:
+                    3c:a5:7d:9f:bb:0c:47:77:0e:d9:61:e5:1b:14:65:
+                    4e:38:c5:a7:8a:ee:32:be:05:25:94:a0:7f:96:09:
+                    59:1b:04:08:42:6b:50:6b:95:7a:78:f6:ec:f4:f6:
+                    4d:43
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                0D:49:37:45:42:77:90:25:BA:9B:67:DB:F6:DC:61:D2:53:5B:C6:BC
+            X509v3 Authority Key Identifier: 
+                keyid:84:09:8B:55:1F:7D:2F:0F:28:D7:9C:EC:54:4E:9F:11:97:55:D9:B9
+
+            X509v3 Subject Alternative Name: critical
+                DNS:server-revoked.w1.fi
+            X509v3 Extended Key Usage: critical
+                TLS Web Server Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: sha256WithRSAEncryption
+         22:c6:72:08:84:a9:e9:19:77:ea:6a:06:68:43:8b:e7:72:af:
+         9c:a2:47:b9:6f:b6:cb:11:17:89:0a:42:52:14:58:9e:3c:01:
+         fd:e7:fc:a2:0d:85:a5:b5:8c:27:d5:5e:b2:47:05:05:f9:56:
+         b6:0b:e2:28:f3:1d:75:5e:13:eb:ec:a0:76:2b:d9:ed:99:84:
+         08:6d:64:71:13:b6:02:81:b3:c2:7e:b8:b6:00:98:4f:26:ea:
+         f1:67:5b:35:2a:26:d0:ca:a8:fb:eb:21:fb:f1:d6:5a:63:42:
+         01:5f:b3:59:3d:f8:e0:4d:94:3a:3a:82:46:02:9d:81:2c:ef:
+         e5:46:c7:99:f4:2f:43:ad:85:fc:2c:ca:0b:6b:48:01:ac:d7:
+         f7:da:0e:16:c4:10:18:14:83:9c:85:90:75:ef:66:9f:65:42:
+         e5:e7:8c:16:ac:f6:60:61:d7:5f:a0:21:cd:8a:85:d4:a0:f2:
+         8e:17:0e:38:5e:31:12:ac:24:b5:67:61:9d:15:84:0b:fc:84:
+         8a:d4:29:90:3d:4b:23:48:19:6b:f7:26:1f:fe:b9:b9:f1:6e:
+         70:ac:ec:31:60:be:7d:6f:58:7e:c1:47:61:a7:b0:4b:b2:fd:
+         62:06:c5:97:43:28:39:a5:c5:60:51:c0:46:9d:6b:e4:1a:ed:
+         0c:a6:51:8a
+-----BEGIN CERTIFICATE-----
+MIIDmDCCAoCgAwIBAgIJAIAgoEB/eYq5MA0GCSqGSIb3DQEBCwUAMD4xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEfMB0GA1UEAwwWU2VydmVyIEludGVybWVk
+aWF0ZSBDQTAeFw0xNTEyMjMxOTM3MzZaFw0yNTEyMjAxOTM3MzZaMDwxCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEdMBsGA1UEAwwUc2VydmVyLXJldm9rZWQu
+dzEuZmkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsXK4GNkpl4NsL
+PCgTCIuQZkNvyLI7+kG9GhAQ++kFarpCkE0uz7G5w3P1/KxMGOlEc2leLYNj0Snl
+WVWov7Aceg0XGLA4Ia/LbalrnaKIDhzuGqWfPCfq/o+blN8SPDS7v2zQbGtGrbz/
+iK7YTYufNFAlxJa+JUIGyLOOIaX9o4L5dHhGVo0L8MT6Gg71NCJT/UM3o0f9n6K8
+0GAlqNuT9wyI/nlS8gfx3vxmbv7aEHZs0IeM791AbYJ80TmyF9YHzxpaORLtSU/Z
+x5FAq3P3VDylfZ+7DEd3Dtlh5RsUZU44xaeK7jK+BSWUoH+WCVkbBAhCa1BrlXp4
+9uz09k1DAgMBAAGjgZowgZcwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUDUk3RUJ3
+kCW6m2fb9txh0lNbxrwwHwYDVR0jBBgwFoAUhAmLVR99Lw8o15zsVE6fEZdV2bkw
+IgYDVR0RAQH/BBgwFoIUc2VydmVyLXJldm9rZWQudzEuZmkwFgYDVR0lAQH/BAww
+CgYIKwYBBQUHAwEwCwYDVR0PBAQDAgWgMA0GCSqGSIb3DQEBCwUAA4IBAQAixnII
+hKnpGXfqagZoQ4vncq+coke5b7bLEReJCkJSFFiePAH95/yiDYWltYwn1V6yRwUF
++Va2C+Io8x11XhPr7KB2K9ntmYQIbWRxE7YCgbPCfri2AJhPJurxZ1s1KibQyqj7
+6yH78dZaY0IBX7NZPfjgTZQ6OoJGAp2BLO/lRseZ9C9DrYX8LMoLa0gBrNf32g4W
+xBAYFIOchZB172afZULl54wWrPZgYddfoCHNioXUoPKOFw44XjESrCS1Z2GdFYQL
+/ISK1CmQPUsjSBlr9yYf/rm58W5wrOwxYL59b1h+wUdhp7BLsv1iBsWXQyg5pcVg
+UcBGnWvkGu0MplGK
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/iCA-server/private/cakey.pem b/tests/hwsim/auth_serv/iCA-server/private/cakey.pem
new file mode 100644 (file)
index 0000000..579139e
--- /dev/null
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDeWKzj2H5A9oQq
+SSRJWvfIIwi5bNkHAWmPdyhxQqLrroYQxjFhmhSIRApov26iRkHpb6KJ+wvz4bgw
+v+WAXvlhjW6s4vco555EKLjkbod2qdes7RE/3sPdQcNFggnDp0zm3yuIHkTO4qcp
+U/YTlq1sLpMAKEJ3vHNuhudb6OvpNx1j5+oFWnEo8IELTD/dc/jbE6jwX29v5RvH
+lH9XxdxmJgxacXrj0j56pllGA2F4iYQ97yKc+MIidcQM7/vk+m+4EduqkptsI05u
+5VXSQUcYlcZ9F75tqzmhOGH9+SKVafOeKP2KyFhyPJHCItn7slQPmhcniN9g9d78
+lZ8lxmSBAgMBAAECggEAYEOYJtVWZB3WvtAH69J8sKOqZU1g8Q2FfF2kntSw4MUg
+uiZ0vsMM3KpIr20iIxOz+bMhdgfA9wfkzQZoAJod8kRfhG6Hf6g3916CHjRUZeXG
+wNGqxDJYLnUIbBGO1KycOOCqYjZoqAGtSdFWGskDsHDBqDHGBT0L5PB3Pm2rpb4u
+JQV2Dcvqjf8MfDBGsyKx7+L+EtMXhcgUCQ4vRtvCvNV+Xl4wL37l1/OkfIPTWkQE
+FpkBMy+/cvB8H6rmlAxp6t8EV9rbgyt9OW86+gf1q4U7VM6VUXFGjFvGwji9OkgA
+UnwrdX0IryG/ruuKzIb6eBEb5hRoluGqHphptiX8IQKBgQD5/QazeInpiHkfZpm5
+obgLYtLHkQuewVIZVFhVAle07AaZ2748lRMu/UHo0YITS1mLK8AA7xVi+NjwIbg0
+WpoBQ4V6k7U/+PfLygFYbTB+vTreH6Za/zIpEXjYudemt5Xgjva+YEM5/rYNkNgH
+d0Dcbuq1D5OgsEWs/S3jlPzWJQKBgQDjsXrj1wO8yYokv9kGETVN9604lYFNfTnD
+HwAcEanCa+Ist6TpMZOK7QV78rmR5bxymLKI6UPCvrdqhLb+BuTl2GrSvrSeNwk4
+zAHi25MapTQxssJMtom88htbBIJ/P+0iEXKKXIRzIi0UXRNfoE5lwQZlHUdFHtlK
+xUvnrgXALQKBgQCva2JcZeVAvsdfxXtxy41+T+Zgq+Nfj4CwzYL+hBpPlqA7Lvub
+P3CqtISffwSrzWAUTKr6/MohHUX9m2vLMRiIcn0juqqhLW+UzTeMeXJiPR8l50ew
+6wqjzuLiEebF0mWVojx68sm51IajllRBSOl2xU5lp3yMcaUy8qZU4KNbEQKBgBnu
+lLhuPJa7vWgCEY2HWDLRCoFvRZK1uGZomXKY8GScNN4y7C1C4DLqW72KH2hmadgD
+XBILvxPm9KzFALJdxqQGyePGpHuAeSRm17AmodJfDlq6qTZjc7x5NnRfRx2HAlLm
++cyYTN1v/wJat2Ikt8kO+tN5SiytHsJNRh/UygLhAoGAXctGrFNl7a/cg0b7zr8O
+0t7UcaqXRpYHFTOaijL3WkI7Ps4us14lmkWvkM1iUjCyPtBCRNeYXu5HxENIn4p5
+RixqYvO1DO/9TYNL/fXReqtVEgYz8ygAmasRf7NSJxO1ByhCiJ+rxRXCTFic/GPU
+k5WGvSSepCUM2RpqXVWsm44=
+-----END PRIVATE KEY-----
diff --git a/tests/hwsim/auth_serv/iCA-server/serial b/tests/hwsim/auth_serv/iCA-server/serial
new file mode 100644 (file)
index 0000000..06b9bf8
--- /dev/null
@@ -0,0 +1 @@
+8020A0407F798ABA
diff --git a/tests/hwsim/auth_serv/iCA-server/server-revoked.key b/tests/hwsim/auth_serv/iCA-server/server-revoked.key
new file mode 100644 (file)
index 0000000..51f2517
--- /dev/null
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCsXK4GNkpl4NsL
+PCgTCIuQZkNvyLI7+kG9GhAQ++kFarpCkE0uz7G5w3P1/KxMGOlEc2leLYNj0Snl
+WVWov7Aceg0XGLA4Ia/LbalrnaKIDhzuGqWfPCfq/o+blN8SPDS7v2zQbGtGrbz/
+iK7YTYufNFAlxJa+JUIGyLOOIaX9o4L5dHhGVo0L8MT6Gg71NCJT/UM3o0f9n6K8
+0GAlqNuT9wyI/nlS8gfx3vxmbv7aEHZs0IeM791AbYJ80TmyF9YHzxpaORLtSU/Z
+x5FAq3P3VDylfZ+7DEd3Dtlh5RsUZU44xaeK7jK+BSWUoH+WCVkbBAhCa1BrlXp4
+9uz09k1DAgMBAAECggEBAIodPemGaXlXg85t5uLRjxwnhdQ2KvQ6paDFGKizY1bO
+3e/mt6JSFWT4hJxRWzMjJxCNtpobuFQsz/iS7DvrVlCLUJ/4TYS9IaPN/NtaFloV
+jQMS4TJGvunkD+koktOG4O6tBqHArvmU0ISm3ww+nyn0fmC1NeGp802CV7cFqYAi
+y5QT6FhBZYRGj8v+YH9I06Os+tr6C0tKdy5J5nMrbHa64XZulHn/McbeDImtnBfy
+5aLOMIZjlat6nYjMC9dhAuDXKXodnmBW4Jq889UVbg+kgtu9r8Uga5Wx+IBKiieM
+vjHOtJPCb4fHTjCl19G7D5WsXy4r/JNQyUQXlSLpO+kCgYEA4cTzLQ5D8WVsUBOp
+cOZBi93AdbQvbbC7HhkMiFACmhs1cQhgvMXVgjdxt1NcX33tZ9kK8dnx41kp0/ey
+/8JEJM5DI1RFqPIBkXi50RY32uazi7azoSAx0xvmkXvdpTdBUB5BjMHbqzxQZhgH
+D4gtC93o2C53z1StE0Dr37b3zNcCgYEAw3EA+PN+y6Y5e13GLC9M0NSK1gFutCEK
+RqhpCWG1NqJgKMcDTaqPyb74ky9JkAVlFA7WQUUOHInbY+ZCnRLRpgNzbvOgQd33
+g7e5kyHcYsdizZrn3qRKPqocmtFNIjs6xNYufdbMvEU66E752WQOq+TZI89vYkPB
+E0uEyzcq6XUCgYAEIWVNirhFf1SG9oUgEqZaV7lArgY8HIKf31dyWvxhM2Q76CpU
+6c2pLzh+YSEMgjJItxjTKeiZ/zSbsylsMnKqtbdWuyD3IU5UCgBkSeLFt3jLcpFA
+vmUK9rS2Lqz0a9lfDN6oI5fQPy89Xu0qJJSmZe3vnpIEkgkElCh8lE1eSwKBgQC4
+Y7oeJmSfMEGVMcDRWQLpF02xYIKYcX+ncCZBEq0MUZ/VeQWV1fB4z7Ln8jo+Jcja
+ZrEfvU32AN463zhDx0iCj0juCe5NlmR6IfF0bgLmMuT1xEs0k930RzxbmFJklGr6
+4HPWh7x7d/l+yVwSDMOGy49NqNyWYgQb9yjfLTpQLQKBgAM+hF/wgbDpA7GGP1ww
+c9kouaXkylPHJWab28Gr2Ef9ixZjQ/RQrcc71H8e4/ZFAgTN0hclxQMdH2mo6ocC
+cEyxajAci8QaX7RDKZUppsP9vbZk+7HTgyaCo2vh5xOPAeeTzOPhFSoxUhFfj+cP
+Ybdr61y8Ug/YwixvsB0eZtLt
+-----END PRIVATE KEY-----
diff --git a/tests/hwsim/auth_serv/iCA-server/server-revoked.pem b/tests/hwsim/auth_serv/iCA-server/server-revoked.pem
new file mode 100644 (file)
index 0000000..7379785
--- /dev/null
@@ -0,0 +1,85 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 9232555434986539705 (0x8020a0407f798ab9)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=Server Intermediate CA
+        Validity
+            Not Before: Dec 23 19:37:36 2015 GMT
+            Not After : Dec 20 19:37:36 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=server-revoked.w1.fi
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:ac:5c:ae:06:36:4a:65:e0:db:0b:3c:28:13:08:
+                    8b:90:66:43:6f:c8:b2:3b:fa:41:bd:1a:10:10:fb:
+                    e9:05:6a:ba:42:90:4d:2e:cf:b1:b9:c3:73:f5:fc:
+                    ac:4c:18:e9:44:73:69:5e:2d:83:63:d1:29:e5:59:
+                    55:a8:bf:b0:1c:7a:0d:17:18:b0:38:21:af:cb:6d:
+                    a9:6b:9d:a2:88:0e:1c:ee:1a:a5:9f:3c:27:ea:fe:
+                    8f:9b:94:df:12:3c:34:bb:bf:6c:d0:6c:6b:46:ad:
+                    bc:ff:88:ae:d8:4d:8b:9f:34:50:25:c4:96:be:25:
+                    42:06:c8:b3:8e:21:a5:fd:a3:82:f9:74:78:46:56:
+                    8d:0b:f0:c4:fa:1a:0e:f5:34:22:53:fd:43:37:a3:
+                    47:fd:9f:a2:bc:d0:60:25:a8:db:93:f7:0c:88:fe:
+                    79:52:f2:07:f1:de:fc:66:6e:fe:da:10:76:6c:d0:
+                    87:8c:ef:dd:40:6d:82:7c:d1:39:b2:17:d6:07:cf:
+                    1a:5a:39:12:ed:49:4f:d9:c7:91:40:ab:73:f7:54:
+                    3c:a5:7d:9f:bb:0c:47:77:0e:d9:61:e5:1b:14:65:
+                    4e:38:c5:a7:8a:ee:32:be:05:25:94:a0:7f:96:09:
+                    59:1b:04:08:42:6b:50:6b:95:7a:78:f6:ec:f4:f6:
+                    4d:43
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                0D:49:37:45:42:77:90:25:BA:9B:67:DB:F6:DC:61:D2:53:5B:C6:BC
+            X509v3 Authority Key Identifier: 
+                keyid:84:09:8B:55:1F:7D:2F:0F:28:D7:9C:EC:54:4E:9F:11:97:55:D9:B9
+
+            X509v3 Subject Alternative Name: critical
+                DNS:server-revoked.w1.fi
+            X509v3 Extended Key Usage: critical
+                TLS Web Server Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: sha256WithRSAEncryption
+         22:c6:72:08:84:a9:e9:19:77:ea:6a:06:68:43:8b:e7:72:af:
+         9c:a2:47:b9:6f:b6:cb:11:17:89:0a:42:52:14:58:9e:3c:01:
+         fd:e7:fc:a2:0d:85:a5:b5:8c:27:d5:5e:b2:47:05:05:f9:56:
+         b6:0b:e2:28:f3:1d:75:5e:13:eb:ec:a0:76:2b:d9:ed:99:84:
+         08:6d:64:71:13:b6:02:81:b3:c2:7e:b8:b6:00:98:4f:26:ea:
+         f1:67:5b:35:2a:26:d0:ca:a8:fb:eb:21:fb:f1:d6:5a:63:42:
+         01:5f:b3:59:3d:f8:e0:4d:94:3a:3a:82:46:02:9d:81:2c:ef:
+         e5:46:c7:99:f4:2f:43:ad:85:fc:2c:ca:0b:6b:48:01:ac:d7:
+         f7:da:0e:16:c4:10:18:14:83:9c:85:90:75:ef:66:9f:65:42:
+         e5:e7:8c:16:ac:f6:60:61:d7:5f:a0:21:cd:8a:85:d4:a0:f2:
+         8e:17:0e:38:5e:31:12:ac:24:b5:67:61:9d:15:84:0b:fc:84:
+         8a:d4:29:90:3d:4b:23:48:19:6b:f7:26:1f:fe:b9:b9:f1:6e:
+         70:ac:ec:31:60:be:7d:6f:58:7e:c1:47:61:a7:b0:4b:b2:fd:
+         62:06:c5:97:43:28:39:a5:c5:60:51:c0:46:9d:6b:e4:1a:ed:
+         0c:a6:51:8a
+-----BEGIN CERTIFICATE-----
+MIIDmDCCAoCgAwIBAgIJAIAgoEB/eYq5MA0GCSqGSIb3DQEBCwUAMD4xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEfMB0GA1UEAwwWU2VydmVyIEludGVybWVk
+aWF0ZSBDQTAeFw0xNTEyMjMxOTM3MzZaFw0yNTEyMjAxOTM3MzZaMDwxCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEdMBsGA1UEAwwUc2VydmVyLXJldm9rZWQu
+dzEuZmkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsXK4GNkpl4NsL
+PCgTCIuQZkNvyLI7+kG9GhAQ++kFarpCkE0uz7G5w3P1/KxMGOlEc2leLYNj0Snl
+WVWov7Aceg0XGLA4Ia/LbalrnaKIDhzuGqWfPCfq/o+blN8SPDS7v2zQbGtGrbz/
+iK7YTYufNFAlxJa+JUIGyLOOIaX9o4L5dHhGVo0L8MT6Gg71NCJT/UM3o0f9n6K8
+0GAlqNuT9wyI/nlS8gfx3vxmbv7aEHZs0IeM791AbYJ80TmyF9YHzxpaORLtSU/Z
+x5FAq3P3VDylfZ+7DEd3Dtlh5RsUZU44xaeK7jK+BSWUoH+WCVkbBAhCa1BrlXp4
+9uz09k1DAgMBAAGjgZowgZcwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUDUk3RUJ3
+kCW6m2fb9txh0lNbxrwwHwYDVR0jBBgwFoAUhAmLVR99Lw8o15zsVE6fEZdV2bkw
+IgYDVR0RAQH/BBgwFoIUc2VydmVyLXJldm9rZWQudzEuZmkwFgYDVR0lAQH/BAww
+CgYIKwYBBQUHAwEwCwYDVR0PBAQDAgWgMA0GCSqGSIb3DQEBCwUAA4IBAQAixnII
+hKnpGXfqagZoQ4vncq+coke5b7bLEReJCkJSFFiePAH95/yiDYWltYwn1V6yRwUF
++Va2C+Io8x11XhPr7KB2K9ntmYQIbWRxE7YCgbPCfri2AJhPJurxZ1s1KibQyqj7
+6yH78dZaY0IBX7NZPfjgTZQ6OoJGAp2BLO/lRseZ9C9DrYX8LMoLa0gBrNf32g4W
+xBAYFIOchZB172afZULl54wWrPZgYddfoCHNioXUoPKOFw44XjESrCS1Z2GdFYQL
+/ISK1CmQPUsjSBlr9yYf/rm58W5wrOwxYL59b1h+wUdhp7BLsv1iBsWXQyg5pcVg
+UcBGnWvkGu0MplGK
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/iCA-server/server-revoked.req b/tests/hwsim/auth_serv/iCA-server/server-revoked.req
new file mode 100644 (file)
index 0000000..775c8a1
--- /dev/null
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIClDCCAXwCAQAwTzELMAkGA1UEBhMCRkkxETAPBgNVBAcMCEhlbHNpbmtpMQ4w
+DAYDVQQKDAV3MS5maTEdMBsGA1UEAwwUc2VydmVyLXJldm9rZWQudzEuZmkwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsXK4GNkpl4NsLPCgTCIuQZkNv
+yLI7+kG9GhAQ++kFarpCkE0uz7G5w3P1/KxMGOlEc2leLYNj0SnlWVWov7Aceg0X
+GLA4Ia/LbalrnaKIDhzuGqWfPCfq/o+blN8SPDS7v2zQbGtGrbz/iK7YTYufNFAl
+xJa+JUIGyLOOIaX9o4L5dHhGVo0L8MT6Gg71NCJT/UM3o0f9n6K80GAlqNuT9wyI
+/nlS8gfx3vxmbv7aEHZs0IeM791AbYJ80TmyF9YHzxpaORLtSU/Zx5FAq3P3VDyl
+fZ+7DEd3Dtlh5RsUZU44xaeK7jK+BSWUoH+WCVkbBAhCa1BrlXp49uz09k1DAgMB
+AAGgADANBgkqhkiG9w0BAQsFAAOCAQEAUcB51hlCnud4M8uQMv74+6VpPykm7srA
+f+kX1or6J1hRrpdUENDydBG/WavyKJmJ4FEb+SS3K+BDoLCObGwazOcFPvJWlT8S
+8h8vX5BC+zqLqqjtBv6BJ6Wkb3s/3yhMpGJtrEHShxQTagkqsqSV+nRcnqR/9Ufw
+/pHVZ+2sc0Q+dzY+aOmHw+XKkczeI73/j8odhf+a5yTyt6DmUgPRsCOhrBPAlakb
+rHzhfnziYI2pS4/q8Ok5LyFAiBjYp5HFvHEwfjb/3o4bLFTpbDDsJoeyX0ddFFhb
+fZUhqGHYHMIGR5RXJ685RXg39f7PN8/YPIq4wAjGb9qpkwCbqUJPOA==
+-----END CERTIFICATE REQUEST-----
diff --git a/tests/hwsim/auth_serv/iCA-server/server-revoked_and_ica.pem b/tests/hwsim/auth_serv/iCA-server/server-revoked_and_ica.pem
new file mode 100644 (file)
index 0000000..fae468a
--- /dev/null
@@ -0,0 +1,155 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 15624081837803162867 (0xd8d3e3a6cbe3ccf3)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=Root CA
+        Validity
+            Not Before: Dec 23 19:37:36 2015 GMT
+            Not After : Dec 22 19:37:36 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=Server Intermediate CA
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:de:58:ac:e3:d8:7e:40:f6:84:2a:49:24:49:5a:
+                    f7:c8:23:08:b9:6c:d9:07:01:69:8f:77:28:71:42:
+                    a2:eb:ae:86:10:c6:31:61:9a:14:88:44:0a:68:bf:
+                    6e:a2:46:41:e9:6f:a2:89:fb:0b:f3:e1:b8:30:bf:
+                    e5:80:5e:f9:61:8d:6e:ac:e2:f7:28:e7:9e:44:28:
+                    b8:e4:6e:87:76:a9:d7:ac:ed:11:3f:de:c3:dd:41:
+                    c3:45:82:09:c3:a7:4c:e6:df:2b:88:1e:44:ce:e2:
+                    a7:29:53:f6:13:96:ad:6c:2e:93:00:28:42:77:bc:
+                    73:6e:86:e7:5b:e8:eb:e9:37:1d:63:e7:ea:05:5a:
+                    71:28:f0:81:0b:4c:3f:dd:73:f8:db:13:a8:f0:5f:
+                    6f:6f:e5:1b:c7:94:7f:57:c5:dc:66:26:0c:5a:71:
+                    7a:e3:d2:3e:7a:a6:59:46:03:61:78:89:84:3d:ef:
+                    22:9c:f8:c2:22:75:c4:0c:ef:fb:e4:fa:6f:b8:11:
+                    db:aa:92:9b:6c:23:4e:6e:e5:55:d2:41:47:18:95:
+                    c6:7d:17:be:6d:ab:39:a1:38:61:fd:f9:22:95:69:
+                    f3:9e:28:fd:8a:c8:58:72:3c:91:c2:22:d9:fb:b2:
+                    54:0f:9a:17:27:88:df:60:f5:de:fc:95:9f:25:c6:
+                    64:81
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                84:09:8B:55:1F:7D:2F:0F:28:D7:9C:EC:54:4E:9F:11:97:55:D9:B9
+            X509v3 Authority Key Identifier: 
+                keyid:B8:92:DE:FD:8A:18:B3:30:C3:9F:55:F3:33:5D:B4:C8:29:8A:41:14
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE, pathlen:0
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+    Signature Algorithm: sha256WithRSAEncryption
+         bd:22:63:3d:a7:e5:ce:c9:f5:66:1f:77:5f:d5:24:e3:68:dc:
+         a4:07:80:3e:5e:b1:2c:96:88:39:ad:00:4c:aa:9d:0b:ed:f3:
+         6d:df:9d:2f:97:d2:77:8b:ba:d0:9c:0f:a6:5e:60:b8:0f:e1:
+         96:b1:61:25:48:69:81:64:a8:5c:82:58:0b:f3:d0:a9:4e:8b:
+         90:fc:2f:67:57:da:72:dc:3c:eb:c2:20:19:05:8d:42:0d:14:
+         cf:00:db:59:00:ea:f0:76:3e:ca:85:b1:05:e5:b8:5f:0b:46:
+         c7:3c:a1:d9:5c:4d:b9:24:e7:d6:2b:3d:0d:eb:c3:88:d8:3a:
+         f6:60
+-----BEGIN CERTIFICATE-----
+MIIC1TCCAj6gAwIBAgIJANjT46bL48zzMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNTEy
+MjMxOTM3MzZaFw0yNTEyMjIxOTM3MzZaMD4xCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+DAV3MS5maTEfMB0GA1UEAwwWU2VydmVyIEludGVybWVkaWF0ZSBDQTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAN5YrOPYfkD2hCpJJEla98gjCLls2QcB
+aY93KHFCouuuhhDGMWGaFIhECmi/bqJGQelvoon7C/PhuDC/5YBe+WGNbqzi9yjn
+nkQouORuh3ap16ztET/ew91Bw0WCCcOnTObfK4geRM7ipylT9hOWrWwukwAoQne8
+c26G51vo6+k3HWPn6gVacSjwgQtMP91z+NsTqPBfb2/lG8eUf1fF3GYmDFpxeuPS
+PnqmWUYDYXiJhD3vIpz4wiJ1xAzv++T6b7gR26qSm2wjTm7lVdJBRxiVxn0Xvm2r
+OaE4Yf35IpVp854o/YrIWHI8kcIi2fuyVA+aFyeI32D13vyVnyXGZIECAwEAAaNm
+MGQwHQYDVR0OBBYEFIQJi1UffS8PKNec7FROnxGXVdm5MB8GA1UdIwQYMBaAFLiS
+3v2KGLMww59V8zNdtMgpikEUMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/
+BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4GBAL0iYz2n5c7J9WYfd1/VJONo3KQHgD5e
+sSyWiDmtAEyqnQvt823fnS+X0neLutCcD6ZeYLgP4ZaxYSVIaYFkqFyCWAvz0KlO
+i5D8L2dX2nLcPOvCIBkFjUINFM8A21kA6vB2PsqFsQXluF8LRsc8odlcTbkk59Yr
+PQ3rw4jYOvZg
+-----END CERTIFICATE-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 9232555434986539705 (0x8020a0407f798ab9)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=Server Intermediate CA
+        Validity
+            Not Before: Dec 23 19:37:36 2015 GMT
+            Not After : Dec 20 19:37:36 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=server-revoked.w1.fi
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:ac:5c:ae:06:36:4a:65:e0:db:0b:3c:28:13:08:
+                    8b:90:66:43:6f:c8:b2:3b:fa:41:bd:1a:10:10:fb:
+                    e9:05:6a:ba:42:90:4d:2e:cf:b1:b9:c3:73:f5:fc:
+                    ac:4c:18:e9:44:73:69:5e:2d:83:63:d1:29:e5:59:
+                    55:a8:bf:b0:1c:7a:0d:17:18:b0:38:21:af:cb:6d:
+                    a9:6b:9d:a2:88:0e:1c:ee:1a:a5:9f:3c:27:ea:fe:
+                    8f:9b:94:df:12:3c:34:bb:bf:6c:d0:6c:6b:46:ad:
+                    bc:ff:88:ae:d8:4d:8b:9f:34:50:25:c4:96:be:25:
+                    42:06:c8:b3:8e:21:a5:fd:a3:82:f9:74:78:46:56:
+                    8d:0b:f0:c4:fa:1a:0e:f5:34:22:53:fd:43:37:a3:
+                    47:fd:9f:a2:bc:d0:60:25:a8:db:93:f7:0c:88:fe:
+                    79:52:f2:07:f1:de:fc:66:6e:fe:da:10:76:6c:d0:
+                    87:8c:ef:dd:40:6d:82:7c:d1:39:b2:17:d6:07:cf:
+                    1a:5a:39:12:ed:49:4f:d9:c7:91:40:ab:73:f7:54:
+                    3c:a5:7d:9f:bb:0c:47:77:0e:d9:61:e5:1b:14:65:
+                    4e:38:c5:a7:8a:ee:32:be:05:25:94:a0:7f:96:09:
+                    59:1b:04:08:42:6b:50:6b:95:7a:78:f6:ec:f4:f6:
+                    4d:43
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                0D:49:37:45:42:77:90:25:BA:9B:67:DB:F6:DC:61:D2:53:5B:C6:BC
+            X509v3 Authority Key Identifier: 
+                keyid:84:09:8B:55:1F:7D:2F:0F:28:D7:9C:EC:54:4E:9F:11:97:55:D9:B9
+
+            X509v3 Subject Alternative Name: critical
+                DNS:server-revoked.w1.fi
+            X509v3 Extended Key Usage: critical
+                TLS Web Server Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: sha256WithRSAEncryption
+         22:c6:72:08:84:a9:e9:19:77:ea:6a:06:68:43:8b:e7:72:af:
+         9c:a2:47:b9:6f:b6:cb:11:17:89:0a:42:52:14:58:9e:3c:01:
+         fd:e7:fc:a2:0d:85:a5:b5:8c:27:d5:5e:b2:47:05:05:f9:56:
+         b6:0b:e2:28:f3:1d:75:5e:13:eb:ec:a0:76:2b:d9:ed:99:84:
+         08:6d:64:71:13:b6:02:81:b3:c2:7e:b8:b6:00:98:4f:26:ea:
+         f1:67:5b:35:2a:26:d0:ca:a8:fb:eb:21:fb:f1:d6:5a:63:42:
+         01:5f:b3:59:3d:f8:e0:4d:94:3a:3a:82:46:02:9d:81:2c:ef:
+         e5:46:c7:99:f4:2f:43:ad:85:fc:2c:ca:0b:6b:48:01:ac:d7:
+         f7:da:0e:16:c4:10:18:14:83:9c:85:90:75:ef:66:9f:65:42:
+         e5:e7:8c:16:ac:f6:60:61:d7:5f:a0:21:cd:8a:85:d4:a0:f2:
+         8e:17:0e:38:5e:31:12:ac:24:b5:67:61:9d:15:84:0b:fc:84:
+         8a:d4:29:90:3d:4b:23:48:19:6b:f7:26:1f:fe:b9:b9:f1:6e:
+         70:ac:ec:31:60:be:7d:6f:58:7e:c1:47:61:a7:b0:4b:b2:fd:
+         62:06:c5:97:43:28:39:a5:c5:60:51:c0:46:9d:6b:e4:1a:ed:
+         0c:a6:51:8a
+-----BEGIN CERTIFICATE-----
+MIIDmDCCAoCgAwIBAgIJAIAgoEB/eYq5MA0GCSqGSIb3DQEBCwUAMD4xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEfMB0GA1UEAwwWU2VydmVyIEludGVybWVk
+aWF0ZSBDQTAeFw0xNTEyMjMxOTM3MzZaFw0yNTEyMjAxOTM3MzZaMDwxCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEdMBsGA1UEAwwUc2VydmVyLXJldm9rZWQu
+dzEuZmkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsXK4GNkpl4NsL
+PCgTCIuQZkNvyLI7+kG9GhAQ++kFarpCkE0uz7G5w3P1/KxMGOlEc2leLYNj0Snl
+WVWov7Aceg0XGLA4Ia/LbalrnaKIDhzuGqWfPCfq/o+blN8SPDS7v2zQbGtGrbz/
+iK7YTYufNFAlxJa+JUIGyLOOIaX9o4L5dHhGVo0L8MT6Gg71NCJT/UM3o0f9n6K8
+0GAlqNuT9wyI/nlS8gfx3vxmbv7aEHZs0IeM791AbYJ80TmyF9YHzxpaORLtSU/Z
+x5FAq3P3VDylfZ+7DEd3Dtlh5RsUZU44xaeK7jK+BSWUoH+WCVkbBAhCa1BrlXp4
+9uz09k1DAgMBAAGjgZowgZcwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUDUk3RUJ3
+kCW6m2fb9txh0lNbxrwwHwYDVR0jBBgwFoAUhAmLVR99Lw8o15zsVE6fEZdV2bkw
+IgYDVR0RAQH/BBgwFoIUc2VydmVyLXJldm9rZWQudzEuZmkwFgYDVR0lAQH/BAww
+CgYIKwYBBQUHAwEwCwYDVR0PBAQDAgWgMA0GCSqGSIb3DQEBCwUAA4IBAQAixnII
+hKnpGXfqagZoQ4vncq+coke5b7bLEReJCkJSFFiePAH95/yiDYWltYwn1V6yRwUF
++Va2C+Io8x11XhPr7KB2K9ntmYQIbWRxE7YCgbPCfri2AJhPJurxZ1s1KibQyqj7
+6yH78dZaY0IBX7NZPfjgTZQ6OoJGAp2BLO/lRseZ9C9DrYX8LMoLa0gBrNf32g4W
+xBAYFIOchZB172afZULl54wWrPZgYddfoCHNioXUoPKOFw44XjESrCS1Z2GdFYQL
+/ISK1CmQPUsjSBlr9yYf/rm58W5wrOwxYL59b1h+wUdhp7BLsv1iBsWXQyg5pcVg
+UcBGnWvkGu0MplGK
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/iCA-server/server.key b/tests/hwsim/auth_serv/iCA-server/server.key
new file mode 100644 (file)
index 0000000..e817ad8
--- /dev/null
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDkiKWTAlu8VGhG
++nN9MzBHRVxJXzxRX5v+xRQQJj0P48KyF4TTPhKosnsCGoqL6fRBHvzzSS3G1Ign
+gdCG87nACiooRQAywxgi9pk38XSNrFRHc+W20+f4gJl19RkZ6xlw35JTsWE4/3/P
+i73hf1Bb0JUwozdrinIGp+g54qR4Q5iRzTCINFuqnqKfJtXhW4ZNAaTCZc0nlL7i
+9XNdxGCY8XURlAkNnQR/7xqdX/BKP4jXdi6b1irGlAk3CjckkpGdGA/qTtTknUU4
+WrrY37YVb6z/bEGs18AKVeyByppZQFWLpHcT3/rDte7vh0GNlNDAlkG0OgS2a2pW
+k/RnfifhAgMBAAECggEAA+GSNknu9ubUEoiEV5b79enmpFRauOMPyibcrV2I4fEz
+SET/+3ptZLILRsDeo3uoq0Z0c0lF3r+TRGB/Axu2ht1lU+PAGhyYF1fqyDlwiktn
+7wK33wAAS4cblBZCg98rQnB5krRLe2VTbVnpMqAv5C9JqVbMRSZHw3csiXcg5e3v
+urH5A90pwFY/1DG68JS+HCLxvorO5EIfeTSBg1F54FHBCQ6Yjr232uXAUez5hv5/
+zX6oxw2zarKMgNiosy5FCoGEUECCfvM2tiXjfZ0DBmZgF/c6Alg+J8gYFVJzSX+x
+xAyL9o3LYddSdDnGBiMm4SU8oUxvnUgrZ+xhnyL69QKBgQD9717EmTLKBna4wX+d
+PM03yIv2ZpFESd4VuxZMyTOO64CMD75n1V/r1V44xIQa7M5QwfD+NmTjW/QyJ0EN
+F5mJYavXc56nlV4wVQJC2/NnyOScjKEIXu/QmEPwTm/NqEqCFs6XGpftigjB+FIO
+Te/PmOVFSDCE+JkOF3Fls55iMwKBgQDmZGW/duaEL4qMnDO51hSz+qv9mZNXoPzg
+DWzmraOikp1zSTjaLzRy6w8bbHTqTZDG68hJ/knW2boD0pDqmuUzS6ADnV7P0fVT
+mOolwmKdGO3axyIsStuhPKaaHv28X0+y2qhUkK7hYJ2yeZIQ/259D75g0BNozjO5
+1sKEsW+BmwKBgBgZu9jU4WkjK+llFAOMXb3Jnt8H5QmiKR3O39Lx1Z7e4xhn9h5M
+tgnf+k1Q+WjEyOAJSCIYb4LUm1yXNSlU8BGF35VXN9uX5ZSYvNoznepfurLQ9geh
+WwllKi2IhDv0mP23xGu67mhxDVu7ga4x32zIihoFO/Wi0oPv3adVYNbZAoGBAOMF
+VwVdYjQqrHl1ibq66teWUFeqNvgIGGWmlQKRY0bU9fUd17mW/jWmzdIWAvbFy71X
+pJrUyWm+TX9qw4WJcAQlpt0o+r4Jg5YGfeMLMiTe5bHIuzGt6dFtdDU2CIzP1jbF
+I02A6/IFRB8TkAzTxcnR86RuJFIHrgyXREGAngG1AoGBAOR/fBPsVAf2MsfGyX7l
+JpHkHgfmAldfRammmGxV2c+NJ/cWjkN/1p8KaiqINP08FemC7Rxvu8Nhm50qOLRM
+iq2KeDCaHoUp9waX7T+WzKbT+jEdcyXeu2DlN8AIyTNjDrVyZil0NbZfQFbR8nWR
+0VX+Eq8Oxrl+pRza/6f62K7s
+-----END PRIVATE KEY-----
diff --git a/tests/hwsim/auth_serv/iCA-server/server.pem b/tests/hwsim/auth_serv/iCA-server/server.pem
new file mode 100644 (file)
index 0000000..ebcbde3
--- /dev/null
@@ -0,0 +1,84 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 9232555434986539704 (0x8020a0407f798ab8)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=Server Intermediate CA
+        Validity
+            Not Before: Dec 23 19:37:36 2015 GMT
+            Not After : Dec 20 19:37:36 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=server.w1.fi
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:e4:88:a5:93:02:5b:bc:54:68:46:fa:73:7d:33:
+                    30:47:45:5c:49:5f:3c:51:5f:9b:fe:c5:14:10:26:
+                    3d:0f:e3:c2:b2:17:84:d3:3e:12:a8:b2:7b:02:1a:
+                    8a:8b:e9:f4:41:1e:fc:f3:49:2d:c6:d4:88:27:81:
+                    d0:86:f3:b9:c0:0a:2a:28:45:00:32:c3:18:22:f6:
+                    99:37:f1:74:8d:ac:54:47:73:e5:b6:d3:e7:f8:80:
+                    99:75:f5:19:19:eb:19:70:df:92:53:b1:61:38:ff:
+                    7f:cf:8b:bd:e1:7f:50:5b:d0:95:30:a3:37:6b:8a:
+                    72:06:a7:e8:39:e2:a4:78:43:98:91:cd:30:88:34:
+                    5b:aa:9e:a2:9f:26:d5:e1:5b:86:4d:01:a4:c2:65:
+                    cd:27:94:be:e2:f5:73:5d:c4:60:98:f1:75:11:94:
+                    09:0d:9d:04:7f:ef:1a:9d:5f:f0:4a:3f:88:d7:76:
+                    2e:9b:d6:2a:c6:94:09:37:0a:37:24:92:91:9d:18:
+                    0f:ea:4e:d4:e4:9d:45:38:5a:ba:d8:df:b6:15:6f:
+                    ac:ff:6c:41:ac:d7:c0:0a:55:ec:81:ca:9a:59:40:
+                    55:8b:a4:77:13:df:fa:c3:b5:ee:ef:87:41:8d:94:
+                    d0:c0:96:41:b4:3a:04:b6:6b:6a:56:93:f4:67:7e:
+                    27:e1
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                4B:81:85:B4:88:41:0D:D4:15:D3:48:0E:F4:A9:99:14:2D:B1:DB:93
+            X509v3 Authority Key Identifier: 
+                keyid:84:09:8B:55:1F:7D:2F:0F:28:D7:9C:EC:54:4E:9F:11:97:55:D9:B9
+
+            X509v3 Subject Alternative Name: critical
+                DNS:server.w1.fi
+            X509v3 Extended Key Usage: critical
+                TLS Web Server Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: sha256WithRSAEncryption
+         49:2a:14:22:16:2c:12:f5:4e:06:f3:c2:1e:ac:54:07:5d:86:
+         16:3e:6c:a0:73:e1:a6:d7:c3:49:1f:80:0d:b6:54:22:77:ce:
+         39:dd:f6:f6:9f:62:ff:d5:27:7f:c3:92:73:b9:a7:ce:87:5a:
+         e3:bc:52:b3:0a:99:eb:91:56:b6:78:01:c3:0e:4b:ca:8a:04:
+         ee:5c:56:05:ef:7a:cb:21:f9:eb:8a:38:12:50:c7:6e:a8:1f:
+         0e:81:81:a6:2d:ea:35:94:24:db:76:77:df:ea:41:4c:af:7e:
+         29:9d:d5:e6:e3:12:78:19:92:ed:35:b9:99:19:a9:d6:cb:f8:
+         a7:21:fb:8e:a7:39:dc:e1:ab:3d:ba:12:87:ba:1c:08:e6:8a:
+         21:96:44:44:8a:61:0f:70:00:d0:cb:63:93:a4:fa:cc:75:a3:
+         fd:e8:af:33:24:80:4a:d9:b9:2a:a1:20:0b:62:0b:17:6c:9a:
+         7c:8b:fd:9e:ff:be:b2:51:5e:e9:3a:cc:28:22:63:44:69:7f:
+         6d:1f:08:14:a4:32:d0:1f:f9:c3:8d:28:1a:76:12:00:3c:b3:
+         38:13:ca:67:17:79:c6:de:5d:b7:9d:f8:e3:64:f7:b3:a0:5c:
+         e5:6e:fc:10:f3:53:d6:70:38:c2:6f:87:ab:07:1c:64:ff:30:
+         d8:3a:1e:75
+-----BEGIN CERTIFICATE-----
+MIIDiDCCAnCgAwIBAgIJAIAgoEB/eYq4MA0GCSqGSIb3DQEBCwUAMD4xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEfMB0GA1UEAwwWU2VydmVyIEludGVybWVk
+aWF0ZSBDQTAeFw0xNTEyMjMxOTM3MzZaFw0yNTEyMjAxOTM3MzZaMDQxCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEVMBMGA1UEAwwMc2VydmVyLncxLmZpMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5IilkwJbvFRoRvpzfTMwR0Vc
+SV88UV+b/sUUECY9D+PCsheE0z4SqLJ7AhqKi+n0QR7880ktxtSIJ4HQhvO5wAoq
+KEUAMsMYIvaZN/F0jaxUR3PlttPn+ICZdfUZGesZcN+SU7FhOP9/z4u94X9QW9CV
+MKM3a4pyBqfoOeKkeEOYkc0wiDRbqp6inybV4VuGTQGkwmXNJ5S+4vVzXcRgmPF1
+EZQJDZ0Ef+8anV/wSj+I13Yum9YqxpQJNwo3JJKRnRgP6k7U5J1FOFq62N+2FW+s
+/2xBrNfAClXsgcqaWUBVi6R3E9/6w7Xu74dBjZTQwJZBtDoEtmtqVpP0Z34n4QID
+AQABo4GSMIGPMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFEuBhbSIQQ3UFdNIDvSp
+mRQtsduTMB8GA1UdIwQYMBaAFIQJi1UffS8PKNec7FROnxGXVdm5MBoGA1UdEQEB
+/wQQMA6CDHNlcnZlci53MS5maTAWBgNVHSUBAf8EDDAKBggrBgEFBQcDATALBgNV
+HQ8EBAMCBaAwDQYJKoZIhvcNAQELBQADggEBAEkqFCIWLBL1Tgbzwh6sVAddhhY+
+bKBz4abXw0kfgA22VCJ3zjnd9vafYv/VJ3/DknO5p86HWuO8UrMKmeuRVrZ4AcMO
+S8qKBO5cVgXvessh+euKOBJQx26oHw6BgaYt6jWUJNt2d9/qQUyvfimd1ebjEngZ
+ku01uZkZqdbL+Kch+46nOdzhqz26Eoe6HAjmiiGWRESKYQ9wANDLY5Ok+sx1o/3o
+rzMkgErZuSqhIAtiCxdsmnyL/Z7/vrJRXuk6zCgiY0Rpf20fCBSkMtAf+cONKBp2
+EgA8szgTymcXecbeXbed+ONk97OgXOVu/BDzU9ZwOMJvh6sHHGT/MNg6HnU=
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/iCA-server/server.req b/tests/hwsim/auth_serv/iCA-server/server.req
new file mode 100644 (file)
index 0000000..2db7cc1
--- /dev/null
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICjDCCAXQCAQAwRzELMAkGA1UEBhMCRkkxETAPBgNVBAcMCEhlbHNpbmtpMQ4w
+DAYDVQQKDAV3MS5maTEVMBMGA1UEAwwMc2VydmVyLncxLmZpMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5IilkwJbvFRoRvpzfTMwR0VcSV88UV+b/sUU
+ECY9D+PCsheE0z4SqLJ7AhqKi+n0QR7880ktxtSIJ4HQhvO5wAoqKEUAMsMYIvaZ
+N/F0jaxUR3PlttPn+ICZdfUZGesZcN+SU7FhOP9/z4u94X9QW9CVMKM3a4pyBqfo
+OeKkeEOYkc0wiDRbqp6inybV4VuGTQGkwmXNJ5S+4vVzXcRgmPF1EZQJDZ0Ef+8a
+nV/wSj+I13Yum9YqxpQJNwo3JJKRnRgP6k7U5J1FOFq62N+2FW+s/2xBrNfAClXs
+gcqaWUBVi6R3E9/6w7Xu74dBjZTQwJZBtDoEtmtqVpP0Z34n4QIDAQABoAAwDQYJ
+KoZIhvcNAQELBQADggEBAE+hOOVtzHJvvrjl21A/gmdj5kRHYCijOGJ53ipY9mFX
+aIK9+kJ0Jrlm9cZGbxwTMwJpAyk+7yPl3K0euoToXf+vdLnYds/HGRonN66pXqmD
+QRZXGp6j58mBcmfiU1OB+6XRcLsYITaOaU9AvJ0jg9wkHISrN5uxfDG9QH//YYQ6
+aWzBfjUPAa+2trlmvI4tpC+w7sDHLa5WB5yBDm7HZ6UGwU5R7aMIZn2Hpe1BZS1u
+Xo86qqJpbt6RvR5QEb6+79+8fmt3onQvZ28+wheUdcUin0G/JP7Lfo9/tNzU/29v
+YJopHLeK1zNc6+lBwRTJiDbLC726H5dqZgxu9NNl8zg=
+-----END CERTIFICATE REQUEST-----
diff --git a/tests/hwsim/auth_serv/iCA-server/server_and_ica.pem b/tests/hwsim/auth_serv/iCA-server/server_and_ica.pem
new file mode 100644 (file)
index 0000000..2e99179
--- /dev/null
@@ -0,0 +1,154 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 9232555434986539704 (0x8020a0407f798ab8)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=Server Intermediate CA
+        Validity
+            Not Before: Dec 23 19:37:36 2015 GMT
+            Not After : Dec 20 19:37:36 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=server.w1.fi
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:e4:88:a5:93:02:5b:bc:54:68:46:fa:73:7d:33:
+                    30:47:45:5c:49:5f:3c:51:5f:9b:fe:c5:14:10:26:
+                    3d:0f:e3:c2:b2:17:84:d3:3e:12:a8:b2:7b:02:1a:
+                    8a:8b:e9:f4:41:1e:fc:f3:49:2d:c6:d4:88:27:81:
+                    d0:86:f3:b9:c0:0a:2a:28:45:00:32:c3:18:22:f6:
+                    99:37:f1:74:8d:ac:54:47:73:e5:b6:d3:e7:f8:80:
+                    99:75:f5:19:19:eb:19:70:df:92:53:b1:61:38:ff:
+                    7f:cf:8b:bd:e1:7f:50:5b:d0:95:30:a3:37:6b:8a:
+                    72:06:a7:e8:39:e2:a4:78:43:98:91:cd:30:88:34:
+                    5b:aa:9e:a2:9f:26:d5:e1:5b:86:4d:01:a4:c2:65:
+                    cd:27:94:be:e2:f5:73:5d:c4:60:98:f1:75:11:94:
+                    09:0d:9d:04:7f:ef:1a:9d:5f:f0:4a:3f:88:d7:76:
+                    2e:9b:d6:2a:c6:94:09:37:0a:37:24:92:91:9d:18:
+                    0f:ea:4e:d4:e4:9d:45:38:5a:ba:d8:df:b6:15:6f:
+                    ac:ff:6c:41:ac:d7:c0:0a:55:ec:81:ca:9a:59:40:
+                    55:8b:a4:77:13:df:fa:c3:b5:ee:ef:87:41:8d:94:
+                    d0:c0:96:41:b4:3a:04:b6:6b:6a:56:93:f4:67:7e:
+                    27:e1
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                4B:81:85:B4:88:41:0D:D4:15:D3:48:0E:F4:A9:99:14:2D:B1:DB:93
+            X509v3 Authority Key Identifier: 
+                keyid:84:09:8B:55:1F:7D:2F:0F:28:D7:9C:EC:54:4E:9F:11:97:55:D9:B9
+
+            X509v3 Subject Alternative Name: critical
+                DNS:server.w1.fi
+            X509v3 Extended Key Usage: critical
+                TLS Web Server Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: sha256WithRSAEncryption
+         49:2a:14:22:16:2c:12:f5:4e:06:f3:c2:1e:ac:54:07:5d:86:
+         16:3e:6c:a0:73:e1:a6:d7:c3:49:1f:80:0d:b6:54:22:77:ce:
+         39:dd:f6:f6:9f:62:ff:d5:27:7f:c3:92:73:b9:a7:ce:87:5a:
+         e3:bc:52:b3:0a:99:eb:91:56:b6:78:01:c3:0e:4b:ca:8a:04:
+         ee:5c:56:05:ef:7a:cb:21:f9:eb:8a:38:12:50:c7:6e:a8:1f:
+         0e:81:81:a6:2d:ea:35:94:24:db:76:77:df:ea:41:4c:af:7e:
+         29:9d:d5:e6:e3:12:78:19:92:ed:35:b9:99:19:a9:d6:cb:f8:
+         a7:21:fb:8e:a7:39:dc:e1:ab:3d:ba:12:87:ba:1c:08:e6:8a:
+         21:96:44:44:8a:61:0f:70:00:d0:cb:63:93:a4:fa:cc:75:a3:
+         fd:e8:af:33:24:80:4a:d9:b9:2a:a1:20:0b:62:0b:17:6c:9a:
+         7c:8b:fd:9e:ff:be:b2:51:5e:e9:3a:cc:28:22:63:44:69:7f:
+         6d:1f:08:14:a4:32:d0:1f:f9:c3:8d:28:1a:76:12:00:3c:b3:
+         38:13:ca:67:17:79:c6:de:5d:b7:9d:f8:e3:64:f7:b3:a0:5c:
+         e5:6e:fc:10:f3:53:d6:70:38:c2:6f:87:ab:07:1c:64:ff:30:
+         d8:3a:1e:75
+-----BEGIN CERTIFICATE-----
+MIIDiDCCAnCgAwIBAgIJAIAgoEB/eYq4MA0GCSqGSIb3DQEBCwUAMD4xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEfMB0GA1UEAwwWU2VydmVyIEludGVybWVk
+aWF0ZSBDQTAeFw0xNTEyMjMxOTM3MzZaFw0yNTEyMjAxOTM3MzZaMDQxCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEVMBMGA1UEAwwMc2VydmVyLncxLmZpMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5IilkwJbvFRoRvpzfTMwR0Vc
+SV88UV+b/sUUECY9D+PCsheE0z4SqLJ7AhqKi+n0QR7880ktxtSIJ4HQhvO5wAoq
+KEUAMsMYIvaZN/F0jaxUR3PlttPn+ICZdfUZGesZcN+SU7FhOP9/z4u94X9QW9CV
+MKM3a4pyBqfoOeKkeEOYkc0wiDRbqp6inybV4VuGTQGkwmXNJ5S+4vVzXcRgmPF1
+EZQJDZ0Ef+8anV/wSj+I13Yum9YqxpQJNwo3JJKRnRgP6k7U5J1FOFq62N+2FW+s
+/2xBrNfAClXsgcqaWUBVi6R3E9/6w7Xu74dBjZTQwJZBtDoEtmtqVpP0Z34n4QID
+AQABo4GSMIGPMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFEuBhbSIQQ3UFdNIDvSp
+mRQtsduTMB8GA1UdIwQYMBaAFIQJi1UffS8PKNec7FROnxGXVdm5MBoGA1UdEQEB
+/wQQMA6CDHNlcnZlci53MS5maTAWBgNVHSUBAf8EDDAKBggrBgEFBQcDATALBgNV
+HQ8EBAMCBaAwDQYJKoZIhvcNAQELBQADggEBAEkqFCIWLBL1Tgbzwh6sVAddhhY+
+bKBz4abXw0kfgA22VCJ3zjnd9vafYv/VJ3/DknO5p86HWuO8UrMKmeuRVrZ4AcMO
+S8qKBO5cVgXvessh+euKOBJQx26oHw6BgaYt6jWUJNt2d9/qQUyvfimd1ebjEngZ
+ku01uZkZqdbL+Kch+46nOdzhqz26Eoe6HAjmiiGWRESKYQ9wANDLY5Ok+sx1o/3o
+rzMkgErZuSqhIAtiCxdsmnyL/Z7/vrJRXuk6zCgiY0Rpf20fCBSkMtAf+cONKBp2
+EgA8szgTymcXecbeXbed+ONk97OgXOVu/BDzU9ZwOMJvh6sHHGT/MNg6HnU=
+-----END CERTIFICATE-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 15624081837803162867 (0xd8d3e3a6cbe3ccf3)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=Root CA
+        Validity
+            Not Before: Dec 23 19:37:36 2015 GMT
+            Not After : Dec 22 19:37:36 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=Server Intermediate CA
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:de:58:ac:e3:d8:7e:40:f6:84:2a:49:24:49:5a:
+                    f7:c8:23:08:b9:6c:d9:07:01:69:8f:77:28:71:42:
+                    a2:eb:ae:86:10:c6:31:61:9a:14:88:44:0a:68:bf:
+                    6e:a2:46:41:e9:6f:a2:89:fb:0b:f3:e1:b8:30:bf:
+                    e5:80:5e:f9:61:8d:6e:ac:e2:f7:28:e7:9e:44:28:
+                    b8:e4:6e:87:76:a9:d7:ac:ed:11:3f:de:c3:dd:41:
+                    c3:45:82:09:c3:a7:4c:e6:df:2b:88:1e:44:ce:e2:
+                    a7:29:53:f6:13:96:ad:6c:2e:93:00:28:42:77:bc:
+                    73:6e:86:e7:5b:e8:eb:e9:37:1d:63:e7:ea:05:5a:
+                    71:28:f0:81:0b:4c:3f:dd:73:f8:db:13:a8:f0:5f:
+                    6f:6f:e5:1b:c7:94:7f:57:c5:dc:66:26:0c:5a:71:
+                    7a:e3:d2:3e:7a:a6:59:46:03:61:78:89:84:3d:ef:
+                    22:9c:f8:c2:22:75:c4:0c:ef:fb:e4:fa:6f:b8:11:
+                    db:aa:92:9b:6c:23:4e:6e:e5:55:d2:41:47:18:95:
+                    c6:7d:17:be:6d:ab:39:a1:38:61:fd:f9:22:95:69:
+                    f3:9e:28:fd:8a:c8:58:72:3c:91:c2:22:d9:fb:b2:
+                    54:0f:9a:17:27:88:df:60:f5:de:fc:95:9f:25:c6:
+                    64:81
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                84:09:8B:55:1F:7D:2F:0F:28:D7:9C:EC:54:4E:9F:11:97:55:D9:B9
+            X509v3 Authority Key Identifier: 
+                keyid:B8:92:DE:FD:8A:18:B3:30:C3:9F:55:F3:33:5D:B4:C8:29:8A:41:14
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE, pathlen:0
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+    Signature Algorithm: sha256WithRSAEncryption
+         bd:22:63:3d:a7:e5:ce:c9:f5:66:1f:77:5f:d5:24:e3:68:dc:
+         a4:07:80:3e:5e:b1:2c:96:88:39:ad:00:4c:aa:9d:0b:ed:f3:
+         6d:df:9d:2f:97:d2:77:8b:ba:d0:9c:0f:a6:5e:60:b8:0f:e1:
+         96:b1:61:25:48:69:81:64:a8:5c:82:58:0b:f3:d0:a9:4e:8b:
+         90:fc:2f:67:57:da:72:dc:3c:eb:c2:20:19:05:8d:42:0d:14:
+         cf:00:db:59:00:ea:f0:76:3e:ca:85:b1:05:e5:b8:5f:0b:46:
+         c7:3c:a1:d9:5c:4d:b9:24:e7:d6:2b:3d:0d:eb:c3:88:d8:3a:
+         f6:60
+-----BEGIN CERTIFICATE-----
+MIIC1TCCAj6gAwIBAgIJANjT46bL48zzMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNTEy
+MjMxOTM3MzZaFw0yNTEyMjIxOTM3MzZaMD4xCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+DAV3MS5maTEfMB0GA1UEAwwWU2VydmVyIEludGVybWVkaWF0ZSBDQTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAN5YrOPYfkD2hCpJJEla98gjCLls2QcB
+aY93KHFCouuuhhDGMWGaFIhECmi/bqJGQelvoon7C/PhuDC/5YBe+WGNbqzi9yjn
+nkQouORuh3ap16ztET/ew91Bw0WCCcOnTObfK4geRM7ipylT9hOWrWwukwAoQne8
+c26G51vo6+k3HWPn6gVacSjwgQtMP91z+NsTqPBfb2/lG8eUf1fF3GYmDFpxeuPS
+PnqmWUYDYXiJhD3vIpz4wiJ1xAzv++T6b7gR26qSm2wjTm7lVdJBRxiVxn0Xvm2r
+OaE4Yf35IpVp854o/YrIWHI8kcIi2fuyVA+aFyeI32D13vyVnyXGZIECAwEAAaNm
+MGQwHQYDVR0OBBYEFIQJi1UffS8PKNec7FROnxGXVdm5MB8GA1UdIwQYMBaAFLiS
+3v2KGLMww59V8zNdtMgpikEUMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/
+BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4GBAL0iYz2n5c7J9WYfd1/VJONo3KQHgD5e
+sSyWiDmtAEyqnQvt823fnS+X0neLutCcD6ZeYLgP4ZaxYSVIaYFkqFyCWAvz0KlO
+i5D8L2dX2nLcPOvCIBkFjUINFM8A21kA6vB2PsqFsQXluF8LRsc8odlcTbkk59Yr
+PQ3rw4jYOvZg
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/iCA-user/ca-and-root.pem b/tests/hwsim/auth_serv/iCA-user/ca-and-root.pem
new file mode 100644 (file)
index 0000000..4fa1248
--- /dev/null
@@ -0,0 +1,125 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 15624081837803162868 (0xd8d3e3a6cbe3ccf4)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=Root CA
+        Validity
+            Not Before: Dec 23 19:37:36 2015 GMT
+            Not After : Dec 22 19:37:36 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=User Intermediate CA
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:c3:2a:0d:f4:66:23:5d:96:91:f7:a0:be:b1:b0:
+                    f7:9e:ae:ea:a6:72:91:f5:70:65:57:91:49:55:59:
+                    67:bb:d7:f5:9e:bc:66:b2:bf:cf:95:31:32:ae:db:
+                    9a:3b:43:e8:a5:8d:1f:8b:3b:e6:e8:e3:3b:b2:9d:
+                    f0:58:62:ea:a3:8a:6f:c8:ed:01:ca:27:74:1c:0e:
+                    9e:28:5c:43:98:db:14:b8:72:07:9f:6b:27:28:25:
+                    ce:a5:91:b7:b7:23:9a:35:ef:0e:b7:fc:9f:69:4d:
+                    10:2e:81:ab:9d:04:ba:2f:b4:eb:61:7d:fd:68:a1:
+                    11:6f:f4:16:42:16:99:20:38:24:04:2d:39:7c:74:
+                    67:14:b9:aa:26:7a:b2:d9:1e:ce:cd:8b:bc:8d:e3:
+                    c7:58:9c:4a:f9:3a:7e:6c:38:f8:5f:1c:ec:05:4c:
+                    e5:56:64:d4:08:d8:fa:db:17:d9:a1:e4:cf:b4:9d:
+                    df:99:50:ce:fa:a4:af:af:c6:f7:f2:0e:c2:c5:7b:
+                    6c:f9:6c:eb:17:e5:c8:6e:5a:bf:eb:a6:b8:c0:f7:
+                    43:81:88:c3:d8:aa:a9:60:ac:a7:45:3f:5d:cb:8d:
+                    6c:48:92:2b:04:5a:c4:a8:32:b3:e9:6f:fe:8d:2d:
+                    65:c0:ea:c5:09:b2:30:b1:a3:2e:db:22:8a:49:b1:
+                    fe:4f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                AC:C4:F6:07:9E:B2:E5:F1:66:7C:40:05:08:AA:DC:EF:8A:60:DA:C1
+            X509v3 Authority Key Identifier: 
+                keyid:B8:92:DE:FD:8A:18:B3:30:C3:9F:55:F3:33:5D:B4:C8:29:8A:41:14
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE, pathlen:0
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+    Signature Algorithm: sha256WithRSAEncryption
+         0d:60:2b:fa:00:f2:5a:90:31:96:50:c8:9e:7f:60:02:99:c6:
+         31:d4:93:86:9e:4c:24:15:b6:b2:31:49:21:79:ce:7f:92:86:
+         1e:83:d8:a0:37:05:1b:89:2b:ef:0b:83:21:b0:37:8d:2f:7b:
+         6b:7d:c6:04:1e:a2:c8:59:be:52:bf:47:ee:46:cb:45:8d:1f:
+         7a:e4:d4:e5:54:60:5f:46:b0:ac:68:8a:26:57:ea:48:45:c1:
+         07:7d:ee:10:9e:94:87:4c:7e:26:2e:f8:ad:03:e5:03:86:09:
+         3e:48:0c:e0:04:2f:22:b4:e0:3a:b0:72:8c:e2:40:d2:cd:fb:
+         8f:fa
+-----BEGIN CERTIFICATE-----
+MIIC0zCCAjygAwIBAgIJANjT46bL48z0MA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNTEy
+MjMxOTM3MzZaFw0yNTEyMjIxOTM3MzZaMDwxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+DAV3MS5maTEdMBsGA1UEAwwUVXNlciBJbnRlcm1lZGlhdGUgQ0EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDKg30ZiNdlpH3oL6xsPeeruqmcpH1cGVX
+kUlVWWe71/WevGayv8+VMTKu25o7Q+iljR+LO+bo4zuynfBYYuqjim/I7QHKJ3Qc
+Dp4oXEOY2xS4cgefaycoJc6lkbe3I5o17w63/J9pTRAugaudBLovtOthff1ooRFv
+9BZCFpkgOCQELTl8dGcUuaomerLZHs7Ni7yN48dYnEr5On5sOPhfHOwFTOVWZNQI
+2PrbF9mh5M+0nd+ZUM76pK+vxvfyDsLFe2z5bOsX5chuWr/rprjA90OBiMPYqqlg
+rKdFP13LjWxIkisEWsSoMrPpb/6NLWXA6sUJsjCxoy7bIopJsf5PAgMBAAGjZjBk
+MB0GA1UdDgQWBBSsxPYHnrLl8WZ8QAUIqtzvimDawTAfBgNVHSMEGDAWgBS4kt79
+ihizMMOfVfMzXbTIKYpBFDASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQE
+AwIBBjANBgkqhkiG9w0BAQsFAAOBgQANYCv6APJakDGWUMief2ACmcYx1JOGnkwk
+FbayMUkhec5/koYeg9igNwUbiSvvC4MhsDeNL3trfcYEHqLIWb5Sv0fuRstFjR96
+5NTlVGBfRrCsaIomV+pIRcEHfe4QnpSHTH4mLvitA+UDhgk+SAzgBC8itOA6sHKM
+4kDSzfuP+g==
+-----END CERTIFICATE-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 15624081837803162817 (0xd8d3e3a6cbe3ccc1)
+    Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=Root CA
+        Validity
+            Not Before: Jun 29 16:41:22 2013 GMT
+            Not After : Jun 27 16:41:22 2023 GMT
+        Subject: C=FI, O=w1.fi, CN=Root CA
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (1024 bit)
+                Modulus:
+                    00:be:1e:86:e4:79:03:c1:d1:94:d5:d4:b3:b1:28:
+                    90:76:fb:b8:a6:cd:6d:1c:d1:48:f4:08:9a:67:ff:
+                    f9:a6:54:b1:19:29:df:29:1b:cd:f1:6f:66:01:e7:
+                    db:79:ce:c0:39:2a:25:13:26:94:0c:2c:7b:5a:2c:
+                    81:0f:94:ee:51:d0:75:e6:46:db:17:46:a7:15:8b:
+                    0e:57:0f:b0:54:76:63:12:ca:86:18:bc:1a:c3:16:
+                    c0:70:09:d6:6b:43:39:b8:98:29:46:ac:cb:6a:ad:
+                    38:88:3b:07:dc:81:cd:3a:f6:1d:f6:2f:ef:1d:d7:
+                    ae:8a:b6:d1:e7:b3:15:02:b9
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                B8:92:DE:FD:8A:18:B3:30:C3:9F:55:F3:33:5D:B4:C8:29:8A:41:14
+            X509v3 Authority Key Identifier: 
+                keyid:B8:92:DE:FD:8A:18:B3:30:C3:9F:55:F3:33:5D:B4:C8:29:8A:41:14
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha1WithRSAEncryption
+         1a:cf:77:60:44:43:c4:55:0e:99:e0:89:aa:b9:d3:7b:32:b7:
+         5c:9c:7c:ca:fe:8c:d4:94:c6:5e:f3:83:19:5f:29:59:68:a4:
+         4f:dc:04:2e:b8:71:c0:6d:3b:ae:01:e4:b9:88:99:cc:ce:82:
+         be:6a:28:c2:ac:6a:94:c6:87:90:ed:85:3c:10:71:c5:ff:3c:
+         70:64:e2:41:62:31:ea:86:7b:11:8c:93:ea:c6:f3:f3:4e:f9:
+         d4:f2:81:90:d7:f4:fa:a1:91:6e:d4:dd:15:3e:26:3b:ac:1e:
+         c3:c2:1f:ed:bb:34:bf:cb:b2:67:c6:c6:51:e8:51:22:b4:f3:
+         92:e8
+-----BEGIN CERTIFICATE-----
+MIICLDCCAZWgAwIBAgIJANjT46bL48zBMA0GCSqGSIb3DQEBBQUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xMzA2
+MjkxNjQxMjJaFw0yMzA2MjcxNjQxMjJaMC8xCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+DAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
+gYkCgYEAvh6G5HkDwdGU1dSzsSiQdvu4ps1tHNFI9AiaZ//5plSxGSnfKRvN8W9m
+Aefbec7AOSolEyaUDCx7WiyBD5TuUdB15kbbF0anFYsOVw+wVHZjEsqGGLwawxbA
+cAnWa0M5uJgpRqzLaq04iDsH3IHNOvYd9i/vHdeuirbR57MVArkCAwEAAaNQME4w
+HQYDVR0OBBYEFLiS3v2KGLMww59V8zNdtMgpikEUMB8GA1UdIwQYMBaAFLiS3v2K
+GLMww59V8zNdtMgpikEUMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEA
+Gs93YERDxFUOmeCJqrnTezK3XJx8yv6M1JTGXvODGV8pWWikT9wELrhxwG07rgHk
+uYiZzM6CvmoowqxqlMaHkO2FPBBxxf88cGTiQWIx6oZ7EYyT6sbz80751PKBkNf0
++qGRbtTdFT4mO6wew8If7bs0v8uyZ8bGUehRIrTzkug=
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/iCA-user/cacert.pem b/tests/hwsim/auth_serv/iCA-user/cacert.pem
new file mode 100644 (file)
index 0000000..9f2dd7b
--- /dev/null
@@ -0,0 +1,70 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 15624081837803162868 (0xd8d3e3a6cbe3ccf4)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=Root CA
+        Validity
+            Not Before: Dec 23 19:37:36 2015 GMT
+            Not After : Dec 22 19:37:36 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=User Intermediate CA
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:c3:2a:0d:f4:66:23:5d:96:91:f7:a0:be:b1:b0:
+                    f7:9e:ae:ea:a6:72:91:f5:70:65:57:91:49:55:59:
+                    67:bb:d7:f5:9e:bc:66:b2:bf:cf:95:31:32:ae:db:
+                    9a:3b:43:e8:a5:8d:1f:8b:3b:e6:e8:e3:3b:b2:9d:
+                    f0:58:62:ea:a3:8a:6f:c8:ed:01:ca:27:74:1c:0e:
+                    9e:28:5c:43:98:db:14:b8:72:07:9f:6b:27:28:25:
+                    ce:a5:91:b7:b7:23:9a:35:ef:0e:b7:fc:9f:69:4d:
+                    10:2e:81:ab:9d:04:ba:2f:b4:eb:61:7d:fd:68:a1:
+                    11:6f:f4:16:42:16:99:20:38:24:04:2d:39:7c:74:
+                    67:14:b9:aa:26:7a:b2:d9:1e:ce:cd:8b:bc:8d:e3:
+                    c7:58:9c:4a:f9:3a:7e:6c:38:f8:5f:1c:ec:05:4c:
+                    e5:56:64:d4:08:d8:fa:db:17:d9:a1:e4:cf:b4:9d:
+                    df:99:50:ce:fa:a4:af:af:c6:f7:f2:0e:c2:c5:7b:
+                    6c:f9:6c:eb:17:e5:c8:6e:5a:bf:eb:a6:b8:c0:f7:
+                    43:81:88:c3:d8:aa:a9:60:ac:a7:45:3f:5d:cb:8d:
+                    6c:48:92:2b:04:5a:c4:a8:32:b3:e9:6f:fe:8d:2d:
+                    65:c0:ea:c5:09:b2:30:b1:a3:2e:db:22:8a:49:b1:
+                    fe:4f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                AC:C4:F6:07:9E:B2:E5:F1:66:7C:40:05:08:AA:DC:EF:8A:60:DA:C1
+            X509v3 Authority Key Identifier: 
+                keyid:B8:92:DE:FD:8A:18:B3:30:C3:9F:55:F3:33:5D:B4:C8:29:8A:41:14
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE, pathlen:0
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+    Signature Algorithm: sha256WithRSAEncryption
+         0d:60:2b:fa:00:f2:5a:90:31:96:50:c8:9e:7f:60:02:99:c6:
+         31:d4:93:86:9e:4c:24:15:b6:b2:31:49:21:79:ce:7f:92:86:
+         1e:83:d8:a0:37:05:1b:89:2b:ef:0b:83:21:b0:37:8d:2f:7b:
+         6b:7d:c6:04:1e:a2:c8:59:be:52:bf:47:ee:46:cb:45:8d:1f:
+         7a:e4:d4:e5:54:60:5f:46:b0:ac:68:8a:26:57:ea:48:45:c1:
+         07:7d:ee:10:9e:94:87:4c:7e:26:2e:f8:ad:03:e5:03:86:09:
+         3e:48:0c:e0:04:2f:22:b4:e0:3a:b0:72:8c:e2:40:d2:cd:fb:
+         8f:fa
+-----BEGIN CERTIFICATE-----
+MIIC0zCCAjygAwIBAgIJANjT46bL48z0MA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNTEy
+MjMxOTM3MzZaFw0yNTEyMjIxOTM3MzZaMDwxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+DAV3MS5maTEdMBsGA1UEAwwUVXNlciBJbnRlcm1lZGlhdGUgQ0EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDKg30ZiNdlpH3oL6xsPeeruqmcpH1cGVX
+kUlVWWe71/WevGayv8+VMTKu25o7Q+iljR+LO+bo4zuynfBYYuqjim/I7QHKJ3Qc
+Dp4oXEOY2xS4cgefaycoJc6lkbe3I5o17w63/J9pTRAugaudBLovtOthff1ooRFv
+9BZCFpkgOCQELTl8dGcUuaomerLZHs7Ni7yN48dYnEr5On5sOPhfHOwFTOVWZNQI
+2PrbF9mh5M+0nd+ZUM76pK+vxvfyDsLFe2z5bOsX5chuWr/rprjA90OBiMPYqqlg
+rKdFP13LjWxIkisEWsSoMrPpb/6NLWXA6sUJsjCxoy7bIopJsf5PAgMBAAGjZjBk
+MB0GA1UdDgQWBBSsxPYHnrLl8WZ8QAUIqtzvimDawTAfBgNVHSMEGDAWgBS4kt79
+ihizMMOfVfMzXbTIKYpBFDASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQE
+AwIBBjANBgkqhkiG9w0BAQsFAAOBgQANYCv6APJakDGWUMief2ACmcYx1JOGnkwk
+FbayMUkhec5/koYeg9igNwUbiSvvC4MhsDeNL3trfcYEHqLIWb5Sv0fuRstFjR96
+5NTlVGBfRrCsaIomV+pIRcEHfe4QnpSHTH4mLvitA+UDhgk+SAzgBC8itOA6sHKM
+4kDSzfuP+g==
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/iCA-user/careq.pem b/tests/hwsim/auth_serv/iCA-user/careq.pem
new file mode 100644 (file)
index 0000000..887c80c
--- /dev/null
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIClDCCAXwCAQAwTzELMAkGA1UEBhMCRkkxETAPBgNVBAcMCEhlbHNpbmtpMQ4w
+DAYDVQQKDAV3MS5maTEdMBsGA1UEAwwUVXNlciBJbnRlcm1lZGlhdGUgQ0EwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDKg30ZiNdlpH3oL6xsPeeruqm
+cpH1cGVXkUlVWWe71/WevGayv8+VMTKu25o7Q+iljR+LO+bo4zuynfBYYuqjim/I
+7QHKJ3QcDp4oXEOY2xS4cgefaycoJc6lkbe3I5o17w63/J9pTRAugaudBLovtOth
+ff1ooRFv9BZCFpkgOCQELTl8dGcUuaomerLZHs7Ni7yN48dYnEr5On5sOPhfHOwF
+TOVWZNQI2PrbF9mh5M+0nd+ZUM76pK+vxvfyDsLFe2z5bOsX5chuWr/rprjA90OB
+iMPYqqlgrKdFP13LjWxIkisEWsSoMrPpb/6NLWXA6sUJsjCxoy7bIopJsf5PAgMB
+AAGgADANBgkqhkiG9w0BAQsFAAOCAQEAKYOesAY0nFSXY1Ez8q5cGRUa0YZWic1l
+NwF05zIFoD3loCWRiayzINJqwXvUO29X0c8W35hTIGHyGUzcc0iwtrjphlmpuimN
+AzL+NG1+TwfEQi+LL+e0lJnl2PIZkIN4cQDgTSdejU40sNRPWzD8w8EYHYAOJ4oU
+0TXfrIRJWBDZKFtjO2fcknf1beGN79ZOHxc6pCFdZ7pM2w3+mKbfysnVBZkDwavG
+SlIdL23QcD3Uj0vOrU+oOSGQKXamZrjjpmu647bcQ5XQr8kZbXWu6A4G24bxZ2rw
+S7Z7DVvLqGxJgSl8b72otGJqkszHiul2ZKHy25flrtGM0SBU+k9FEQ==
+-----END CERTIFICATE REQUEST-----
diff --git a/tests/hwsim/auth_serv/iCA-user/index.txt b/tests/hwsim/auth_serv/iCA-user/index.txt
new file mode 100644 (file)
index 0000000..61be730
--- /dev/null
@@ -0,0 +1 @@
+V      251220193736Z           E153BA3A7605DA1E        unknown /C=FI/O=w1.fi/CN=user.w1.fi
diff --git a/tests/hwsim/auth_serv/iCA-user/index.txt.attr b/tests/hwsim/auth_serv/iCA-user/index.txt.attr
new file mode 100644 (file)
index 0000000..8f7e63a
--- /dev/null
@@ -0,0 +1 @@
+unique_subject = yes
diff --git a/tests/hwsim/auth_serv/iCA-user/newcerts/E153BA3A7605DA1E.pem b/tests/hwsim/auth_serv/iCA-user/newcerts/E153BA3A7605DA1E.pem
new file mode 100644 (file)
index 0000000..296060a
--- /dev/null
@@ -0,0 +1,84 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 16236525841851734558 (0xe153ba3a7605da1e)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=User Intermediate CA
+        Validity
+            Not Before: Dec 23 19:37:36 2015 GMT
+            Not After : Dec 20 19:37:36 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=user.w1.fi
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:c0:86:20:e5:06:5a:a8:47:2d:c9:5e:25:24:f7:
+                    bf:a6:b6:44:50:99:8c:95:b5:6a:ad:74:b6:ba:ee:
+                    31:5e:b2:20:60:9a:b4:93:55:6d:15:0b:dc:5a:27:
+                    3f:df:c1:92:18:59:66:10:eb:47:1c:35:1f:08:dd:
+                    eb:25:bd:21:9c:2d:48:34:5f:97:18:dc:83:28:db:
+                    14:8c:16:3b:5a:36:6a:50:63:e9:3b:e0:37:fd:f6:
+                    a0:d6:40:af:ef:1e:99:1d:88:c1:4f:4b:92:25:53:
+                    28:cb:c4:b7:ce:ca:ca:26:af:2d:f7:e4:62:79:48:
+                    49:6a:82:33:b0:a6:c6:a5:17:33:88:93:77:36:b2:
+                    77:61:e0:55:de:2e:75:15:92:4c:e7:bf:11:ea:33:
+                    03:1e:4a:e6:18:38:16:34:f5:d9:ed:f8:0c:17:6f:
+                    78:65:ae:14:18:a3:0f:08:b6:e2:87:02:e4:eb:0f:
+                    fb:81:d9:4b:90:ff:b3:fa:0f:d3:04:4d:b0:99:b4:
+                    2b:5e:fb:ad:04:2b:a7:d6:36:0d:17:e0:be:c0:43:
+                    cf:e5:2e:f0:8e:87:88:60:b3:22:d8:03:59:53:50:
+                    a6:69:ce:de:d0:c9:2e:f7:6d:9a:59:4d:99:dc:4b:
+                    3c:c2:15:8f:27:64:23:34:14:34:af:41:76:a5:6a:
+                    9a:0f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                3E:35:E0:F9:A3:1E:2C:FA:DD:E7:8B:CE:58:06:38:20:5D:5E:71:D2
+            X509v3 Authority Key Identifier: 
+                keyid:AC:C4:F6:07:9E:B2:E5:F1:66:7C:40:05:08:AA:DC:EF:8A:60:DA:C1
+
+            X509v3 Subject Alternative Name: critical
+                DNS:user.w1.fi
+            X509v3 Extended Key Usage: 
+                TLS Web Client Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: sha256WithRSAEncryption
+         7b:e9:eb:d7:d4:60:a8:08:62:71:61:dd:42:7d:e5:88:f4:24:
+         bb:3f:6b:a9:16:64:2d:fb:ce:8e:55:1c:f5:7e:b4:c3:74:de:
+         96:e4:59:32:f4:aa:74:e2:ac:43:28:06:54:5d:f7:fe:87:31:
+         3d:ac:45:d5:1c:51:7f:8c:f9:37:0b:66:94:a7:22:5f:d1:55:
+         bf:a4:82:c7:0a:50:bb:c7:18:cf:df:47:81:00:c4:d2:d7:12:
+         b0:83:2d:67:3f:80:b8:be:6f:c9:c5:76:9a:87:ef:3a:f6:0d:
+         4f:24:d8:e7:06:6c:6e:ff:dc:5e:6e:21:a1:e7:26:f6:94:44:
+         69:f4:b2:36:38:08:b1:df:07:fa:7a:53:b8:60:db:63:4b:4f:
+         e6:2a:42:ff:29:68:b5:99:3a:36:eb:26:05:76:d2:ab:e6:d0:
+         7c:af:8c:a0:20:8b:50:6c:3b:bc:1a:53:6d:a7:c8:70:97:21:
+         56:02:24:04:9b:63:2a:5d:b8:8c:e4:bf:e9:8f:58:cd:6e:99:
+         47:3c:02:7b:63:67:c1:c7:32:53:cc:d5:cb:e9:a0:39:ef:f8:
+         44:b7:f3:57:0c:b5:a7:23:3f:16:28:c6:02:14:b6:80:d8:33:
+         42:0c:81:5c:ac:3f:13:d0:5b:4a:66:9f:33:ee:ac:56:fe:37:
+         17:2b:03:40
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIJAOFTujp2BdoeMA0GCSqGSIb3DQEBCwUAMDwxCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEdMBsGA1UEAwwUVXNlciBJbnRlcm1lZGlh
+dGUgQ0EwHhcNMTUxMjIzMTkzNzM2WhcNMjUxMjIwMTkzNzM2WjAyMQswCQYDVQQG
+EwJGSTEOMAwGA1UECgwFdzEuZmkxEzARBgNVBAMMCnVzZXIudzEuZmkwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAhiDlBlqoRy3JXiUk97+mtkRQmYyV
+tWqtdLa67jFesiBgmrSTVW0VC9xaJz/fwZIYWWYQ60ccNR8I3eslvSGcLUg0X5cY
+3IMo2xSMFjtaNmpQY+k74Df99qDWQK/vHpkdiMFPS5IlUyjLxLfOysomry335GJ5
+SElqgjOwpsalFzOIk3c2sndh4FXeLnUVkkznvxHqMwMeSuYYOBY09dnt+AwXb3hl
+rhQYow8ItuKHAuTrD/uB2UuQ/7P6D9METbCZtCte+60EK6fWNg0X4L7AQ8/lLvCO
+h4hgsyLYA1lTUKZpzt7QyS73bZpZTZncSzzCFY8nZCM0FDSvQXalapoPAgMBAAGj
+gYowgYcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUPjXg+aMeLPrd54vOWAY4IF1ecdIw
+HwYDVR0jBBgwFoAUrMT2B56y5fFmfEAFCKrc74pg2sEwGAYDVR0RAQH/BA4wDIIK
+dXNlci53MS5maTATBgNVHSUEDDAKBggrBgEFBQcDAjALBgNVHQ8EBAMCBaAwDQYJ
+KoZIhvcNAQELBQADggEBAHvp69fUYKgIYnFh3UJ95Yj0JLs/a6kWZC37zo5VHPV+
+tMN03pbkWTL0qnTirEMoBlRd9/6HMT2sRdUcUX+M+TcLZpSnIl/RVb+kgscKULvH
+GM/fR4EAxNLXErCDLWc/gLi+b8nFdpqH7zr2DU8k2OcGbG7/3F5uIaHnJvaURGn0
+sjY4CLHfB/p6U7hg22NLT+YqQv8paLWZOjbrJgV20qvm0HyvjKAgi1BsO7waU22n
+yHCXIVYCJASbYypduIzkv+mPWM1umUc8AntjZ8HHMlPM1cvpoDnv+ES381cMtacj
+PxYoxgIUtoDYM0IMgVysPxPQW0pmnzPurFb+NxcrA0A=
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/iCA-user/private/cakey.pem b/tests/hwsim/auth_serv/iCA-user/private/cakey.pem
new file mode 100644 (file)
index 0000000..97ead18
--- /dev/null
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDDKg30ZiNdlpH3
+oL6xsPeeruqmcpH1cGVXkUlVWWe71/WevGayv8+VMTKu25o7Q+iljR+LO+bo4zuy
+nfBYYuqjim/I7QHKJ3QcDp4oXEOY2xS4cgefaycoJc6lkbe3I5o17w63/J9pTRAu
+gaudBLovtOthff1ooRFv9BZCFpkgOCQELTl8dGcUuaomerLZHs7Ni7yN48dYnEr5
+On5sOPhfHOwFTOVWZNQI2PrbF9mh5M+0nd+ZUM76pK+vxvfyDsLFe2z5bOsX5chu
+Wr/rprjA90OBiMPYqqlgrKdFP13LjWxIkisEWsSoMrPpb/6NLWXA6sUJsjCxoy7b
+IopJsf5PAgMBAAECggEAMQpcP1F7CYVQYH0P7e6eCk3BwNmBO79md76WQtAYdOcr
+XRvSYpA4RTD7n1ynQMUrrI3tozsGJvcShSuSvWL9uuKKfF6x2G5ZisNRkqq8gahr
+aH2e1LxENp5pcslO9MIJegv8Etdz5y3qJwWGbgpGDr7TdsgF6Uiv7QXUof6zs5h3
+dri5y4tIbv+/OrEL9pz0x0wR1wFZ24huLLd+I4qHW+nSVynzRsb7dH76vvJRcj+o
+UUIXx0QASoiFyhTPL3kSIcLcwRW1WEkqQXSENj3765CewhpOVcbzUZQiHjPVdOmg
+6+CRptOGJMh5SGHzAbeABwkgeQ4LGWnPdL9B0ZClYQKBgQDk6tGncCWYELelrt9q
+D/bzTvTZADzxYKuOUmyiu9Wr6Lx3nbfJupf0kZSGZuTBOjOd8iQkI1edIWTZLgyY
+48oW2EggJTo5xmAaAdz82ItXpI0/Rt71QQqhcxsaT2uLIinBdox8wP6/DbnG57DJ
+6FcHOsVfAFAVk2sM8ZCK1XRjiwKBgQDaQPbUNGXg04D08jk+15FDlPYh/2TJNSc+
+SBOE1j7wlTNGr6Vcg7N34U+I8Zo/ci8CXQVAMlLd7UJR9UhPsU2ptMldziDPEn5d
+28CkoAmfw/vrcE8j12cuKUViJK6E/Fpvmbmb/cKrACj9qHd1QV7kXFemDKPEUlAe
+8zp4EqPYzQKBgB4NphCxbH4WU8Xwu2wVRHqU9xg2K8oUwvEgaRrERj0XhQa/Mg3N
+7X0yT6mFgKrNlVE7JPuJmEsMw0yv+v9niHSPWIi/2nETVjKT5Atd8o1DETgpecQB
+EgA4OGqv2pKdnZXElpUaUVeL2cP/TvpzAln0oUzjoZ/zhq5gWHWhqHIZAoGBANjt
+pyfGKNitAEj2FKX8dvrYLUgfY5qFhUrnMtdeZ1KSyVNhs5dfo9rsjDQOB4U2Rbkw
+oc5r9md0se1qQYRMM2gRM/BTt9J5jDZX/ILkOoycrGEX0OFL8Nc12CuzT+8IMA8q
+mQyNzZZPY26zqoBWCC4sBkYZ3BB+y/nnQV8lD8ulAoGAB0cwM8SWfP+u4M7qWGFV
+Dk448ODrEfwnbSABc6EavEJ0BL5h60AsXhV9FW6nxfB66Yt84DZm6YXS+9MElLVy
+jlql+Gbaj1Wawtwyzwk7Sl/vqtDwCRta+TP98kAm93Y9CVizlRH93kpNCoYAoDrA
+qN+IRKm0VOAaYV4NXrTTMWE=
+-----END PRIVATE KEY-----
diff --git a/tests/hwsim/auth_serv/iCA-user/serial b/tests/hwsim/auth_serv/iCA-user/serial
new file mode 100644 (file)
index 0000000..f692ea9
--- /dev/null
@@ -0,0 +1 @@
+E153BA3A7605DA1F
diff --git a/tests/hwsim/auth_serv/iCA-user/user.key b/tests/hwsim/auth_serv/iCA-user/user.key
new file mode 100644 (file)
index 0000000..a6d31a5
--- /dev/null
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDAhiDlBlqoRy3J
+XiUk97+mtkRQmYyVtWqtdLa67jFesiBgmrSTVW0VC9xaJz/fwZIYWWYQ60ccNR8I
+3eslvSGcLUg0X5cY3IMo2xSMFjtaNmpQY+k74Df99qDWQK/vHpkdiMFPS5IlUyjL
+xLfOysomry335GJ5SElqgjOwpsalFzOIk3c2sndh4FXeLnUVkkznvxHqMwMeSuYY
+OBY09dnt+AwXb3hlrhQYow8ItuKHAuTrD/uB2UuQ/7P6D9METbCZtCte+60EK6fW
+Ng0X4L7AQ8/lLvCOh4hgsyLYA1lTUKZpzt7QyS73bZpZTZncSzzCFY8nZCM0FDSv
+QXalapoPAgMBAAECggEBAItIPkISv8GghTJ6htrg1elRUckR3VBtyDinCI/iRRti
+OORK6DrzAZDJXOhoHuDNVNmCy8GPxYlVsRckHbvWwZsQc31YbqLQ3Z7QKGRUrSnN
+1kpEjfcAduGn7KI0eFPBSjrAtkGcxaV1LT2GGwhjU6567AG8W7Wso1iHy8eQUIQc
+LKRJ6KYpDc019Ly01XRH8mNhmxo3hxpBzMxudiHua/9qXmsRGevsshxQ911wkPdO
+7Yr9bH1YJ7OvwOxxxAkNyRFAhWa7KPzvhsYX6KHEPTfTSv+3GCz5WLI//5NJ6NFB
+3E2ofJOrmxT6EG6hKzyoNzoUwqpbA2BiHhlSVvOjHhECgYEA4pfICLLh40DMdBc9
+LMnPsp7Sv6H1Lcv/SJr0sjI8ESa2WK+XQOKgfB7jxyBHoMYhlr4UxwtgFA2M0cIs
+4tfqv6zNKWmwB8VpUS+1kwaITtny8U4Kb7hQadpE0dXG84kb1aG3dsvK07aSTS6w
+cW/NPZ9mNQhQ1sYsqF0HzuNysvkCgYEA2YJ0qKvLEkzTGcU0y5CLvzb4ZEuhAc7X
+zzHRCNW61mmhNKR3QVEo3vzpKlxF3PbWJUwt0OOUkdyjbRE3yV0d4JCsNH6vRUmD
+CxafENHZgkuCDD9TrDWhSefhWc7ip3unGG8KdnkGYDe1lw7zIJW5g7GS41GORqDV
+gZngtyxJb0cCgYBQL5ZCPctiOFQh4PdtGh2+ACZkWlQBWOeGMg/V36ESELkGuVy1
+QX25btT8apfudS79wVZo+cWOUx06PZTU0cPpAKW5ugTpOxsB9/gxh2ZFQSuP6SYY
+Uwlh7DPebeBx3ltTRl8+Uu/76+fqGFOoUQA4hmgM7FxvJMI48nMI68RzQQKBgQCW
+BgAW8t9PUQPt63Kd0aZCDlVHQE7eY1/A/nhSorCLATJ6j9HdkHAjVcgxOpHJdcuA
+0EltofswnEFwkgarcfmQkdjlIFgd7zVeqYyvWj6vOwuJDQjWZ+tGgZSSkDsPEB/R
+n41U5+b46JPsjBgv6nWZmxpYhkEfAAIjsRIo5XgFMwKBgD6fAKGFelZuJ/W3uUYl
+swb0ks/L3CMmisMmPwafp4C9QB89xV8jtyDNhiIG1nCI54it9mKrPCASoPDrdJR5
+r2/yovQFWk1LIRqcfCjqV/2qVZo5Hdp7Ux/aI8N7/M1eEIgbq+RcZlFTclQ6fppt
+gBDXmqE8gFdegAGqv+OiifB5
+-----END PRIVATE KEY-----
diff --git a/tests/hwsim/auth_serv/iCA-user/user.pem b/tests/hwsim/auth_serv/iCA-user/user.pem
new file mode 100644 (file)
index 0000000..296060a
--- /dev/null
@@ -0,0 +1,84 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 16236525841851734558 (0xe153ba3a7605da1e)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=User Intermediate CA
+        Validity
+            Not Before: Dec 23 19:37:36 2015 GMT
+            Not After : Dec 20 19:37:36 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=user.w1.fi
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:c0:86:20:e5:06:5a:a8:47:2d:c9:5e:25:24:f7:
+                    bf:a6:b6:44:50:99:8c:95:b5:6a:ad:74:b6:ba:ee:
+                    31:5e:b2:20:60:9a:b4:93:55:6d:15:0b:dc:5a:27:
+                    3f:df:c1:92:18:59:66:10:eb:47:1c:35:1f:08:dd:
+                    eb:25:bd:21:9c:2d:48:34:5f:97:18:dc:83:28:db:
+                    14:8c:16:3b:5a:36:6a:50:63:e9:3b:e0:37:fd:f6:
+                    a0:d6:40:af:ef:1e:99:1d:88:c1:4f:4b:92:25:53:
+                    28:cb:c4:b7:ce:ca:ca:26:af:2d:f7:e4:62:79:48:
+                    49:6a:82:33:b0:a6:c6:a5:17:33:88:93:77:36:b2:
+                    77:61:e0:55:de:2e:75:15:92:4c:e7:bf:11:ea:33:
+                    03:1e:4a:e6:18:38:16:34:f5:d9:ed:f8:0c:17:6f:
+                    78:65:ae:14:18:a3:0f:08:b6:e2:87:02:e4:eb:0f:
+                    fb:81:d9:4b:90:ff:b3:fa:0f:d3:04:4d:b0:99:b4:
+                    2b:5e:fb:ad:04:2b:a7:d6:36:0d:17:e0:be:c0:43:
+                    cf:e5:2e:f0:8e:87:88:60:b3:22:d8:03:59:53:50:
+                    a6:69:ce:de:d0:c9:2e:f7:6d:9a:59:4d:99:dc:4b:
+                    3c:c2:15:8f:27:64:23:34:14:34:af:41:76:a5:6a:
+                    9a:0f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                3E:35:E0:F9:A3:1E:2C:FA:DD:E7:8B:CE:58:06:38:20:5D:5E:71:D2
+            X509v3 Authority Key Identifier: 
+                keyid:AC:C4:F6:07:9E:B2:E5:F1:66:7C:40:05:08:AA:DC:EF:8A:60:DA:C1
+
+            X509v3 Subject Alternative Name: critical
+                DNS:user.w1.fi
+            X509v3 Extended Key Usage: 
+                TLS Web Client Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: sha256WithRSAEncryption
+         7b:e9:eb:d7:d4:60:a8:08:62:71:61:dd:42:7d:e5:88:f4:24:
+         bb:3f:6b:a9:16:64:2d:fb:ce:8e:55:1c:f5:7e:b4:c3:74:de:
+         96:e4:59:32:f4:aa:74:e2:ac:43:28:06:54:5d:f7:fe:87:31:
+         3d:ac:45:d5:1c:51:7f:8c:f9:37:0b:66:94:a7:22:5f:d1:55:
+         bf:a4:82:c7:0a:50:bb:c7:18:cf:df:47:81:00:c4:d2:d7:12:
+         b0:83:2d:67:3f:80:b8:be:6f:c9:c5:76:9a:87:ef:3a:f6:0d:
+         4f:24:d8:e7:06:6c:6e:ff:dc:5e:6e:21:a1:e7:26:f6:94:44:
+         69:f4:b2:36:38:08:b1:df:07:fa:7a:53:b8:60:db:63:4b:4f:
+         e6:2a:42:ff:29:68:b5:99:3a:36:eb:26:05:76:d2:ab:e6:d0:
+         7c:af:8c:a0:20:8b:50:6c:3b:bc:1a:53:6d:a7:c8:70:97:21:
+         56:02:24:04:9b:63:2a:5d:b8:8c:e4:bf:e9:8f:58:cd:6e:99:
+         47:3c:02:7b:63:67:c1:c7:32:53:cc:d5:cb:e9:a0:39:ef:f8:
+         44:b7:f3:57:0c:b5:a7:23:3f:16:28:c6:02:14:b6:80:d8:33:
+         42:0c:81:5c:ac:3f:13:d0:5b:4a:66:9f:33:ee:ac:56:fe:37:
+         17:2b:03:40
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIJAOFTujp2BdoeMA0GCSqGSIb3DQEBCwUAMDwxCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEdMBsGA1UEAwwUVXNlciBJbnRlcm1lZGlh
+dGUgQ0EwHhcNMTUxMjIzMTkzNzM2WhcNMjUxMjIwMTkzNzM2WjAyMQswCQYDVQQG
+EwJGSTEOMAwGA1UECgwFdzEuZmkxEzARBgNVBAMMCnVzZXIudzEuZmkwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAhiDlBlqoRy3JXiUk97+mtkRQmYyV
+tWqtdLa67jFesiBgmrSTVW0VC9xaJz/fwZIYWWYQ60ccNR8I3eslvSGcLUg0X5cY
+3IMo2xSMFjtaNmpQY+k74Df99qDWQK/vHpkdiMFPS5IlUyjLxLfOysomry335GJ5
+SElqgjOwpsalFzOIk3c2sndh4FXeLnUVkkznvxHqMwMeSuYYOBY09dnt+AwXb3hl
+rhQYow8ItuKHAuTrD/uB2UuQ/7P6D9METbCZtCte+60EK6fWNg0X4L7AQ8/lLvCO
+h4hgsyLYA1lTUKZpzt7QyS73bZpZTZncSzzCFY8nZCM0FDSvQXalapoPAgMBAAGj
+gYowgYcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUPjXg+aMeLPrd54vOWAY4IF1ecdIw
+HwYDVR0jBBgwFoAUrMT2B56y5fFmfEAFCKrc74pg2sEwGAYDVR0RAQH/BA4wDIIK
+dXNlci53MS5maTATBgNVHSUEDDAKBggrBgEFBQcDAjALBgNVHQ8EBAMCBaAwDQYJ
+KoZIhvcNAQELBQADggEBAHvp69fUYKgIYnFh3UJ95Yj0JLs/a6kWZC37zo5VHPV+
+tMN03pbkWTL0qnTirEMoBlRd9/6HMT2sRdUcUX+M+TcLZpSnIl/RVb+kgscKULvH
+GM/fR4EAxNLXErCDLWc/gLi+b8nFdpqH7zr2DU8k2OcGbG7/3F5uIaHnJvaURGn0
+sjY4CLHfB/p6U7hg22NLT+YqQv8paLWZOjbrJgV20qvm0HyvjKAgi1BsO7waU22n
+yHCXIVYCJASbYypduIzkv+mPWM1umUc8AntjZ8HHMlPM1cvpoDnv+ES381cMtacj
+PxYoxgIUtoDYM0IMgVysPxPQW0pmnzPurFb+NxcrA0A=
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/iCA-user/user.req b/tests/hwsim/auth_serv/iCA-user/user.req
new file mode 100644 (file)
index 0000000..21314b7
--- /dev/null
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICijCCAXICAQAwRTELMAkGA1UEBhMCRkkxETAPBgNVBAcMCEhlbHNpbmtpMQ4w
+DAYDVQQKDAV3MS5maTETMBEGA1UEAwwKdXNlci53MS5maTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAMCGIOUGWqhHLcleJST3v6a2RFCZjJW1aq10trru
+MV6yIGCatJNVbRUL3FonP9/BkhhZZhDrRxw1Hwjd6yW9IZwtSDRflxjcgyjbFIwW
+O1o2alBj6TvgN/32oNZAr+8emR2IwU9LkiVTKMvEt87KyiavLffkYnlISWqCM7Cm
+xqUXM4iTdzayd2HgVd4udRWSTOe/EeozAx5K5hg4FjT12e34DBdveGWuFBijDwi2
+4ocC5OsP+4HZS5D/s/oP0wRNsJm0K177rQQrp9Y2DRfgvsBDz+Uu8I6HiGCzItgD
+WVNQpmnO3tDJLvdtmllNmdxLPMIVjydkIzQUNK9BdqVqmg8CAwEAAaAAMA0GCSqG
+SIb3DQEBCwUAA4IBAQCUmkpNMn0zJiThP+5G+GvjE4bf1zBPWCQ2jNu9ve5dAd6+
+og47aR2PAJWUmFYMfFBzAFxAVkXVwAMAzN7npwtSjTW9kVPxYHItrncopEzPjIOQ
+WHSH8nuYxNNYbbkq1/dvivcJVFk8gNCIFvnW8EKgtDfvDlYcyleWnYA343N7eeBc
+ujRiiRrZuADk7VFqWM0TdwUEytP/6FJIhB50Y3yDkGNx1KkAJuCU8eSx/aBg/2Si
+XPxDKAcVsESrCfFnHuaqN1+BXP5QXuuvR5N6EPt+C/Mv1VnV28uSkLzFO4PCN2pD
+ArGZjVzFM6Qegag10DPk8BmDuh3s+NydD29xUfbA
+-----END CERTIFICATE REQUEST-----
diff --git a/tests/hwsim/auth_serv/iCA-user/user_and_ica.pem b/tests/hwsim/auth_serv/iCA-user/user_and_ica.pem
new file mode 100644 (file)
index 0000000..5de2e9d
--- /dev/null
@@ -0,0 +1,154 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 15624081837803162868 (0xd8d3e3a6cbe3ccf4)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=Root CA
+        Validity
+            Not Before: Dec 23 19:37:36 2015 GMT
+            Not After : Dec 22 19:37:36 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=User Intermediate CA
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:c3:2a:0d:f4:66:23:5d:96:91:f7:a0:be:b1:b0:
+                    f7:9e:ae:ea:a6:72:91:f5:70:65:57:91:49:55:59:
+                    67:bb:d7:f5:9e:bc:66:b2:bf:cf:95:31:32:ae:db:
+                    9a:3b:43:e8:a5:8d:1f:8b:3b:e6:e8:e3:3b:b2:9d:
+                    f0:58:62:ea:a3:8a:6f:c8:ed:01:ca:27:74:1c:0e:
+                    9e:28:5c:43:98:db:14:b8:72:07:9f:6b:27:28:25:
+                    ce:a5:91:b7:b7:23:9a:35:ef:0e:b7:fc:9f:69:4d:
+                    10:2e:81:ab:9d:04:ba:2f:b4:eb:61:7d:fd:68:a1:
+                    11:6f:f4:16:42:16:99:20:38:24:04:2d:39:7c:74:
+                    67:14:b9:aa:26:7a:b2:d9:1e:ce:cd:8b:bc:8d:e3:
+                    c7:58:9c:4a:f9:3a:7e:6c:38:f8:5f:1c:ec:05:4c:
+                    e5:56:64:d4:08:d8:fa:db:17:d9:a1:e4:cf:b4:9d:
+                    df:99:50:ce:fa:a4:af:af:c6:f7:f2:0e:c2:c5:7b:
+                    6c:f9:6c:eb:17:e5:c8:6e:5a:bf:eb:a6:b8:c0:f7:
+                    43:81:88:c3:d8:aa:a9:60:ac:a7:45:3f:5d:cb:8d:
+                    6c:48:92:2b:04:5a:c4:a8:32:b3:e9:6f:fe:8d:2d:
+                    65:c0:ea:c5:09:b2:30:b1:a3:2e:db:22:8a:49:b1:
+                    fe:4f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                AC:C4:F6:07:9E:B2:E5:F1:66:7C:40:05:08:AA:DC:EF:8A:60:DA:C1
+            X509v3 Authority Key Identifier: 
+                keyid:B8:92:DE:FD:8A:18:B3:30:C3:9F:55:F3:33:5D:B4:C8:29:8A:41:14
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE, pathlen:0
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+    Signature Algorithm: sha256WithRSAEncryption
+         0d:60:2b:fa:00:f2:5a:90:31:96:50:c8:9e:7f:60:02:99:c6:
+         31:d4:93:86:9e:4c:24:15:b6:b2:31:49:21:79:ce:7f:92:86:
+         1e:83:d8:a0:37:05:1b:89:2b:ef:0b:83:21:b0:37:8d:2f:7b:
+         6b:7d:c6:04:1e:a2:c8:59:be:52:bf:47:ee:46:cb:45:8d:1f:
+         7a:e4:d4:e5:54:60:5f:46:b0:ac:68:8a:26:57:ea:48:45:c1:
+         07:7d:ee:10:9e:94:87:4c:7e:26:2e:f8:ad:03:e5:03:86:09:
+         3e:48:0c:e0:04:2f:22:b4:e0:3a:b0:72:8c:e2:40:d2:cd:fb:
+         8f:fa
+-----BEGIN CERTIFICATE-----
+MIIC0zCCAjygAwIBAgIJANjT46bL48z0MA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xNTEy
+MjMxOTM3MzZaFw0yNTEyMjIxOTM3MzZaMDwxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+DAV3MS5maTEdMBsGA1UEAwwUVXNlciBJbnRlcm1lZGlhdGUgQ0EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDKg30ZiNdlpH3oL6xsPeeruqmcpH1cGVX
+kUlVWWe71/WevGayv8+VMTKu25o7Q+iljR+LO+bo4zuynfBYYuqjim/I7QHKJ3Qc
+Dp4oXEOY2xS4cgefaycoJc6lkbe3I5o17w63/J9pTRAugaudBLovtOthff1ooRFv
+9BZCFpkgOCQELTl8dGcUuaomerLZHs7Ni7yN48dYnEr5On5sOPhfHOwFTOVWZNQI
+2PrbF9mh5M+0nd+ZUM76pK+vxvfyDsLFe2z5bOsX5chuWr/rprjA90OBiMPYqqlg
+rKdFP13LjWxIkisEWsSoMrPpb/6NLWXA6sUJsjCxoy7bIopJsf5PAgMBAAGjZjBk
+MB0GA1UdDgQWBBSsxPYHnrLl8WZ8QAUIqtzvimDawTAfBgNVHSMEGDAWgBS4kt79
+ihizMMOfVfMzXbTIKYpBFDASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQE
+AwIBBjANBgkqhkiG9w0BAQsFAAOBgQANYCv6APJakDGWUMief2ACmcYx1JOGnkwk
+FbayMUkhec5/koYeg9igNwUbiSvvC4MhsDeNL3trfcYEHqLIWb5Sv0fuRstFjR96
+5NTlVGBfRrCsaIomV+pIRcEHfe4QnpSHTH4mLvitA+UDhgk+SAzgBC8itOA6sHKM
+4kDSzfuP+g==
+-----END CERTIFICATE-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 16236525841851734558 (0xe153ba3a7605da1e)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=FI, O=w1.fi, CN=User Intermediate CA
+        Validity
+            Not Before: Dec 23 19:37:36 2015 GMT
+            Not After : Dec 20 19:37:36 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=user.w1.fi
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:c0:86:20:e5:06:5a:a8:47:2d:c9:5e:25:24:f7:
+                    bf:a6:b6:44:50:99:8c:95:b5:6a:ad:74:b6:ba:ee:
+                    31:5e:b2:20:60:9a:b4:93:55:6d:15:0b:dc:5a:27:
+                    3f:df:c1:92:18:59:66:10:eb:47:1c:35:1f:08:dd:
+                    eb:25:bd:21:9c:2d:48:34:5f:97:18:dc:83:28:db:
+                    14:8c:16:3b:5a:36:6a:50:63:e9:3b:e0:37:fd:f6:
+                    a0:d6:40:af:ef:1e:99:1d:88:c1:4f:4b:92:25:53:
+                    28:cb:c4:b7:ce:ca:ca:26:af:2d:f7:e4:62:79:48:
+                    49:6a:82:33:b0:a6:c6:a5:17:33:88:93:77:36:b2:
+                    77:61:e0:55:de:2e:75:15:92:4c:e7:bf:11:ea:33:
+                    03:1e:4a:e6:18:38:16:34:f5:d9:ed:f8:0c:17:6f:
+                    78:65:ae:14:18:a3:0f:08:b6:e2:87:02:e4:eb:0f:
+                    fb:81:d9:4b:90:ff:b3:fa:0f:d3:04:4d:b0:99:b4:
+                    2b:5e:fb:ad:04:2b:a7:d6:36:0d:17:e0:be:c0:43:
+                    cf:e5:2e:f0:8e:87:88:60:b3:22:d8:03:59:53:50:
+                    a6:69:ce:de:d0:c9:2e:f7:6d:9a:59:4d:99:dc:4b:
+                    3c:c2:15:8f:27:64:23:34:14:34:af:41:76:a5:6a:
+                    9a:0f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                3E:35:E0:F9:A3:1E:2C:FA:DD:E7:8B:CE:58:06:38:20:5D:5E:71:D2
+            X509v3 Authority Key Identifier: 
+                keyid:AC:C4:F6:07:9E:B2:E5:F1:66:7C:40:05:08:AA:DC:EF:8A:60:DA:C1
+
+            X509v3 Subject Alternative Name: critical
+                DNS:user.w1.fi
+            X509v3 Extended Key Usage: 
+                TLS Web Client Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: sha256WithRSAEncryption
+         7b:e9:eb:d7:d4:60:a8:08:62:71:61:dd:42:7d:e5:88:f4:24:
+         bb:3f:6b:a9:16:64:2d:fb:ce:8e:55:1c:f5:7e:b4:c3:74:de:
+         96:e4:59:32:f4:aa:74:e2:ac:43:28:06:54:5d:f7:fe:87:31:
+         3d:ac:45:d5:1c:51:7f:8c:f9:37:0b:66:94:a7:22:5f:d1:55:
+         bf:a4:82:c7:0a:50:bb:c7:18:cf:df:47:81:00:c4:d2:d7:12:
+         b0:83:2d:67:3f:80:b8:be:6f:c9:c5:76:9a:87:ef:3a:f6:0d:
+         4f:24:d8:e7:06:6c:6e:ff:dc:5e:6e:21:a1:e7:26:f6:94:44:
+         69:f4:b2:36:38:08:b1:df:07:fa:7a:53:b8:60:db:63:4b:4f:
+         e6:2a:42:ff:29:68:b5:99:3a:36:eb:26:05:76:d2:ab:e6:d0:
+         7c:af:8c:a0:20:8b:50:6c:3b:bc:1a:53:6d:a7:c8:70:97:21:
+         56:02:24:04:9b:63:2a:5d:b8:8c:e4:bf:e9:8f:58:cd:6e:99:
+         47:3c:02:7b:63:67:c1:c7:32:53:cc:d5:cb:e9:a0:39:ef:f8:
+         44:b7:f3:57:0c:b5:a7:23:3f:16:28:c6:02:14:b6:80:d8:33:
+         42:0c:81:5c:ac:3f:13:d0:5b:4a:66:9f:33:ee:ac:56:fe:37:
+         17:2b:03:40
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIJAOFTujp2BdoeMA0GCSqGSIb3DQEBCwUAMDwxCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEdMBsGA1UEAwwUVXNlciBJbnRlcm1lZGlh
+dGUgQ0EwHhcNMTUxMjIzMTkzNzM2WhcNMjUxMjIwMTkzNzM2WjAyMQswCQYDVQQG
+EwJGSTEOMAwGA1UECgwFdzEuZmkxEzARBgNVBAMMCnVzZXIudzEuZmkwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAhiDlBlqoRy3JXiUk97+mtkRQmYyV
+tWqtdLa67jFesiBgmrSTVW0VC9xaJz/fwZIYWWYQ60ccNR8I3eslvSGcLUg0X5cY
+3IMo2xSMFjtaNmpQY+k74Df99qDWQK/vHpkdiMFPS5IlUyjLxLfOysomry335GJ5
+SElqgjOwpsalFzOIk3c2sndh4FXeLnUVkkznvxHqMwMeSuYYOBY09dnt+AwXb3hl
+rhQYow8ItuKHAuTrD/uB2UuQ/7P6D9METbCZtCte+60EK6fWNg0X4L7AQ8/lLvCO
+h4hgsyLYA1lTUKZpzt7QyS73bZpZTZncSzzCFY8nZCM0FDSvQXalapoPAgMBAAGj
+gYowgYcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUPjXg+aMeLPrd54vOWAY4IF1ecdIw
+HwYDVR0jBBgwFoAUrMT2B56y5fFmfEAFCKrc74pg2sEwGAYDVR0RAQH/BA4wDIIK
+dXNlci53MS5maTATBgNVHSUEDDAKBggrBgEFBQcDAjALBgNVHQ8EBAMCBaAwDQYJ
+KoZIhvcNAQELBQADggEBAHvp69fUYKgIYnFh3UJ95Yj0JLs/a6kWZC37zo5VHPV+
+tMN03pbkWTL0qnTirEMoBlRd9/6HMT2sRdUcUX+M+TcLZpSnIl/RVb+kgscKULvH
+GM/fR4EAxNLXErCDLWc/gLi+b8nFdpqH7zr2DU8k2OcGbG7/3F5uIaHnJvaURGn0
+sjY4CLHfB/p6U7hg22NLT+YqQv8paLWZOjbrJgV20qvm0HyvjKAgi1BsO7waU22n
+yHCXIVYCJASbYypduIzkv+mPWM1umUc8AntjZ8HHMlPM1cvpoDnv+ES381cMtacj
+PxYoxgIUtoDYM0IMgVysPxPQW0pmnzPurFb+NxcrA0A=
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/ica-generate.sh b/tests/hwsim/auth_serv/ica-generate.sh
new file mode 100755 (executable)
index 0000000..8d77088
--- /dev/null
@@ -0,0 +1,87 @@
+#!/bin/sh
+
+OPENSSL=openssl
+
+echo
+echo "---[ Intermediate CA - Server ]-----------------------------------------"
+echo
+
+cat ec-ca-openssl.cnf |
+       sed "s/ec-ca/rootCA/" |
+       sed "s/#@CN@/commonName_default = Server Intermediate CA/" \
+       > openssl.cnf.tmp
+mkdir -p iCA-server/certs iCA-server/crl iCA-server/newcerts iCA-server/private
+touch iCA-server/index.txt
+$OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -keyout iCA-server/private/cakey.pem -out iCA-server/careq.pem -outform PEM -days 3652 -sha256
+$OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out iCA-server/cacert.pem -days 3652 -batch -keyfile ca-key.pem -cert ca.pem -extensions v3_ca -outdir rootCA/newcerts -infiles iCA-server/careq.pem
+cat iCA-server/cacert.pem ca.pem  > iCA-server/ca-and-root.pem
+rm openssl.cnf.tmp
+
+echo
+echo "---[ Intermediate CA - User ]-------------------------------------------"
+echo
+
+cat ec-ca-openssl.cnf |
+       sed "s/ec-ca/rootCA/" |
+       sed "s/#@CN@/commonName_default = User Intermediate CA/" \
+       > openssl.cnf.tmp
+mkdir -p iCA-user/certs iCA-user/crl iCA-user/newcerts iCA-user/private
+touch iCA-user/index.txt
+$OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -keyout iCA-user/private/cakey.pem -out iCA-user/careq.pem -outform PEM -days 3652 -sha256
+$OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out iCA-user/cacert.pem -days 3652 -batch -keyfile ca-key.pem -cert ca.pem -extensions v3_ca -outdir rootCA/newcerts -infiles iCA-user/careq.pem
+cat iCA-user/cacert.pem ca.pem  > iCA-user/ca-and-root.pem
+rm openssl.cnf.tmp
+
+echo
+echo "---[ Server ]-----------------------------------------------------------"
+echo
+
+cat ec-ca-openssl.cnf |
+       sed "s/ec-ca/iCA-server/" |
+       sed "s/#@CN@/commonName_default = server.w1.fi/" |
+       sed "s/#@ALTNAME@/subjectAltName=critical,DNS:server.w1.fi/" \
+       > openssl.cnf.tmp
+$OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -keyout iCA-server/server.key -out iCA-server/server.req -outform PEM -sha256
+$OPENSSL ca -config openssl.cnf.tmp -batch -keyfile iCA-server/private/cakey.pem -cert iCA-server/cacert.pem -create_serial -in iCA-server/server.req -out iCA-server/server.pem -extensions ext_server -md sha256
+cat iCA-server/cacert.pem iCA-server/server.pem > iCA-server/server_and_ica.pem
+rm openssl.cnf.tmp
+
+echo
+echo "---[ Server - revoked ]-------------------------------------------------"
+echo
+
+cat ec-ca-openssl.cnf |
+       sed "s/ec-ca/iCA-server/" |
+       sed "s/#@CN@/commonName_default = server-revoked.w1.fi/" |
+       sed "s/#@ALTNAME@/subjectAltName=critical,DNS:server-revoked.w1.fi/" \
+       > openssl.cnf.tmp
+$OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -keyout iCA-server/server-revoked.key -out iCA-server/server-revoked.req -outform PEM -sha256
+$OPENSSL ca -config openssl.cnf.tmp -batch -keyfile iCA-server/private/cakey.pem -cert iCA-server/cacert.pem -create_serial -in iCA-server/server-revoked.req -out iCA-server/server-revoked.pem -extensions ext_server -md sha256
+$OPENSSL ca -config openssl.cnf.tmp -revoke iCA-server/server-revoked.pem -keyfile iCA-server/private/cakey.pem -cert iCA-server/cacert.pem
+cat iCA-server/cacert.pem iCA-server/server-revoked.pem > iCA-server/server-revoked_and_ica.pem
+rm openssl.cnf.tmp
+
+echo
+echo "---[ User ]-----------------------------------------------------------"
+echo
+
+cat ec-ca-openssl.cnf |
+       sed "s/ec-ca/iCA-user/" |
+       sed "s/#@CN@/commonName_default = user.w1.fi/" |
+       sed "s/#@ALTNAME@/subjectAltName=critical,DNS:user.w1.fi/" \
+       > openssl.cnf.tmp
+$OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -keyout iCA-user/user.key -out iCA-user/user.req -outform PEM -sha256
+$OPENSSL ca -config openssl.cnf.tmp -batch -keyfile iCA-user/private/cakey.pem -cert iCA-user/cacert.pem -create_serial -in iCA-user/user.req -out iCA-user/user.pem -extensions ext_client -md sha256
+cat iCA-user/cacert.pem iCA-user/user.pem > iCA-user/user_and_ica.pem
+rm openssl.cnf.tmp
+
+echo
+echo "---[ Verify ]-----------------------------------------------------------"
+echo
+
+$OPENSSL verify -CAfile ca.pem iCA-server/cacert.pem
+$OPENSSL verify -CAfile ca.pem iCA-user/cacert.pem
+$OPENSSL verify -CAfile ca.pem -untrusted iCA-server/cacert.pem iCA-server/server.pem
+$OPENSSL verify -CAfile ca.pem -untrusted iCA-server/cacert.pem iCA-server/server-revoked.pem
+$OPENSSL verify -CAfile ca.pem iCA-user/cacert.pem
+$OPENSSL verify -CAfile ca.pem -untrusted iCA-user/cacert.pem iCA-user/user.pem
diff --git a/tests/hwsim/auth_serv/ocsp-multi-server-cache.der b/tests/hwsim/auth_serv/ocsp-multi-server-cache.der
new file mode 100644 (file)
index 0000000..5a0179e
Binary files /dev/null and b/tests/hwsim/auth_serv/ocsp-multi-server-cache.der differ
diff --git a/tests/hwsim/auth_serv/rootCA/index.txt b/tests/hwsim/auth_serv/rootCA/index.txt
new file mode 100644 (file)
index 0000000..8575df9
--- /dev/null
@@ -0,0 +1,2 @@
+V      251222193736Z           D8D3E3A6CBE3CCF3        unknown /C=FI/O=w1.fi/CN=Server Intermediate CA
+V      251222193736Z           D8D3E3A6CBE3CCF4        unknown /C=FI/O=w1.fi/CN=User Intermediate CA
diff --git a/tests/hwsim/auth_serv/rootCA/index.txt.attr b/tests/hwsim/auth_serv/rootCA/index.txt.attr
new file mode 100644 (file)
index 0000000..3a7e39e
--- /dev/null
@@ -0,0 +1 @@
+unique_subject = no
diff --git a/tests/hwsim/auth_serv/rootCA/serial b/tests/hwsim/auth_serv/rootCA/serial
new file mode 100644 (file)
index 0000000..b0de706
--- /dev/null
@@ -0,0 +1 @@
+D8D3E3A6CBE3CCF5
diff --git a/tests/hwsim/auth_serv/server-extra.pkcs12 b/tests/hwsim/auth_serv/server-extra.pkcs12
new file mode 100644 (file)
index 0000000..1ae6ce5
Binary files /dev/null and b/tests/hwsim/auth_serv/server-extra.pkcs12 differ
diff --git a/tests/hwsim/auth_serv/sha384-server.key b/tests/hwsim/auth_serv/sha384-server.key
new file mode 100644 (file)
index 0000000..10ff145
--- /dev/null
@@ -0,0 +1,40 @@
+-----BEGIN PRIVATE KEY-----
+MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQDm91jBTdZzl79p
+4ZPklcK5EoOMvj3++QdZ+7pFKmDFHX8qqfk6HXz4fkFXMYokV2pFvRh+i+wvbAPc
+OLI6cxSSSz02yspRkcN1hDlERfjIrMrJq5M5GgoT1F2zQ0Wc+inXDetgIG1QOb+q
+oQR3mxMCQLphohv8n2JkW6+Lmdt9zsx9tOQWjFSB3YFdcb4yhGP5sJ4n8EanpNdR
+k0NbdKffehDDxXUtb4O1U6i/H1NFA0/l/oN0IuhwXkdkv8ikdpPke+FqCp8H6CZM
+vZrC3ItJpIm+k/eXIyAvW4hag/75GfGeV7b4MnVegcylWtacFpaDRsklfAStMXd5
+EOiC4cmANIYupoZwfiSadthk9BbBqzRAcpvFljgFeUeR5N8St4B1noPwatoMuMzh
+WG28Iv/hNr8Rj/vzWznO0xp3lPckZPVHzrl08U1QSH9j6SqsmGMY1Y4riRGzNkUf
+o7eV9GB8kKp6oWM6TCuyRbMhS0LB/TNH3682oBJMEftK5HBiTf8CAwEAAQKCAYEA
+txfjyzGaTH5CZnxFklLKT46GrF7vpJ3jnwi37DahCgHNGpQuF0zjEdZ8k9OY0CBg
+BbLWpRLlA97b3IsxdrZd2287sqDl6+3ihdlw0Fer1eFszJxwFDc5P+j88qvkloGW
+A35sVgK+xXdSIsCMWwia9BE970Hkb8ol5KruKXupjT0PzKNGoT1TjLN85wfRIBjl
+bD3/0mdei21Yp7lXDzwWDEmm2ptAvekF/wu33PLHPxFWGFw/9yPpIZMLg6mpM/8u
+0lWjpuTuQZLAVU0yKag5mhRa9rwCqslxDZzNXYA7hUO57hT+diO1U447cdAEYzpF
+XUZrPBHUOlaRNd2f2INFAX3W0SraSTp3IX2KBd3daU2aSN6y4DMO4I9wJwJV4vrC
+1rnJB+e9DnBNUezhgpiDOE0+vOprrqGtXsdULgFuPd47b2eU4WWvFHeeKuMBgrRg
+iRSgaxButfFIryRhCYA88cXFG0qO3qNUPMmDTCRjS1S6rhQeP8dxN6kcJc+o/+Ep
+AoHBAP95nPrypMNYJAlQtlgYMbxyMRLz7HXLN/TklEtPMNsjK8LHIIa3v3uv8gbk
+1VmXc8oQa4NB8cu9CtX98fSwvbiuwXjhxFe0mMlg4QdkbCQYXj3CeDsE5PNO3aXK
+oIF1WzJZYN+KV/NgyCIP/hAgBBmDFcfgovJb3YvMGmC3/2MmP3+1tgsLabPXoJSZ
+Uqc7c5m9Tlm7NP8LAi/zRjFOD+b3BDIH8e8ADV02uAYe0fyCcihaf7ZYbiROG2KE
+BNlbgwKBwQDncNdXOgz9bb0C+HymH0LwB0KECt2NNN0DV1GXoH8IXEYtK4V2XJdU
+P63EtMfaUgk0vyL/pIWQLlyt9bW0Gnr0nDY3NiX2ctRnh6WUzKNrpdQmhquEWXXw
+pujDupY2O90lXeJdMhp2WWT+22IFMykwLY2sVBJzhXpY2lUd/EBgFiUpD8NRAt2V
+f98eJYd3lC1JEsrEgCQrvEzc+B9y7GHPm8YevJrIcNvYMjUXEMo8rmjd+GZC4SD/
+rZVcCBrYDtUCgcEA7fbkjye26zJNltO0lYgrw8GGDoZgyjP5skW8EA36jxRKrcp3
+dKTxWo+/3EYIqMQXGa+DxaaGSGWVE1DQsEB05/L3ydZZ4ewZqPJxiUY0KMb9+X8M
+KMVdUXkzojuEmDGtOc/hGTeuxsdug7Przi9UQkNE5YJLpX6GdbIvG8onu74jxZyH
+re/6jIccT24lfBo3iou30IM9URd6+RkcV87DpzqNkOCvrRSaXioa7bCFnjQPi6EI
+dtwV9AFBJtmb/q5rAoHAAt/l7NFtw+APDvBjK/ULccvFSbqQ0eYsMJRvEQEPUt1C
+ieEWgUfZIVTBJcZRDScjsiIFn0M93XKV+BsrLJd/m3YtPjZP9mWqubZ3mgeIqBeh
+MPFPRA+QZXLNRVEV+Ip5zrMB0sKCjaHCnV/AMexWwKBwOAm7SPAJev0LPZoaepcL
+0xy9Ak6UzfyOmuNAcX3Hqjavig1FZb2q/rueOGEzPc7jgRI6oe607FSDUEwHFwXb
+i5ZAPuho7oQLbN805iYZAoHAReFyMpjLEXOfyJQAOZb1BQHJ4U8AyYyPleXB/Bh1
+EmO+Qv3VhtqorN0g3t7XaupEqcPBRWQHxo8hlrP+6Rj4fVnT8gFYOb1QMmy5EW2b
+0sdt74xLv4LI6TLLZim+akYNuFxQbBnLHJgDXgjinM+jZfzve39Uhz7ojrFaySqW
+bRcQzciRgbHWrSxkLGq+gJDyjvKkszs4RN9J7LH+C8+BiyRhgxc2ZTja75bq5TQB
+Tohu1wDMgHHInYJkhZNxYIGX
+-----END PRIVATE KEY-----
diff --git a/tests/hwsim/auth_serv/sha384-server.pem b/tests/hwsim/auth_serv/sha384-server.pem
new file mode 100644 (file)
index 0000000..d51921f
--- /dev/null
@@ -0,0 +1,115 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 14110776913249282218 (0xc3d38cd72b01a8aa)
+    Signature Algorithm: sha384WithRSAEncryption
+        Issuer: C=FI, L=Helsinki, O=w1.fi, CN=SHA384 and SHA512 Root CA
+        Validity
+            Not Before: Nov 29 22:33:25 2015 GMT
+            Not After : Nov 26 22:33:25 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=sha384.server.w1.fi
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (3072 bit)
+                Modulus:
+                    00:e6:f7:58:c1:4d:d6:73:97:bf:69:e1:93:e4:95:
+                    c2:b9:12:83:8c:be:3d:fe:f9:07:59:fb:ba:45:2a:
+                    60:c5:1d:7f:2a:a9:f9:3a:1d:7c:f8:7e:41:57:31:
+                    8a:24:57:6a:45:bd:18:7e:8b:ec:2f:6c:03:dc:38:
+                    b2:3a:73:14:92:4b:3d:36:ca:ca:51:91:c3:75:84:
+                    39:44:45:f8:c8:ac:ca:c9:ab:93:39:1a:0a:13:d4:
+                    5d:b3:43:45:9c:fa:29:d7:0d:eb:60:20:6d:50:39:
+                    bf:aa:a1:04:77:9b:13:02:40:ba:61:a2:1b:fc:9f:
+                    62:64:5b:af:8b:99:db:7d:ce:cc:7d:b4:e4:16:8c:
+                    54:81:dd:81:5d:71:be:32:84:63:f9:b0:9e:27:f0:
+                    46:a7:a4:d7:51:93:43:5b:74:a7:df:7a:10:c3:c5:
+                    75:2d:6f:83:b5:53:a8:bf:1f:53:45:03:4f:e5:fe:
+                    83:74:22:e8:70:5e:47:64:bf:c8:a4:76:93:e4:7b:
+                    e1:6a:0a:9f:07:e8:26:4c:bd:9a:c2:dc:8b:49:a4:
+                    89:be:93:f7:97:23:20:2f:5b:88:5a:83:fe:f9:19:
+                    f1:9e:57:b6:f8:32:75:5e:81:cc:a5:5a:d6:9c:16:
+                    96:83:46:c9:25:7c:04:ad:31:77:79:10:e8:82:e1:
+                    c9:80:34:86:2e:a6:86:70:7e:24:9a:76:d8:64:f4:
+                    16:c1:ab:34:40:72:9b:c5:96:38:05:79:47:91:e4:
+                    df:12:b7:80:75:9e:83:f0:6a:da:0c:b8:cc:e1:58:
+                    6d:bc:22:ff:e1:36:bf:11:8f:fb:f3:5b:39:ce:d3:
+                    1a:77:94:f7:24:64:f5:47:ce:b9:74:f1:4d:50:48:
+                    7f:63:e9:2a:ac:98:63:18:d5:8e:2b:89:11:b3:36:
+                    45:1f:a3:b7:95:f4:60:7c:90:aa:7a:a1:63:3a:4c:
+                    2b:b2:45:b3:21:4b:42:c1:fd:33:47:df:af:36:a0:
+                    12:4c:11:fb:4a:e4:70:62:4d:ff
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                C8:A6:E4:81:75:69:7C:09:1D:A1:E6:14:CE:62:65:4E:56:D8:92:79
+            X509v3 Authority Key Identifier: 
+                keyid:0E:74:B5:09:EC:FB:FA:E7:BA:6B:1A:F6:2B:28:7E:A9:70:DA:D7:18
+
+            X509v3 Subject Alternative Name: critical
+                DNS:sha384.server.w1.fi
+            X509v3 Extended Key Usage: critical
+                TLS Web Server Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: sha384WithRSAEncryption
+         04:da:fd:8c:4d:ae:05:1a:bc:39:7d:b4:6e:b1:fa:9e:6c:39:
+         a1:58:24:49:59:0b:2a:d9:2c:c3:64:93:07:72:b0:37:3e:24:
+         9d:b0:b4:6e:d7:4c:75:57:74:1a:4a:f1:34:4f:83:3d:eb:b3:
+         77:a0:b3:1a:90:f2:6b:57:7b:46:a2:cb:f4:31:d8:9f:e8:1f:
+         5c:3f:b3:ac:ff:2d:c8:d5:f2:1b:dd:7c:9b:b8:7f:61:13:3a:
+         b1:14:82:4d:52:cf:d0:dc:6f:20:e7:94:06:6b:9f:6d:49:dc:
+         41:9b:9e:66:41:d6:45:15:af:92:00:6d:75:5f:95:93:ec:29:
+         7d:f9:a8:57:1a:16:a4:f9:9e:ac:e1:86:f2:d3:38:25:16:e3:
+         a1:f2:9f:3b:7e:a7:9b:b9:e7:24:0f:f3:da:66:c4:de:34:3c:
+         75:58:b2:64:e2:d1:2e:6d:ac:f8:03:d9:d2:a9:b6:67:d9:98:
+         51:76:b5:1f:a8:a0:5f:73:65:dd:52:04:88:f4:e6:d7:cb:94:
+         83:ac:08:29:25:c5:aa:8a:44:6d:73:14:cf:9a:48:24:ab:46:
+         d1:85:ee:29:81:e6:23:03:82:57:34:2c:f8:e1:5f:03:53:79:
+         f7:ca:b3:58:2c:60:8f:52:d1:20:6e:f0:5a:f4:7e:52:fa:a8:
+         fa:4d:6c:a8:67:d6:da:a5:da:9c:54:c6:34:3a:ca:06:32:a8:
+         45:3b:41:95:6e:81:07:9b:f4:fb:6a:4b:7c:ee:d5:7f:30:7e:
+         c2:39:8d:88:b4:c9:62:5f:14:3a:1c:48:9d:b6:06:d8:8e:12:
+         1c:99:e0:d6:7a:a6:e4:0a:b4:23:33:98:3a:00:5b:2d:d2:0a:
+         05:b8:9c:1f:9d:f0:1e:a0:d4:88:35:0e:47:bc:59:f3:f2:08:
+         5e:f6:11:b2:53:b3:b4:80:c9:3b:18:e4:51:45:43:9b:7b:8f:
+         7d:23:0b:2e:66:da:29:b9:0c:98:16:7a:2b:b5:a7:37:e1:f6:
+         20:cc:06:56:50:7c:36:6b:f3:c8:00:08:7b:bb:df:4d:94:e1:
+         04:49:7b:e7:c7:77:66:c1:42:59:f3:40:91:eb:c7:98:14:cc:
+         3f:26:0d:7c:8a:c9:9e:ce:2e:82:99:5b:b3:9a:39:a4:56:8d:
+         46:13:fa:dc:6e:a0:6d:43:68:05:53:78:c9:d7:dd:45:ca:b1:
+         0f:ca:ef:e5:5f:54:8e:52:94:ee:4b:ab:0d:dd:02:81:e5:92:
+         d9:b8:6a:58:7f:14:f4:a7:9a:18:9c:51:4f:ec:5f:7e:6e:b1:
+         4a:46:bf:5d:c7:4f:19:16:f5:df:0c:fc:92:4b:d8:23:e9:7b:
+         43:38:82:5e:82:f7:04:e1
+-----BEGIN CERTIFICATE-----
+MIIFLDCCAxSgAwIBAgIJAMPTjNcrAaiqMA0GCSqGSIb3DQEBDAUAMFQxCzAJBgNV
+BAYTAkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxIjAgBgNV
+BAMMGVNIQTM4NCBhbmQgU0hBNTEyIFJvb3QgQ0EwHhcNMTUxMTI5MjIzMzI1WhcN
+MjUxMTI2MjIzMzI1WjA7MQswCQYDVQQGEwJGSTEOMAwGA1UECgwFdzEuZmkxHDAa
+BgNVBAMME3NoYTM4NC5zZXJ2ZXIudzEuZmkwggGiMA0GCSqGSIb3DQEBAQUAA4IB
+jwAwggGKAoIBgQDm91jBTdZzl79p4ZPklcK5EoOMvj3++QdZ+7pFKmDFHX8qqfk6
+HXz4fkFXMYokV2pFvRh+i+wvbAPcOLI6cxSSSz02yspRkcN1hDlERfjIrMrJq5M5
+GgoT1F2zQ0Wc+inXDetgIG1QOb+qoQR3mxMCQLphohv8n2JkW6+Lmdt9zsx9tOQW
+jFSB3YFdcb4yhGP5sJ4n8EanpNdRk0NbdKffehDDxXUtb4O1U6i/H1NFA0/l/oN0
+IuhwXkdkv8ikdpPke+FqCp8H6CZMvZrC3ItJpIm+k/eXIyAvW4hag/75GfGeV7b4
+MnVegcylWtacFpaDRsklfAStMXd5EOiC4cmANIYupoZwfiSadthk9BbBqzRAcpvF
+ljgFeUeR5N8St4B1noPwatoMuMzhWG28Iv/hNr8Rj/vzWznO0xp3lPckZPVHzrl0
+8U1QSH9j6SqsmGMY1Y4riRGzNkUfo7eV9GB8kKp6oWM6TCuyRbMhS0LB/TNH3682
+oBJMEftK5HBiTf8CAwEAAaOBmTCBljAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTI
+puSBdWl8CR2h5hTOYmVOVtiSeTAfBgNVHSMEGDAWgBQOdLUJ7Pv657prGvYrKH6p
+cNrXGDAhBgNVHREBAf8EFzAVghNzaGEzODQuc2VydmVyLncxLmZpMBYGA1UdJQEB
+/wQMMAoGCCsGAQUFBwMBMAsGA1UdDwQEAwIFoDANBgkqhkiG9w0BAQwFAAOCAgEA
+BNr9jE2uBRq8OX20brH6nmw5oVgkSVkLKtksw2STB3KwNz4knbC0btdMdVd0Gkrx
+NE+DPeuzd6CzGpDya1d7RqLL9DHYn+gfXD+zrP8tyNXyG918m7h/YRM6sRSCTVLP
+0NxvIOeUBmufbUncQZueZkHWRRWvkgBtdV+Vk+wpffmoVxoWpPmerOGG8tM4JRbj
+ofKfO36nm7nnJA/z2mbE3jQ8dViyZOLRLm2s+APZ0qm2Z9mYUXa1H6igX3Nl3VIE
+iPTm18uUg6wIKSXFqopEbXMUz5pIJKtG0YXuKYHmIwOCVzQs+OFfA1N598qzWCxg
+j1LRIG7wWvR+Uvqo+k1sqGfW2qXanFTGNDrKBjKoRTtBlW6BB5v0+2pLfO7VfzB+
+wjmNiLTJYl8UOhxInbYG2I4SHJng1nqm5Aq0IzOYOgBbLdIKBbicH53wHqDUiDUO
+R7xZ8/IIXvYRslOztIDJOxjkUUVDm3uPfSMLLmbaKbkMmBZ6K7WnN+H2IMwGVlB8
+NmvzyAAIe7vfTZThBEl758d3ZsFCWfNAkevHmBTMPyYNfIrJns4ugplbs5o5pFaN
+RhP63G6gbUNoBVN4ydfdRcqxD8rv5V9UjlKU7kurDd0CgeWS2bhqWH8U9KeaGJxR
+T+xffm6xSka/XcdPGRb13wz8kkvYI+l7QziCXoL3BOE=
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/sha384-user.key b/tests/hwsim/auth_serv/sha384-user.key
new file mode 100644 (file)
index 0000000..6a15e79
--- /dev/null
@@ -0,0 +1,38 @@
+-----BEGIN PRIVATE KEY-----
+MIIGnAIBADANBgkqhkiG9w0BAQEFAASCBoYwggaCAgEAAoIBaw1HuCl0ydhb9q0E
+epVENi+Gp7eksHMq2Rx97T29DDwFe8jpVlVWJ1b0oKq96+o6RSzYtp1UGhgSCXiw
+ZPZgrVmZAnJJJU9JceoJDl3PIhkDKfApKxz9LvrmajocRiezZoaTIKj31URKALae
+Id/aY/+ACoBBxIeZoH5g8zPDIg4jEPQJ8ul3WMfKY96vFne1SGjri5iwj72RV+9t
+Pi/jgNSEwgFvUIp/mxR9bT4EmfdXwFhDUlfb7YRA45fzewcualxQE1P+LX7919i5
+mz4zH+OQFvFRtx6VwHVq9Hea2Ix0k3/0JUl1arSbE8h3J5aO377wDUK9DDfjFc8t
+qV4S1rZaJo2Gw++sLni28HBj4iw9qOuLThVRuZA1uDiBvbap9VcJiiDy6RKyyE1X
+Y230W6bXOGKbcw4h1QDLoDOMxDJTXsVOzErCE6Be8K9SviwWFIpdF3xL1i+ddKhi
+dd/Kp59niREH4qvg68TUrQIDAQABAoIBawv9Rt9uh9gkVpSnaYAfIAhSOlLKhV7E
+PVTCv4+wgD4j+ThOqNnMOSIBIphjdHx3dQJi+KMbTZ+TkSd7oPrqFza/s/y32s41
+EXnoCSdaHH+WYqNml3zJe0ObCCZEZnXrOlGevKqvbMQFR5WXOB/gC82crF5Ugfim
+EsZmAssljTZUJDceUEbEr8tYBkgBrHgQmznWBaapKGxNrqUC7FTRwPqcjIY9F+qh
+/8FE535JKzOp7oYA6XNQDLCUMI5oALmc5lq/a9g+HQpr26LNxQW5fadOKQUwZFiJ
+nRtcQo6+JZzXdobH5FZ1oNi2uOHVSiQnnQgqhESJ6jLGWJxVUGXo6kqBWWmICF9D
+g07ky+mssXXCPvNwtG9Mc4yh2Mm+LzDJI1rgMgoA08N0j+q5fT8QzmDZEmM/Gzsf
+NP/GjsLIXE+KjMcILrxDtvbNRv/hx/ys9yQjK9+VR7+uZWmXYaxH3r7D8g5XHdBz
+5/XCpQKBtgPYnHvwMRsZsQZae25/FCUfBT97JmGhr8ifGv0dhSZKRcP4zNtGU4ow
+H6J/B/eecH6bVb4/ja/nSUlLIoAUqqJWWurXdkwZII3b3PzbkqkCnZayBy2x3OIi
+VE7bVUpCSz0EIyuUjqrwc/d3PqrIARwiuucbgXqC8gqaAEUoXQGRGGKoerZLv/dQ
+VyTlyjXDlJYLub7cLBBCo8mpii6AFbc0Js+1qZJfUp0D+12qlfu9qy1W3/efAoG2
+A3PuRMQtWn0q84o36zQaJRbMQlymiMOMQBzFmR8GUiAiXHUqPZgAPsvzs7RllCTL
+ItDiKMcpE6/6MN0ArmDHA5bnAnu29SkPRiD7rU/ZGTR2Y9uujj0DIBcNHS/bbDtT
+xEwFnshSz6vvpxu6DtJ8uvEf3wJyeZmdMJeDmrBnadqT2juZIseGHneHrjJK3ZyU
+iLRI0ulXAbziwxnkKj9QUaHK0XiSzjAAt5NRTLoALix0ittJgDMCgbYBnDEGgatN
+GRhO/Jony/N3BuF/jeKnhLS+XD1EMZOIUBeczw+TzIE0nKjhsiR3uVCG8CiZGKoM
+NdssX9P1orE8fMJbBhB0EyDZwm1lPdbMAlhOugDfVFKQKKb6zD+McuxkgtLmb666
+SSeDNdx6SniMes2b6pvt2dvSLF5olVk6Sq/WvYmBv3yB4JRa0ggxMcuGdSoxiKK5
+u+wthFhg1yZAKAkHc5mluVoweXZF5CAd321F8dSZKQKBtgEEpWTXqDv/nrOztSuA
+8JixMUf8RAseBnQ9R7MQJ+/9k8RJtEv3T1M1FsaN0kot00yP5bB6kc1BXfgcov/I
+f8a6L6JW0qtWES/vt+byHaVGCAcIF1/P8+T5hx9tJjmzAM9oT1vz3B9qpr9S+Lk4
+Lhl90pUTBqh+uJBEjUUG8WeQUXrPiidsSEshmfuuzs6sRkxNRRAUSFi11vQK5XHj
+u45mtASyli+AjiWTpiyGyFjVOQRdBz5rAoG1ErrUGzeHL9plx9NPsUgw2TMAt//g
+yu1a9yDl6oARMkWMXKFytPBwwBY6H0zE74qvVQVcxHEMLGTOiLTHU57meGfVbfW+
+ikWO82ztD30nSrQ2vH3sZjeftU98R7y8L+f9icNftUTo3oA1pU8QuOj+2J/ja2Pa
+ksRDoe8fqUCi3OhiG7dhBcuK4wc0p17qjmKS+fA/Ky4yV24LuxWp1ge737rjlrvm
+hoCJF/ERHMvfrviGjrs+Rg==
+-----END PRIVATE KEY-----
diff --git a/tests/hwsim/auth_serv/sha384-user.pem b/tests/hwsim/auth_serv/sha384-user.pem
new file mode 100644 (file)
index 0000000..6935dd3
--- /dev/null
@@ -0,0 +1,113 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 14110776913249282220 (0xc3d38cd72b01a8ac)
+    Signature Algorithm: sha384WithRSAEncryption
+        Issuer: C=FI, L=Helsinki, O=w1.fi, CN=SHA384 and SHA512 Root CA
+        Validity
+            Not Before: Nov 29 22:33:25 2015 GMT
+            Not After : Nov 26 22:33:25 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=user-sha384
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2900 bit)
+                Modulus:
+                    0d:47:b8:29:74:c9:d8:5b:f6:ad:04:7a:95:44:36:
+                    2f:86:a7:b7:a4:b0:73:2a:d9:1c:7d:ed:3d:bd:0c:
+                    3c:05:7b:c8:e9:56:55:56:27:56:f4:a0:aa:bd:eb:
+                    ea:3a:45:2c:d8:b6:9d:54:1a:18:12:09:78:b0:64:
+                    f6:60:ad:59:99:02:72:49:25:4f:49:71:ea:09:0e:
+                    5d:cf:22:19:03:29:f0:29:2b:1c:fd:2e:fa:e6:6a:
+                    3a:1c:46:27:b3:66:86:93:20:a8:f7:d5:44:4a:00:
+                    b6:9e:21:df:da:63:ff:80:0a:80:41:c4:87:99:a0:
+                    7e:60:f3:33:c3:22:0e:23:10:f4:09:f2:e9:77:58:
+                    c7:ca:63:de:af:16:77:b5:48:68:eb:8b:98:b0:8f:
+                    bd:91:57:ef:6d:3e:2f:e3:80:d4:84:c2:01:6f:50:
+                    8a:7f:9b:14:7d:6d:3e:04:99:f7:57:c0:58:43:52:
+                    57:db:ed:84:40:e3:97:f3:7b:07:2e:6a:5c:50:13:
+                    53:fe:2d:7e:fd:d7:d8:b9:9b:3e:33:1f:e3:90:16:
+                    f1:51:b7:1e:95:c0:75:6a:f4:77:9a:d8:8c:74:93:
+                    7f:f4:25:49:75:6a:b4:9b:13:c8:77:27:96:8e:df:
+                    be:f0:0d:42:bd:0c:37:e3:15:cf:2d:a9:5e:12:d6:
+                    b6:5a:26:8d:86:c3:ef:ac:2e:78:b6:f0:70:63:e2:
+                    2c:3d:a8:eb:8b:4e:15:51:b9:90:35:b8:38:81:bd:
+                    b6:a9:f5:57:09:8a:20:f2:e9:12:b2:c8:4d:57:63:
+                    6d:f4:5b:a6:d7:38:62:9b:73:0e:21:d5:00:cb:a0:
+                    33:8c:c4:32:53:5e:c5:4e:cc:4a:c2:13:a0:5e:f0:
+                    af:52:be:2c:16:14:8a:5d:17:7c:4b:d6:2f:9d:74:
+                    a8:62:75:df:ca:a7:9f:67:89:11:07:e2:ab:e0:eb:
+                    c4:d4:ad
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                85:5F:26:C0:68:70:33:79:E3:BA:57:A3:5F:52:94:38:F0:6E:53:05
+            X509v3 Authority Key Identifier: 
+                keyid:0E:74:B5:09:EC:FB:FA:E7:BA:6B:1A:F6:2B:28:7E:A9:70:DA:D7:18
+
+            X509v3 Subject Alternative Name: 
+                email:user-sha384@w1.fi
+            X509v3 Extended Key Usage: 
+                TLS Web Client Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: sha384WithRSAEncryption
+         81:95:03:32:e7:e5:e3:0e:22:0e:cc:a5:b5:96:3e:15:a8:6c:
+         f5:e2:1f:32:b9:09:71:b5:fa:f4:84:ae:e1:8c:d4:cb:ef:e3:
+         b4:58:aa:bd:bc:df:6a:9c:91:9b:5a:d4:e1:b0:1c:dc:dc:e9:
+         b6:68:71:83:e1:7e:1c:81:fd:a6:3b:14:67:1a:67:64:ed:a8:
+         3c:43:2f:cf:e1:63:51:f0:9d:1d:e7:0c:0f:58:bc:bd:bf:af:
+         ee:55:f8:1f:5a:9e:1f:c2:74:f0:8a:e4:5f:b2:19:e3:e8:c2:
+         5c:1c:39:f4:24:51:ae:d2:21:da:b8:12:97:ff:2a:d9:ff:61:
+         02:31:1f:87:3b:14:0b:7b:9a:77:11:a8:83:25:38:6a:1d:89:
+         fc:48:75:8c:2f:38:a7:66:ee:a9:65:2c:d9:f8:bf:e0:12:d6:
+         b7:11:07:d0:72:a8:76:53:32:94:39:47:be:74:69:f6:6b:13:
+         2f:eb:e1:a2:8e:32:43:0a:cc:13:ea:00:29:cc:99:7b:eb:5c:
+         06:d5:4d:ef:6e:2a:96:6b:33:a3:6f:53:0c:59:4e:89:9b:56:
+         f6:a3:94:0d:7b:21:df:0e:af:b7:df:cf:56:98:81:02:9d:e2:
+         f1:29:90:2e:7f:be:4d:24:6f:46:8d:af:ff:f9:30:7b:40:48:
+         1c:1b:68:6e:9f:ec:e2:33:51:7c:ed:ee:12:bb:3a:97:ce:85:
+         fe:d9:c3:0b:1a:a6:1b:12:bb:db:4f:f3:b1:e5:80:25:b9:62:
+         7a:e9:8e:17:44:97:cc:54:bf:8e:c3:aa:37:b2:74:e9:58:9b:
+         d7:53:00:4d:82:c2:42:ba:c1:c2:7f:00:fa:da:06:dc:98:04:
+         68:35:d6:3c:14:4e:dc:4d:e4:d8:b9:b5:e2:17:79:91:3b:d7:
+         c7:f1:ff:e7:a3:25:68:c4:96:29:c6:b9:45:e3:3d:1c:29:22:
+         2f:0b:c7:8c:8e:b6:0a:0a:82:20:0b:50:ca:e6:c6:de:01:38:
+         f9:3b:31:e0:1c:85:11:bd:a9:9e:bf:8c:f7:f2:64:03:ca:60:
+         16:2d:26:94:eb:9f:8a:d0:5e:1c:eb:3c:26:7e:03:84:d2:f0:
+         5a:b3:8a:7b:86:86:67:ce:1e:c9:c8:ad:3b:0f:08:7f:3e:54:
+         fa:ad:e4:5e:3f:c1:cb:50:3a:dd:ba:b1:0e:d2:9b:88:46:17:
+         bb:67:cf:5c:11:f3:a3:f7:0b:95:ae:25:ce:3c:e9:ca:aa:46:
+         f8:a9:8c:cf:a9:cb:bc:00:94:a1:c7:02:98:1e:e5:b1:c7:e7:
+         51:50:f7:5e:a5:c8:e9:ff:e0:50:17:cc:10:c5:f8:0a:68:ba:
+         ca:78:f8:1a:6c:ac:f2:10
+-----BEGIN CERTIFICATE-----
+MIIFAzCCAuugAwIBAgIJAMPTjNcrAaisMA0GCSqGSIb3DQEBDAUAMFQxCzAJBgNV
+BAYTAkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxIjAgBgNV
+BAMMGVNIQTM4NCBhbmQgU0hBNTEyIFJvb3QgQ0EwHhcNMTUxMTI5MjIzMzI1WhcN
+MjUxMTI2MjIzMzI1WjAzMQswCQYDVQQGEwJGSTEOMAwGA1UECgwFdzEuZmkxFDAS
+BgNVBAMMC3VzZXItc2hhMzg0MIIBjDANBgkqhkiG9w0BAQEFAAOCAXkAMIIBdAKC
+AWsNR7gpdMnYW/atBHqVRDYvhqe3pLBzKtkcfe09vQw8BXvI6VZVVidW9KCqvevq
+OkUs2LadVBoYEgl4sGT2YK1ZmQJySSVPSXHqCQ5dzyIZAynwKSsc/S765mo6HEYn
+s2aGkyCo99VESgC2niHf2mP/gAqAQcSHmaB+YPMzwyIOIxD0CfLpd1jHymPerxZ3
+tUho64uYsI+9kVfvbT4v44DUhMIBb1CKf5sUfW0+BJn3V8BYQ1JX2+2EQOOX83sH
+LmpcUBNT/i1+/dfYuZs+Mx/jkBbxUbcelcB1avR3mtiMdJN/9CVJdWq0mxPIdyeW
+jt++8A1CvQw34xXPLaleEta2WiaNhsPvrC54tvBwY+IsPajri04VUbmQNbg4gb22
+qfVXCYog8ukSsshNV2Nt9Fum1zhim3MOIdUAy6AzjMQyU17FTsxKwhOgXvCvUr4s
+FhSKXRd8S9YvnXSoYnXfyqefZ4kRB+Kr4OvE1K0CAwEAAaOBjjCBizAJBgNVHRME
+AjAAMB0GA1UdDgQWBBSFXybAaHAzeeO6V6NfUpQ48G5TBTAfBgNVHSMEGDAWgBQO
+dLUJ7Pv657prGvYrKH6pcNrXGDAcBgNVHREEFTATgRF1c2VyLXNoYTM4NEB3MS5m
+aTATBgNVHSUEDDAKBggrBgEFBQcDAjALBgNVHQ8EBAMCBaAwDQYJKoZIhvcNAQEM
+BQADggIBAIGVAzLn5eMOIg7MpbWWPhWobPXiHzK5CXG1+vSEruGM1Mvv47RYqr28
+32qckZta1OGwHNzc6bZocYPhfhyB/aY7FGcaZ2TtqDxDL8/hY1HwnR3nDA9YvL2/
+r+5V+B9anh/CdPCK5F+yGePowlwcOfQkUa7SIdq4Epf/Ktn/YQIxH4c7FAt7mncR
+qIMlOGodifxIdYwvOKdm7qllLNn4v+AS1rcRB9ByqHZTMpQ5R750afZrEy/r4aKO
+MkMKzBPqACnMmXvrXAbVTe9uKpZrM6NvUwxZTombVvajlA17Id8Or7ffz1aYgQKd
+4vEpkC5/vk0kb0aNr//5MHtASBwbaG6f7OIzUXzt7hK7OpfOhf7ZwwsaphsSu9tP
+87HlgCW5YnrpjhdEl8xUv47DqjeydOlYm9dTAE2CwkK6wcJ/APraBtyYBGg11jwU
+TtxN5Ni5teIXeZE718fx/+ejJWjElinGuUXjPRwpIi8Lx4yOtgoKgiALUMrmxt4B
+OPk7MeAchRG9qZ6/jPfyZAPKYBYtJpTrn4rQXhzrPCZ+A4TS8FqzinuGhmfOHsnI
+rTsPCH8+VPqt5F4/wctQOt26sQ7Sm4hGF7tnz1wR86P3C5WuJc486cqqRvipjM+p
+y7wAlKHHApge5bHH51FQ916lyOn/4FAXzBDF+Apousp4+BpsrPIQ
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/sha512-ca.key b/tests/hwsim/auth_serv/sha512-ca.key
new file mode 100644 (file)
index 0000000..b4f7eb2
--- /dev/null
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCgV1xtgG7ws5e4
+N+F5KfWrEMKzsP5P8PXVMiB6Rv/Wuzi1EHZjNdbUQuVV+hHRI1K2ReqXAeaNyhEE
+Jn42hGndcHKHfcAUTQWQWfCscP32Ti2YSViHD60sqZKr4agDoLkMR21BMHXgrU6W
+QED070WE0CbELVUtcb17oPh/ndh46Ftb5U6H5rpY8T13148xhNCh8yKAOcFfE9GW
+Z3mTMp+VxmcK72KL4Yga7bU3Uk5xHlFZ0rK1W0xItEi+SGfMLELalP6wAYMVtPAA
+iqepg3WSq5eNyZgTwq5jAuLP/4Bf1C7WhNveFE9WalJ3rrYEs7Rd+mOYm0QXcH8t
+IqC9UTUhfI3wJOpLGEfHieLHCDl8SYijET+hFFTYiU1jj4sQjAeY8VnC7/tmjJpC
+j6oNcbr57WwMxO/Xafo0JW3axZiyfDUlPShPbhyBjhq2/3wOKJUbeK/cY9J0CjW1
+5k8DYjSC0vGFwl4CRmhfN/5XeO9kGQR9kQjha59v2/gW4wKFnuqPyWyY4vWgcEmc
+8kqJqrkR61fwZ3H7G5ErMw/q/jR9tuqcTuRvQjh1LEtv2UxzNg68L73nhqT4UQRO
+uXkXPsUCN13Bgm3OzTul+zmbXtRlH/2oc+16IyzICj5VWpiZgC7D7Ljnlquvo1/3
+EitInFWjEl8kpsPJnBT4id/xrJHoywIDAQABAoICAFFF1ti+R/2D2ryKvqQOy7KJ
+DVfNuCpHJiSJgwLX6CgswAKvNIL3MExpGBvrZIqQkAVKDS27zeRC7zseU81IcuzG
+aZcZ+3mOzOotXJvbri7h06SkUNYs8Qd5cJnlCKfGGOYLcmqfqLBYyEPKj+JXQfKf
+G3dGzyz4wSXgIvV0ydwHUv+SjKrAHealaRXM0o00GBhuyCccn1KVFiBZlLsy5sch
+SOu3CUmD6NxVbwx6kL4vsuaHsQPSIimcEF87DjnkmYJ4EVyfd5VSIHD11yRKORc+
+GNTKwWYKwR/4v4TUqnpob9FWiKfZvZk8zU5S5XoeqKcWGtOop+wFnsD/E2DCv93K
+vbY0n5B5L5XFjtmBYuvdqXe4RH46ZgyePI3G6DSTCq5L8/+5pZlTeny4Vz77ecm8
+CU/4XOcYMIBZim9Fie4jQLpD4KNjKjhXLjpetNyHp3sIoghb90Qv5UdLZ6dnf4+D
+nxbg+tfvwltNfPgCvrOh3OcnSSLUSb5kSim0xpFtaH5QgAQhVaFaDY8GtaOnPyRG
+39XPwpAQXpt8EyW4omwtI8QL+/bciQNg0tVLHkxg7qOEPWGoaxvQbxT8EBGufRz9
+7qvl1ajGEAeaDY62HUssBW2+YhFKNLbzWBVO/S4AWPYPLMeAVQfFNVXWyS5www7P
+DfQXAt+rwLWwfvpW2C2BAoIBAQDVVXpIykVnUuQoRclLMnm8Z5DMfWOP/Oj3Em2z
+nKvnyM+rXEr7sT7XLAJa4aU0Fg27omUXZpNB6UDntWLOHXi+Zh3PgMd1CqdIclVK
+z6uGfK9TKHIQpYY7RLGcvBAjfnyv2KKcqBi2IQEXidoHLtZ2gQJJQ1Aoiw8gIQAe
+kZjXwcxlEgDdVR4+Zamj5QRfAG7Nd7PVl06gJNyCinS21/UFELz6hB4COgVjOPzr
+FvhoPrZE6QUNm76wFVXhYl9Taj/lM+0q5b88ZCJCqhma6aGOuVRaSpaTeRYC63ys
+oTYdUR5Cc7Z4h8iFW4S6Qs992MvH3k73R6/ad0o8kaUrZU1BAoIBAQDAaLP8jjc8
+4cDi3lNos0cSiF2OBazsCAsI5IRovkkugSDYK9FKOrQ0P8mFTsA+IapAe8gMIjZY
+ivRJ8dQ8beNhub9gULlNpp8VZ0QJV5jn1qp1vqW72ti28KcwPFTSmQZKMevwl6Bw
+t/s3RY3SndU3LJ1RdtZuhC9tgAGbH/Os524kvBc8sPjQkwRP8MABF/4XTS1aR7yO
+6kka1ZxJ32X7Chz7pO/IagTmAhJmbLkponWPtCvwlHx8SFE0dyC86snhb7CIr8B/
++1BBueTjUhrhADCm6X106hIgm7C2o9m+x92Y7KHM4yEjHEo8+VVC8WV5TmcXOqMM
+nqYCHeNn1tcLAoIBAQC9w2MbDJHf7uP0zt7XfPa8mIM84uyFUDsKS+I5OsvPSdkw
+XNB2QpvbWtJddQo24sckeLfjsOKcZpfNhJN3NNAKzVsHEU5a1jcnQkyMV14EKzTp
+i7irBhH49onnGYJhkEnpQZKkNwKEP6dxALZoXUl38BnQgYf0CH5T3gb1Kh4DDeh6
+nyEVwHk+l7/mgfj5aLEnI6tb+1N9MEzV8cMQQdk5wEHZtVvcLzBLqo2PsMcWM3J+
+qahNCpT8nH3gFlklIgXkI+R7nBIX7hprolNUcS28fy6Bgoeedr8VqdMk2+H/AgEg
+qz1MybucpGPUK0nWb9oU17L2U1YhxqrKZeO+TkYBAoIBAAu7Vp4jncKckUJEBBny
+NHcw0WODfRO3OdUE+f3Y/GVVgkcsBMrd4Xb+HK+AKcCgFN1xrrTusRmc/2Ay2poE
+qUSgKscYpPPTIQgRD9jx+mTIdgRP55MYuPYOnmMWiqV8pyGHAbfdxu6YiTzJhOg+
+r215zu3UrSZ38NxgXbizrgvw4Ipk3ZXZxJITJMQrDcoDSH7rOcSzcw/TwTldpPXs
+JS+1YicF24kAzeOoZK7SGkgrm7dzaOp2Y1DAqBLm4JwkRML2KHFtJfOnwzD+wLIL
+o4/sjwreWcPzMb/DPnckbnZvgVd9ti/j+XVGmFA3c7dtOJ645RhJfv+Z/M1MPT1r
+oBkCggEAWqkhZDArd1EqwauhCKwAb2Bp8IVd3rAyaBMtQZVebf467rMh0o4FaPZb
+a4oTZQEAAvlabbKiNW16kmdhzhXNIpgtsTQ1ZfagjHP3fPp0mz3XQiATudaxQBVH
+o7hKafsr2YJLWD03RO+hO2UPr/rLqN9+8/MlT5pityn1QZHpHf9qzliUhw/2zAjq
+kgygbM8UCEXl7zb7ptxaiPsxBn+ynwxgzibwLRHiePOfil8fD5hyE/5gRISrQidA
+VO5RzhqnD3kDH7Da8BPJt917CsgvZ+VffzDP4D/V+L1a/R1ldyXG+omn7qED1ui6
+V2qOAd4RYJFC9FFgNAWy22r3lSYw+g==
+-----END PRIVATE KEY-----
diff --git a/tests/hwsim/auth_serv/sha512-ca.pem b/tests/hwsim/auth_serv/sha512-ca.pem
new file mode 100644 (file)
index 0000000..2ed9314
--- /dev/null
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFkTCCA3mgAwIBAgIJAPz9Jkl2amj5MA0GCSqGSIb3DQEBDQUAMFQxCzAJBgNV
+BAYTAkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxIjAgBgNV
+BAMMGVNIQTM4NCBhbmQgU0hBNTEyIFJvb3QgQ0EwHhcNMTUxMTI5MjIzMzI0WhcN
+MjUxMTI2MjIzMzI0WjBUMQswCQYDVQQGEwJGSTERMA8GA1UEBwwISGVsc2lua2kx
+DjAMBgNVBAoMBXcxLmZpMSIwIAYDVQQDDBlTSEEzODQgYW5kIFNIQTUxMiBSb290
+IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAoFdcbYBu8LOXuDfh
+eSn1qxDCs7D+T/D11TIgekb/1rs4tRB2YzXW1ELlVfoR0SNStkXqlwHmjcoRBCZ+
+NoRp3XByh33AFE0FkFnwrHD99k4tmElYhw+tLKmSq+GoA6C5DEdtQTB14K1OlkBA
+9O9FhNAmxC1VLXG9e6D4f53YeOhbW+VOh+a6WPE9d9ePMYTQofMigDnBXxPRlmd5
+kzKflcZnCu9ii+GIGu21N1JOcR5RWdKytVtMSLRIvkhnzCxC2pT+sAGDFbTwAIqn
+qYN1kquXjcmYE8KuYwLiz/+AX9Qu1oTb3hRPVmpSd662BLO0XfpjmJtEF3B/LSKg
+vVE1IXyN8CTqSxhHx4nixwg5fEmIoxE/oRRU2IlNY4+LEIwHmPFZwu/7ZoyaQo+q
+DXG6+e1sDMTv12n6NCVt2sWYsnw1JT0oT24cgY4atv98DiiVG3iv3GPSdAo1teZP
+A2I0gtLxhcJeAkZoXzf+V3jvZBkEfZEI4Wufb9v4FuMChZ7qj8lsmOL1oHBJnPJK
+iaq5EetX8Gdx+xuRKzMP6v40fbbqnE7kb0I4dSxLb9lMczYOvC+954ak+FEETrl5
+Fz7FAjddwYJtzs07pfs5m17UZR/9qHPteiMsyAo+VVqYmYAuw+y455arr6Nf9xIr
+SJxVoxJfJKbDyZwU+Inf8ayR6MsCAwEAAaNmMGQwHQYDVR0OBBYEFA50tQns+/rn
+umsa9isofqlw2tcYMB8GA1UdIwQYMBaAFA50tQns+/rnumsa9isofqlw2tcYMBIG
+A1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDQUA
+A4ICAQCSG0Tk6pMvUxSMi9q4Bnq1jjMehEVZH6JHoADSjYDpRYj26Zjzd5k1qRua
+rdAlugMaV/Jq0kcebcvIRl1de0BPx7qfRzq39lSVDojtefjj824EsYj+rBssmwUZ
+e5XfXzxSmfEtT7Ot1PMLyCUCeg7JPr0dbdo7EVjh6XhYo0IlLsOJcKwfj/z74K14
+SlL1jXknhQgizCzt/gFkrdrFFCg0cCTjG5gKVHnn97GY61PI1CEMYGjkP2x7wv2o
+dJE09ElEPjrQOiShqfmfeUOuM6xmYzZFtVWp/M+tEQdL5WsBrN2dujHA+Ftf3xrF
+aRlGLFCzqlC+HU1CSsiI4gXXJT4Bp6WrVP/insAuuS/a8KQRkox8JvPBOqnYf/m4
+JvGJbhukEgbhUdUON4UtWwr3pTkt16SKmE3IdG/Umabi+bSkMmSzw3Iy12LOkrhT
+5OVbU+EwFolc6WUmp5VnhD/NtNdTvaTIjuujU4MyXkBfHvPj4bR62/cSXdGL4LzL
+UjlrFEN3RnFiF4/slrT4z4VRa4FqaYg+aRnMuGwPMHBjUTmyQp1yjF0kp/MYDGF7
+YO46+ep1pwx7zboB1nsKPdLzwEHvO7p6yBO2daEBCiE4RpedSjkpNhYgfHn4WVoX
+NPZChYbX8mGds3xnB6BGsfvzXEtCtmOGbDRIJm6aB7qTrfHiYA==
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/sha512-generate.sh b/tests/hwsim/auth_serv/sha512-generate.sh
new file mode 100755 (executable)
index 0000000..d692465
--- /dev/null
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+OPENSSL=openssl
+
+DIGEST="-sha512"
+DIGEST_CA="-md sha512"
+
+echo
+echo "---[ Root CA ]----------------------------------------------------------"
+echo
+
+cat ec-ca-openssl.cnf |
+       sed "s/#@CN@/commonName_default = SHA384 and SHA512 Root CA/" \
+       > ec-ca-openssl.cnf.tmp
+$OPENSSL req -config ec-ca-openssl.cnf.tmp -batch -x509 -new -newkey rsa:4096 -nodes -keyout sha512-ca.key -out sha512-ca.pem -outform PEM -days 3650 $DIGEST
+mkdir -p ec-ca/certs ec-ca/crl ec-ca/newcerts ec-ca/private
+touch ec-ca/index.txt
+rm ec-ca-openssl.cnf.tmp
+
+echo
+echo "---[ Server SHA-512 ]---------------------------------------------------"
+echo
+
+cat ec-ca-openssl.cnf |
+       sed "s/#@CN@/commonName_default = sha512.server.w1.fi/" |
+       sed "s/#@ALTNAME@/subjectAltName=critical,DNS:sha512.server.w1.fi/" \
+       > ec-ca-openssl.cnf.tmp
+$OPENSSL req -config ec-ca-openssl.cnf.tmp -batch -new -newkey rsa:3500 -nodes -keyout sha512-server.key -out sha512-server.req -outform PEM $DIGEST
+$OPENSSL ca -config ec-ca-openssl.cnf.tmp -batch -keyfile sha512-ca.key -cert sha512-ca.pem -create_serial -in sha512-server.req -out sha512-server.pem -extensions ext_server $DIGEST_CA
+rm ec-ca-openssl.cnf.tmp
+
+echo
+echo "---[ Server SHA-384 ]---------------------------------------------------"
+echo
+
+cat ec-ca-openssl.cnf |
+       sed "s/#@CN@/commonName_default = sha384.server.w1.fi/" |
+       sed "s/#@ALTNAME@/subjectAltName=critical,DNS:sha384.server.w1.fi/" \
+       > ec-ca-openssl.cnf.tmp
+$OPENSSL req -config ec-ca-openssl.cnf.tmp -batch -new -newkey rsa:3072 -nodes -keyout sha384-server.key -out sha384-server.req -outform PEM $DIGEST
+$OPENSSL ca -config ec-ca-openssl.cnf.tmp -batch -keyfile sha512-ca.key -cert sha512-ca.pem -create_serial -in sha384-server.req -out sha384-server.pem -extensions ext_server -md sha384
+rm ec-ca-openssl.cnf.tmp
+
+echo
+echo "---[ User SHA-512 ]-----------------------------------------------------"
+echo
+
+cat ec-ca-openssl.cnf |
+       sed "s/#@CN@/commonName_default = user-sha512/" |
+       sed "s/#@ALTNAME@/subjectAltName=email:user-sha512@w1.fi/" \
+       > ec-ca-openssl.cnf.tmp
+$OPENSSL req -config ec-ca-openssl.cnf.tmp -batch -new -newkey rsa:3400 -nodes -keyout sha512-user.key -out sha512-user.req -outform PEM -extensions ext_client $DIGEST
+$OPENSSL ca -config ec-ca-openssl.cnf.tmp -batch -keyfile sha512-ca.key -cert sha512-ca.pem -create_serial -in sha512-user.req -out sha512-user.pem -extensions ext_client $DIGEST_CA
+rm ec-ca-openssl.cnf.tmp
+
+echo
+echo "---[ User SHA-384 ]-----------------------------------------------------"
+echo
+
+cat ec-ca-openssl.cnf |
+       sed "s/#@CN@/commonName_default = user-sha384/" |
+       sed "s/#@ALTNAME@/subjectAltName=email:user-sha384@w1.fi/" \
+       > ec-ca-openssl.cnf.tmp
+$OPENSSL req -config ec-ca-openssl.cnf.tmp -batch -new -newkey rsa:2900 -nodes -keyout sha384-user.key -out sha384-user.req -outform PEM -extensions ext_client $DIGEST
+$OPENSSL ca -config ec-ca-openssl.cnf.tmp -batch -keyfile sha512-ca.key -cert sha512-ca.pem -create_serial -in sha384-user.req -out sha384-user.pem -extensions ext_client -md sha384
+rm ec-ca-openssl.cnf.tmp
+
+echo
+echo "---[ Verify ]-----------------------------------------------------------"
+echo
+
+$OPENSSL verify -CAfile sha512-ca.pem sha512-server.pem
+$OPENSSL verify -CAfile sha512-ca.pem sha384-server.pem
+$OPENSSL verify -CAfile sha512-ca.pem sha512-user.pem
+$OPENSSL verify -CAfile sha512-ca.pem sha384-user.pem
diff --git a/tests/hwsim/auth_serv/sha512-server.key b/tests/hwsim/auth_serv/sha512-server.key
new file mode 100644 (file)
index 0000000..8cc5e80
--- /dev/null
@@ -0,0 +1,45 @@
+-----BEGIN PRIVATE KEY-----
+MIIH7AIBADANBgkqhkiG9w0BAQEFAASCB9YwggfSAgEAAoIBtgyUrc5DYSg0X9fe
+xaXrNjYldxn7pZsOu+1u2RAbcNNKFPs+XFCihLMu/QnNxKv5+n7njugzUIoBg0I5
+Oydoi/rmXGCG6NBWWnm8KsqpC/WJ1aMldsFxi4oyKieBizGo+alsYgApzWp8LMwD
+NHdfk+fyGoyneJowKdGVO2BridD0abGCfBdztSta76bse8eb4wo8TEGYrbSkBTBV
+YFmpDRw5tLTzcPy300fmRD+PPm7QMY6F7i8s9Z2GwYJ3Ec30Fah4KhidtiwfllHW
+PLYu9ONl1J9OkuZVGOI+bh7FPV11ISx6r8r+Cz0YlkyG8qf4bbMPDcv3RYa/iCFV
+9BzMp++ySRNCzpV0+mSw5P842hTvXBBwCqgwTyL4+Vao9Pcf6TGISn3tESeJSecG
+plrTJ9xgey2RWkgRP+Cj0r2Jr8ijhKAntYmY/TxY9KjbgXu6CAvVXzB86hnVd9+F
++sT060f/cGXZ0ZF5EKcbEcqu2N+98fFU2Q2LeBxgzZ5jBAWGYKsZ58/dz+o9Df+B
+F4t0W4Wp5JPKdIbkTETUCwaNBtM1TvetKvZ30HZc/DxjLv0/QkE2ctZ4PwIDAQAB
+AoIBtglR7/y5T/W/7yz2HUhQmyW71aMLGWFopfI8x1O2cHwnCqoiRbN64oH4En87
+0DJzi46OLwF4WncSrdHWoisMuX7TP6ZG65zEDFzY+H6Qg4qQZRNrArJGUtC7Xx1L
+S/orK2HHKEbksQftHCa7TRgOV31ijyaaPq9DdQeN3aINqNiC6PYXK6UYFCQdRyNL
+WFvE8Yq4pumFmVIUnL900F877Ll3SpcvLgoaiMxgGzlW/jKLy9rA/3Y1gXQEy8DC
+Qw9nftACzXTVCYtgjzTrWKjC2qrH2p92Tz+R1VBuXUPZLMhCGGI9eYWdaaoCFsPy
+RRsDhLpExK+WcQyinPrhUinr8p8DsgL2Qn6LJCBRbSS7kYa4cT//e+ohsvelE+sv
+9nhUEpyndUW5FNm4fp29wi+mKfhFWlYXsMA5xJ2btcKZPH1iVuV3oPI6ykj2RSRc
+/ZfnXyyCKxnYlZ2mQCmB2HpU6gTwp7LJY6X//dODFtuuVXXdDKAQLTfcCIhBWcAW
+MRFjs7UeY9D+iiSmMH7NAgaWWLJUIVFKbRj6hItCjfJV/bub6kfy5AXmx9kAqv58
++muUMiWBHC15iQKB2z1ZBWNWFaa4fPlLUNo0orxDOv1vPUChs1D8SyD/7486XE9K
+VHolpWy6d/XmuQTFSbRs2E4XaWQNirXPG5FVpe4D8YnL57E1sITYTdqnYbeifZVb
++Wt+u89d4a1jEECFqHXUKixm0/kcl++UJwkYLm9eol5Ip8pp6OC6upht8p+8HHHr
+1lL4Alzwq/8iUkIy79BQQurcIAzAE2CBgzbU4Dc63yiyqRhepeOhqdCZDr35F1E3
+RxgsCsmKDIJQ2bV80Q+yrGVcR4Uz+oeG3MjAzsmQR4IvsU5jGSd2TQKB2zR/rWEJ
+WsVgMFiAyFdYI45x+bpG9tOuc6VHNX/7f0DeOlM/eXnvRwpvW9LDBwCXIkJkwOSx
+bMtlQge/RI0AwchzvEz3UMYpHYtaJmYCxUXLHc/ziYrNHfsZOVIIw1y6yrrfWGiV
+54nFdFRZx2aXZpPqa2oVUqxl3qkKEpPgLzQancS5xDcm14J65pCYbuodNkz02Buv
+8RzSakF+UJmLhBulMBHMgN0NGNnTYfomUFCb2/Plu/kK58raokOxiAgusCDgpgsR
+ohwdTjBb/GJ8VceGvooqBXVB9FJGuwKB2wn5zN9/YxvuShw7vBUPlBrrD8+gZCR7
+Zu5XaFwgYjM3OUWHf78xGfpZRCKPdyyobDjTrkTcl722WgUAfaofdFEFAST4LF/r
+rB2eEuLobwJugN9lymRJgn7Q9F6+iikD0wX+DzGTMwsCNE64F7Tp4rsnd12/kNFg
+cYcBtlANKPQCodmAkSSCwdedJ0rgqOGs6MRGGOuaCfgoz73UsaKb8S3p+9nhW4/j
+7DPc2QFbskMAG2OQipYKq2JkeW5DeXOCrXhRBKmi3NpzPl0FeCeI+tdaB9bKrJlj
+kfaRzQKB2xGoJ44NcWQU9+2sUrVdxYexOca2+2kysV6TVqEW2zPcCk3ZeWfTXFdc
+IMwAICjIrBMcg+vm6Kp4Af9NCydJa+OZWWmhfJ9JUNB/n46LvAG/UOWSCV6PolfD
+og2/OMXFZU34tGlokZk6ueds0q3kmfGB1GK3jTjCgmLkKl9l9TpXAV0bBa1u+Oi/
+oTBctGE1NgAoEU8um6+P7YDdlQovbF1H76Ts3SJ7tzH78GYL4NNbuFyNle0rB86o
+Pg76dMAbw80rAW2TnqxKBvQo2/fbzZXv8cHSZEeNyTiq5QKB2xDSGoN8kLg3VpUf
+tqhy60WuLPOlzrOmRPRFAPzT/tOqKSfa59/QXuXcZ1z3tI7DN0TLMGc9weNcytvD
+KJrZTtqsyjRrdpTQfMBzn3+sP4dXg9vw9fRmKOHLo323Vr4WPXeWBBkUGGCLr7qM
+Lw2iWNO64lwG7qOz53IVAkgQv4hHkpZdc5UKdFBef6OT+pgSG8MOEVkMfnGcqWh8
+dMbbIQ5xvHOhsplzQm/V2x7ucmFMaT/HO6FGSeIYmX/ZsWyBvfA5zJtAc79KGX0k
+Jer426hlmX1bSvfG1YJlXg==
+-----END PRIVATE KEY-----
diff --git a/tests/hwsim/auth_serv/sha512-server.pem b/tests/hwsim/auth_serv/sha512-server.pem
new file mode 100644 (file)
index 0000000..9e66993
--- /dev/null
@@ -0,0 +1,120 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 14110776913249282217 (0xc3d38cd72b01a8a9)
+    Signature Algorithm: sha512WithRSAEncryption
+        Issuer: C=FI, L=Helsinki, O=w1.fi, CN=SHA384 and SHA512 Root CA
+        Validity
+            Not Before: Nov 29 22:33:25 2015 GMT
+            Not After : Nov 26 22:33:25 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=sha512.server.w1.fi
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (3500 bit)
+                Modulus:
+                    0c:94:ad:ce:43:61:28:34:5f:d7:de:c5:a5:eb:36:
+                    36:25:77:19:fb:a5:9b:0e:bb:ed:6e:d9:10:1b:70:
+                    d3:4a:14:fb:3e:5c:50:a2:84:b3:2e:fd:09:cd:c4:
+                    ab:f9:fa:7e:e7:8e:e8:33:50:8a:01:83:42:39:3b:
+                    27:68:8b:fa:e6:5c:60:86:e8:d0:56:5a:79:bc:2a:
+                    ca:a9:0b:f5:89:d5:a3:25:76:c1:71:8b:8a:32:2a:
+                    27:81:8b:31:a8:f9:a9:6c:62:00:29:cd:6a:7c:2c:
+                    cc:03:34:77:5f:93:e7:f2:1a:8c:a7:78:9a:30:29:
+                    d1:95:3b:60:6b:89:d0:f4:69:b1:82:7c:17:73:b5:
+                    2b:5a:ef:a6:ec:7b:c7:9b:e3:0a:3c:4c:41:98:ad:
+                    b4:a4:05:30:55:60:59:a9:0d:1c:39:b4:b4:f3:70:
+                    fc:b7:d3:47:e6:44:3f:8f:3e:6e:d0:31:8e:85:ee:
+                    2f:2c:f5:9d:86:c1:82:77:11:cd:f4:15:a8:78:2a:
+                    18:9d:b6:2c:1f:96:51:d6:3c:b6:2e:f4:e3:65:d4:
+                    9f:4e:92:e6:55:18:e2:3e:6e:1e:c5:3d:5d:75:21:
+                    2c:7a:af:ca:fe:0b:3d:18:96:4c:86:f2:a7:f8:6d:
+                    b3:0f:0d:cb:f7:45:86:bf:88:21:55:f4:1c:cc:a7:
+                    ef:b2:49:13:42:ce:95:74:fa:64:b0:e4:ff:38:da:
+                    14:ef:5c:10:70:0a:a8:30:4f:22:f8:f9:56:a8:f4:
+                    f7:1f:e9:31:88:4a:7d:ed:11:27:89:49:e7:06:a6:
+                    5a:d3:27:dc:60:7b:2d:91:5a:48:11:3f:e0:a3:d2:
+                    bd:89:af:c8:a3:84:a0:27:b5:89:98:fd:3c:58:f4:
+                    a8:db:81:7b:ba:08:0b:d5:5f:30:7c:ea:19:d5:77:
+                    df:85:fa:c4:f4:eb:47:ff:70:65:d9:d1:91:79:10:
+                    a7:1b:11:ca:ae:d8:df:bd:f1:f1:54:d9:0d:8b:78:
+                    1c:60:cd:9e:63:04:05:86:60:ab:19:e7:cf:dd:cf:
+                    ea:3d:0d:ff:81:17:8b:74:5b:85:a9:e4:93:ca:74:
+                    86:e4:4c:44:d4:0b:06:8d:06:d3:35:4e:f7:ad:2a:
+                    f6:77:d0:76:5c:fc:3c:63:2e:fd:3f:42:41:36:72:
+                    d6:78:3f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                39:3B:83:DB:3C:59:8F:5C:66:D8:86:6A:22:F9:F6:6C:B4:29:37:A3
+            X509v3 Authority Key Identifier: 
+                keyid:0E:74:B5:09:EC:FB:FA:E7:BA:6B:1A:F6:2B:28:7E:A9:70:DA:D7:18
+
+            X509v3 Subject Alternative Name: critical
+                DNS:sha512.server.w1.fi
+            X509v3 Extended Key Usage: critical
+                TLS Web Server Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: sha512WithRSAEncryption
+         8f:42:08:a0:bc:c1:eb:50:ef:6a:26:b7:3e:54:a6:7a:ad:b0:
+         66:d3:1d:4c:d4:bc:63:9f:f9:b8:58:ec:33:82:9a:7e:60:28:
+         e8:2b:ee:a6:51:46:7f:bf:c4:39:71:8e:a4:d8:11:88:2e:89:
+         60:82:4a:d7:e9:a5:6e:cb:ec:4b:79:d4:48:3f:e3:fd:1f:e2:
+         6f:7e:43:bf:63:ff:e3:ec:d3:82:7f:bd:2a:3a:66:45:50:d5:
+         f7:ea:5b:28:4c:b0:f8:89:8a:03:e3:22:6a:eb:ee:09:46:6a:
+         8a:c6:c9:a7:62:41:ae:ea:42:5a:7c:16:0a:b3:33:51:5c:b7:
+         26:51:68:cb:ec:7e:6e:7c:cd:1b:24:be:c9:91:53:0f:dc:d2:
+         e0:d3:df:18:05:ca:f6:98:bf:d2:d6:c2:88:8f:93:91:2d:7b:
+         6d:3c:56:c2:0d:90:11:93:29:67:5e:c5:b7:c5:0f:e0:b3:09:
+         d6:60:ca:b5:d5:8d:ff:fd:57:6b:fb:05:23:62:8f:4e:bf:03:
+         bc:da:ba:81:a3:7f:53:f4:8f:d1:49:1c:e0:32:47:b6:b9:71:
+         d4:85:5e:a8:44:63:47:1d:9d:6b:34:eb:c5:da:02:2a:5a:07:
+         5b:3f:0c:47:f2:a3:54:5d:e0:3a:0c:eb:77:3b:d5:fd:03:1e:
+         01:f6:c5:68:3f:d6:ed:cb:f9:4c:03:06:65:a9:9a:39:6b:20:
+         d7:11:eb:62:c7:09:0d:b0:51:b4:49:ff:3e:02:7d:e4:a1:6b:
+         36:bf:f3:04:33:1f:7e:b2:69:af:7d:bb:a8:ef:7f:7e:0b:d3:
+         33:4f:8e:61:09:fa:a3:b9:d5:97:8c:0b:90:17:ce:72:52:2a:
+         de:b8:96:4d:36:c0:b8:d7:7d:9e:56:e0:38:6b:a7:02:a0:90:
+         6f:e8:ee:4f:f2:26:f3:6b:a4:75:80:8f:b0:c4:1b:d4:37:49:
+         75:4b:d9:ed:2b:11:3c:ed:a8:dd:4b:8f:01:60:4d:26:f4:2d:
+         6b:74:d5:75:79:88:2f:18:5e:76:6c:80:2c:eb:da:e2:cc:46:
+         a1:67:89:f5:f6:29:35:ae:b2:f6:79:a8:c3:43:f6:6a:a3:39:
+         d7:64:65:b7:bd:a6:c9:2d:60:70:4b:d9:60:1b:a9:a6:5e:b0:
+         cd:88:02:ae:28:57:b0:46:44:1a:ad:dc:1f:bb:e3:90:db:3c:
+         07:a1:bf:a9:31:1c:0d:97:37:78:80:8a:7f:f8:7a:60:0b:0f:
+         fe:d1:bc:38:ff:b3:72:72:80:e0:65:1d:86:90:b0:f6:7a:38:
+         1b:7b:05:b7:d9:f9:44:3e:4a:1c:2b:d4:3a:cc:db:75:20:eb:
+         6d:bf:22:4b:83:1c:4f:39
+-----BEGIN CERTIFICATE-----
+MIIFYTCCA0mgAwIBAgIJAMPTjNcrAaipMA0GCSqGSIb3DQEBDQUAMFQxCzAJBgNV
+BAYTAkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxIjAgBgNV
+BAMMGVNIQTM4NCBhbmQgU0hBNTEyIFJvb3QgQ0EwHhcNMTUxMTI5MjIzMzI1WhcN
+MjUxMTI2MjIzMzI1WjA7MQswCQYDVQQGEwJGSTEOMAwGA1UECgwFdzEuZmkxHDAa
+BgNVBAMME3NoYTUxMi5zZXJ2ZXIudzEuZmkwggHXMA0GCSqGSIb3DQEBAQUAA4IB
+xAAwggG/AoIBtgyUrc5DYSg0X9fexaXrNjYldxn7pZsOu+1u2RAbcNNKFPs+XFCi
+hLMu/QnNxKv5+n7njugzUIoBg0I5Oydoi/rmXGCG6NBWWnm8KsqpC/WJ1aMldsFx
+i4oyKieBizGo+alsYgApzWp8LMwDNHdfk+fyGoyneJowKdGVO2BridD0abGCfBdz
+tSta76bse8eb4wo8TEGYrbSkBTBVYFmpDRw5tLTzcPy300fmRD+PPm7QMY6F7i8s
+9Z2GwYJ3Ec30Fah4KhidtiwfllHWPLYu9ONl1J9OkuZVGOI+bh7FPV11ISx6r8r+
+Cz0YlkyG8qf4bbMPDcv3RYa/iCFV9BzMp++ySRNCzpV0+mSw5P842hTvXBBwCqgw
+TyL4+Vao9Pcf6TGISn3tESeJSecGplrTJ9xgey2RWkgRP+Cj0r2Jr8ijhKAntYmY
+/TxY9KjbgXu6CAvVXzB86hnVd9+F+sT060f/cGXZ0ZF5EKcbEcqu2N+98fFU2Q2L
+eBxgzZ5jBAWGYKsZ58/dz+o9Df+BF4t0W4Wp5JPKdIbkTETUCwaNBtM1TvetKvZ3
+0HZc/DxjLv0/QkE2ctZ4PwIDAQABo4GZMIGWMAwGA1UdEwEB/wQCMAAwHQYDVR0O
+BBYEFDk7g9s8WY9cZtiGaiL59my0KTejMB8GA1UdIwQYMBaAFA50tQns+/rnumsa
+9isofqlw2tcYMCEGA1UdEQEB/wQXMBWCE3NoYTUxMi5zZXJ2ZXIudzEuZmkwFgYD
+VR0lAQH/BAwwCgYIKwYBBQUHAwEwCwYDVR0PBAQDAgWgMA0GCSqGSIb3DQEBDQUA
+A4ICAQCPQgigvMHrUO9qJrc+VKZ6rbBm0x1M1Lxjn/m4WOwzgpp+YCjoK+6mUUZ/
+v8Q5cY6k2BGILolggkrX6aVuy+xLedRIP+P9H+JvfkO/Y//j7NOCf70qOmZFUNX3
+6lsoTLD4iYoD4yJq6+4JRmqKxsmnYkGu6kJafBYKszNRXLcmUWjL7H5ufM0bJL7J
+kVMP3NLg098YBcr2mL/S1sKIj5ORLXttPFbCDZARkylnXsW3xQ/gswnWYMq11Y3/
+/Vdr+wUjYo9OvwO82rqBo39T9I/RSRzgMke2uXHUhV6oRGNHHZ1rNOvF2gIqWgdb
+PwxH8qNUXeA6DOt3O9X9Ax4B9sVoP9bty/lMAwZlqZo5ayDXEetixwkNsFG0Sf8+
+An3koWs2v/MEMx9+smmvfbuo739+C9MzT45hCfqjudWXjAuQF85yUireuJZNNsC4
+132eVuA4a6cCoJBv6O5P8ibza6R1gI+wxBvUN0l1S9ntKxE87ajdS48BYE0m9C1r
+dNV1eYgvGF52bIAs69rizEahZ4n19ik1rrL2eajDQ/ZqoznXZGW3vabJLWBwS9lg
+G6mmXrDNiAKuKFewRkQardwfu+OQ2zwHob+pMRwNlzd4gIp/+HpgCw/+0bw4/7Ny
+coDgZR2GkLD2ejgbewW32flEPkocK9Q6zNt1IOttvyJLgxxPOQ==
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/sha512-user.key b/tests/hwsim/auth_serv/sha512-user.key
new file mode 100644 (file)
index 0000000..5985ea1
--- /dev/null
@@ -0,0 +1,44 @@
+-----BEGIN PRIVATE KEY-----
+MIIHtQIBADANBgkqhkiG9w0BAQEFAASCB58wggebAgEAAoIBqgDEVq3fqyK8sXHD
+9eeLAaxkWFeX9PoC8rLx/kuMBuEz/IuY1/JwkPPeOUUXn/fDNQCvS12aGtoyxBHE
+ucBF6j6ojz+tGS88Sfzvp+VTjbIdryyd+oMZondO4GIflxCTnY0GE+ZuUeltD9mX
+HkGEFwl1Jf9cB3iUXz6X5mTXSeXlmKHL4g34wDMtc+shaINM5G0gJEWl7qebruCp
+FFVpGkkjy+QzMpjnwSYJSaC31Y/w9QTjFERdfy0TwmATJ+7mPbhsQ6Rob5olyZBt
+6a4pXdjbJm/7RAW4ov11NV0aChHzAkv1hC62Gmp51PamFu7VrxrZ9TlzNGQnJied
+IqpuK0C/eap7zjtlbsgkkOwkKZiHWf7l/opJ8yWX524STzd+ekA5EoUr7YDd0Ig1
+UYkxvIsLIza7+hOyq6ugcNeZuurCOE4OG+GGTLFSpu+FqBfS/DqptZ3xxQINKugI
+g9srE1scoP8ZvKyclHgqLZPXJZM0fZnkPEzN9EK84vPH7D387cX2LMBO/6vudL/F
+VTDwdLSbvKw9lwsnNP7hiy8LUIqk+3vhClWztNwd4QIDAQABAoIBqX/9zZ1or914
+g6RuksHglmRX3spVzgHL+3GcB93Bwl+ke9Bovkg5hnDQvsTW6KpdzBN6OwuyA5pi
+jP7E5J3vRWeW8rjCGTPhO71zoyDj10BYqOpXm81DRympRu43CXxhkcRrhqVWSqhp
+U7ya4bTdW7H90klJKYb3zBM0A3sBVphk9ty1gcwuZ25zCc4elrGym5z/aFPyj1sD
+FrvCYKeCljl6uknR6zHxjP0y/U26L/qxj70Ewkh9FoKyDPWP68I2bBpPwka+sit+
+CeRNGNcosayzkv6m2BcPm3LZMzLouoWCkAszYhwXhAqSHQzFNqoCv/IW68qYGVgr
+XtKbDB/SYGbatP2+SIbPt3oW907yW/Zfv7hDvSZF3BNEVooPC6f6NWHTdGBLHCWJ
+1FvBWpSKF2uwy+s6aV2YTdB5S0myE7p9KlY/SZiHSNjWt16puC6mHyOpBc2yEGGi
+zCCANSxUEg1C6EKquk8bfJ/6WRnnEt96d5DFRFMKHDFEIxITThQDIcITuh8YLLBM
+fPDMc2HxSR5fyfkgR9wj7+hxHSoRmWNnnAnm2kr5SwMBAoHVDpslqXfYhhtcdrCm
+NqJpQxHqCYHiWLDCGl52Tjyq21quYQC4IDPk1qb9bIUjw9cYk0OlSY1tT+0z2DfG
+iN7lWSjVqlxXZihjQIkh1d2UV2SQHuAqnWnDSRwKjkWmDzLPFM4ZC52x7ZH54Rba
+iEnSDOy59Kuw05gE0+ia1AEROSmV5ROgFevEnwp3fX7/T0e9cEr5+z3LyNDY/6I4
+PHgBN9/OXhbBO+rWSFEEezQ8JEu5DfgZ9vAN8y3dNoRZcsYR/mafimygcVhKwySj
+hDi/lEoVcxIxAoHVDXE5jfRVrdKSIVMkngFuMM+p8IItpDDX3MHmFzqW8PDZu/BD
+VdqKa3Thc9f/rPwdUwOIFUfUxqIZum8n809rkAtBhxcases+E3NcHESulnM4kJNO
+gVS0TdfdaANeLXxd6zuXgxsxXU/omdqH2ZqlSFy2VvQncNJov1s6R6m5y22aOKdu
+fdgA9suzEh3PAHhqVRXGEGXakbJg/irVX15odZMn0jume5+2ajWyt6skoCR1UI9H
+FMHU5KS3mpFba7L1sG39dZS5C4R4sV3Vz4NpTtnTuKqxAoHVBcDn3RHwoSM2ESsU
+zoC7pkfwQT6Awx8d1vVO9RLA2xeliWCXJ1hJ1KSDP7RSmlqou5nyCj9DyDBQM+QE
+uPXUsoJ7aFhntT5DmrBqO6zFOofKnd7/6nI3Ex2QquqUt3f0SuXEx+aeqE7Qd/Jg
+sz8hFyZJOjBHv5IqlK8UDl89QZ84BLzuWrQ9B8k/uJfGSpyf6xQd1PJKzBg44ros
+HOXI1RG8YSPlioy/TE1dzoqNBl8tzmrlD3kQhbKTaV5JPgT4IZabUhPoP73f9W8B
+WpxgGzHzsRiBAoHVAiizU8dwk3CEo/GUqgQUzKYt50EhT4PAx+YkrIpuf9hPQE5A
+omNtZADrzQ1eNUxw8UpZ6wEUfaq/cyAzTHLvFb2ZErd1RCpCWCFpI+ksGWH8Lcxb
+CY6vPuly2CfiUm/tLcDuftI5RYF2HG/q7dpWvZ6WcrTYONiyljlyzNvHyZKa+Ip7
+xp6Q2RKyejBrdOniOjQ7EZsqVchOp8P9bUnegTPXa37FKInoZHqnb7R/N3FjnkLE
+6eKP7QE/tAWwp0WhDGs+EEqIxf7K28H0e1Xh7hYyWTChAoHVBn76/JDy92nDEWjG
+JkEJBeh88mT6ocKvFYbKrSAjBpFrPiTbHJ6Md0duRgvSB2ikGQnJfESz7Q/M5bdo
+Ssy0qH9Paugbye4FgVwQCECkfJkB3Ijn9VuR+8cdoCySXPzhWDU6UXh5taSvsHvT
+LRLyBjFC/6UTsElVCam28aujJmNI7X+LbXBij4a3J8nXO3BFqK8HIopeG2z1lyBi
+fgtLN2fTl6adq8lDYxoMBPmrEmob5lKwCPsOMCLz50WEacNK8CFZ6QUiwx1ZhJeA
+HR9JilLQkZRY
+-----END PRIVATE KEY-----
diff --git a/tests/hwsim/auth_serv/sha512-user.pem b/tests/hwsim/auth_serv/sha512-user.pem
new file mode 100644 (file)
index 0000000..df2a0bd
--- /dev/null
@@ -0,0 +1,119 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 14110776913249282219 (0xc3d38cd72b01a8ab)
+    Signature Algorithm: sha512WithRSAEncryption
+        Issuer: C=FI, L=Helsinki, O=w1.fi, CN=SHA384 and SHA512 Root CA
+        Validity
+            Not Before: Nov 29 22:33:25 2015 GMT
+            Not After : Nov 26 22:33:25 2025 GMT
+        Subject: C=FI, O=w1.fi, CN=user-sha512
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (3400 bit)
+                Modulus:
+                    00:c4:56:ad:df:ab:22:bc:b1:71:c3:f5:e7:8b:01:
+                    ac:64:58:57:97:f4:fa:02:f2:b2:f1:fe:4b:8c:06:
+                    e1:33:fc:8b:98:d7:f2:70:90:f3:de:39:45:17:9f:
+                    f7:c3:35:00:af:4b:5d:9a:1a:da:32:c4:11:c4:b9:
+                    c0:45:ea:3e:a8:8f:3f:ad:19:2f:3c:49:fc:ef:a7:
+                    e5:53:8d:b2:1d:af:2c:9d:fa:83:19:a2:77:4e:e0:
+                    62:1f:97:10:93:9d:8d:06:13:e6:6e:51:e9:6d:0f:
+                    d9:97:1e:41:84:17:09:75:25:ff:5c:07:78:94:5f:
+                    3e:97:e6:64:d7:49:e5:e5:98:a1:cb:e2:0d:f8:c0:
+                    33:2d:73:eb:21:68:83:4c:e4:6d:20:24:45:a5:ee:
+                    a7:9b:ae:e0:a9:14:55:69:1a:49:23:cb:e4:33:32:
+                    98:e7:c1:26:09:49:a0:b7:d5:8f:f0:f5:04:e3:14:
+                    44:5d:7f:2d:13:c2:60:13:27:ee:e6:3d:b8:6c:43:
+                    a4:68:6f:9a:25:c9:90:6d:e9:ae:29:5d:d8:db:26:
+                    6f:fb:44:05:b8:a2:fd:75:35:5d:1a:0a:11:f3:02:
+                    4b:f5:84:2e:b6:1a:6a:79:d4:f6:a6:16:ee:d5:af:
+                    1a:d9:f5:39:73:34:64:27:26:27:9d:22:aa:6e:2b:
+                    40:bf:79:aa:7b:ce:3b:65:6e:c8:24:90:ec:24:29:
+                    98:87:59:fe:e5:fe:8a:49:f3:25:97:e7:6e:12:4f:
+                    37:7e:7a:40:39:12:85:2b:ed:80:dd:d0:88:35:51:
+                    89:31:bc:8b:0b:23:36:bb:fa:13:b2:ab:ab:a0:70:
+                    d7:99:ba:ea:c2:38:4e:0e:1b:e1:86:4c:b1:52:a6:
+                    ef:85:a8:17:d2:fc:3a:a9:b5:9d:f1:c5:02:0d:2a:
+                    e8:08:83:db:2b:13:5b:1c:a0:ff:19:bc:ac:9c:94:
+                    78:2a:2d:93:d7:25:93:34:7d:99:e4:3c:4c:cd:f4:
+                    42:bc:e2:f3:c7:ec:3d:fc:ed:c5:f6:2c:c0:4e:ff:
+                    ab:ee:74:bf:c5:55:30:f0:74:b4:9b:bc:ac:3d:97:
+                    0b:27:34:fe:e1:8b:2f:0b:50:8a:a4:fb:7b:e1:0a:
+                    55:b3:b4:dc:1d:e1
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                2F:60:49:97:43:3C:7A:7E:22:C1:44:0B:43:78:D4:9D:7C:DF:A6:12
+            X509v3 Authority Key Identifier: 
+                keyid:0E:74:B5:09:EC:FB:FA:E7:BA:6B:1A:F6:2B:28:7E:A9:70:DA:D7:18
+
+            X509v3 Subject Alternative Name: 
+                email:user-sha512@w1.fi
+            X509v3 Extended Key Usage: 
+                TLS Web Client Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: sha512WithRSAEncryption
+         9d:58:98:97:95:49:c5:bc:be:f2:1d:01:65:ff:2b:5c:24:81:
+         71:87:05:3e:11:1d:2f:f2:16:12:d3:0e:36:72:af:87:6b:81:
+         c1:7c:aa:c8:be:be:a7:90:2c:7b:35:7c:0f:8b:67:e2:9c:da:
+         26:ad:09:fc:56:28:78:3b:3a:00:91:8d:f9:d1:39:a2:c5:3f:
+         e4:97:42:70:5c:93:93:23:5f:01:67:37:b7:d9:12:0c:14:dd:
+         9d:73:be:9e:46:47:90:21:26:6d:0e:4c:af:0b:80:41:06:94:
+         86:ef:49:66:1c:70:83:9c:1b:71:83:16:38:22:f5:a0:47:09:
+         bd:69:0f:9f:5b:19:1b:d4:44:f5:15:65:d5:6c:2b:d1:8c:c7:
+         3a:f4:a7:22:b0:53:e0:27:ff:06:c6:37:a7:cf:a6:25:2a:d4:
+         24:90:3e:46:59:6a:9b:dd:57:71:d1:79:3a:e2:6c:b5:22:19:
+         0f:dd:e6:d4:04:eb:fc:65:98:da:fd:e3:7c:04:d6:a0:2a:9e:
+         19:d8:aa:44:a7:8e:c6:7d:35:00:e5:ac:24:2f:ec:53:0a:7b:
+         3d:bc:67:f3:23:95:fd:98:8b:ba:ac:e0:25:90:b2:38:e1:bb:
+         62:a3:0c:39:bb:3b:79:40:53:91:20:10:86:88:f3:ae:ba:5a:
+         7a:eb:61:72:4d:3b:cc:fc:1c:ff:86:fb:6a:83:b8:ca:9a:34:
+         dc:66:46:e7:d9:39:59:a1:91:a9:d2:b9:38:c7:84:b9:23:10:
+         a6:21:e3:de:a1:56:90:bd:63:48:c7:10:d6:2d:2d:e0:90:ba:
+         19:3a:57:c4:ea:e4:d8:62:f3:84:c4:dd:a9:e9:fe:07:33:dc:
+         ed:7e:27:9d:4a:9e:d4:3d:12:35:84:f0:df:cf:d3:8d:7c:f8:
+         2d:cd:2b:24:70:92:40:b1:9f:38:b5:b1:34:b5:47:1b:19:6c:
+         5a:a2:ce:04:5a:e6:ce:a4:18:11:88:2c:d6:53:80:3d:87:88:
+         5b:89:63:47:0e:ed:52:7b:49:7f:0b:31:66:9c:54:5f:08:7d:
+         d7:e3:6e:6c:d6:12:a0:a8:cf:d9:69:6a:53:10:bf:67:d6:0c:
+         2e:8e:6a:9a:35:c6:0a:bd:ee:28:2b:9f:d9:af:89:0f:19:5f:
+         23:d2:f8:ce:04:69:78:a8:a3:33:3d:dc:d7:09:77:cb:51:8c:
+         80:0e:aa:07:60:34:32:b1:b7:e6:04:1c:5d:8e:53:1f:be:fe:
+         49:8a:21:a2:d8:f0:f8:ce:70:a4:b7:6e:90:ec:9d:68:f7:33:
+         08:67:59:d7:ff:f6:20:00:f5:51:79:66:e6:35:bd:29:85:62:
+         d3:e1:3a:1c:b3:8c:ef:8d
+-----BEGIN CERTIFICATE-----
+MIIFQjCCAyqgAwIBAgIJAMPTjNcrAairMA0GCSqGSIb3DQEBDQUAMFQxCzAJBgNV
+BAYTAkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxIjAgBgNV
+BAMMGVNIQTM4NCBhbmQgU0hBNTEyIFJvb3QgQ0EwHhcNMTUxMTI5MjIzMzI1WhcN
+MjUxMTI2MjIzMzI1WjAzMQswCQYDVQQGEwJGSTEOMAwGA1UECgwFdzEuZmkxFDAS
+BgNVBAMMC3VzZXItc2hhNTEyMIIByzANBgkqhkiG9w0BAQEFAAOCAbgAMIIBswKC
+AaoAxFat36sivLFxw/XniwGsZFhXl/T6AvKy8f5LjAbhM/yLmNfycJDz3jlFF5/3
+wzUAr0tdmhraMsQRxLnAReo+qI8/rRkvPEn876flU42yHa8snfqDGaJ3TuBiH5cQ
+k52NBhPmblHpbQ/Zlx5BhBcJdSX/XAd4lF8+l+Zk10nl5Zihy+IN+MAzLXPrIWiD
+TORtICRFpe6nm67gqRRVaRpJI8vkMzKY58EmCUmgt9WP8PUE4xREXX8tE8JgEyfu
+5j24bEOkaG+aJcmQbemuKV3Y2yZv+0QFuKL9dTVdGgoR8wJL9YQuthpqedT2phbu
+1a8a2fU5czRkJyYnnSKqbitAv3mqe847ZW7IJJDsJCmYh1n+5f6KSfMll+duEk83
+fnpAORKFK+2A3dCINVGJMbyLCyM2u/oTsquroHDXmbrqwjhODhvhhkyxUqbvhagX
+0vw6qbWd8cUCDSroCIPbKxNbHKD/GbysnJR4Ki2T1yWTNH2Z5DxMzfRCvOLzx+w9
+/O3F9izATv+r7nS/xVUw8HS0m7ysPZcLJzT+4YsvC1CKpPt74QpVs7TcHeECAwEA
+AaOBjjCBizAJBgNVHRMEAjAAMB0GA1UdDgQWBBQvYEmXQzx6fiLBRAtDeNSdfN+m
+EjAfBgNVHSMEGDAWgBQOdLUJ7Pv657prGvYrKH6pcNrXGDAcBgNVHREEFTATgRF1
+c2VyLXNoYTUxMkB3MS5maTATBgNVHSUEDDAKBggrBgEFBQcDAjALBgNVHQ8EBAMC
+BaAwDQYJKoZIhvcNAQENBQADggIBAJ1YmJeVScW8vvIdAWX/K1wkgXGHBT4RHS/y
+FhLTDjZyr4drgcF8qsi+vqeQLHs1fA+LZ+Kc2iatCfxWKHg7OgCRjfnROaLFP+SX
+QnBck5MjXwFnN7fZEgwU3Z1zvp5GR5AhJm0OTK8LgEEGlIbvSWYccIOcG3GDFjgi
+9aBHCb1pD59bGRvURPUVZdVsK9GMxzr0pyKwU+An/wbGN6fPpiUq1CSQPkZZapvd
+V3HReTribLUiGQ/d5tQE6/xlmNr943wE1qAqnhnYqkSnjsZ9NQDlrCQv7FMKez28
+Z/Mjlf2Yi7qs4CWQsjjhu2KjDDm7O3lAU5EgEIaI8666WnrrYXJNO8z8HP+G+2qD
+uMqaNNxmRufZOVmhkanSuTjHhLkjEKYh496hVpC9Y0jHENYtLeCQuhk6V8Tq5Nhi
+84TE3anp/gcz3O1+J51KntQ9EjWE8N/P0418+C3NKyRwkkCxnzi1sTS1RxsZbFqi
+zgRa5s6kGBGILNZTgD2HiFuJY0cO7VJ7SX8LMWacVF8IfdfjbmzWEqCoz9lpalMQ
+v2fWDC6Oapo1xgq97igrn9mviQ8ZXyPS+M4EaXioozM93NcJd8tRjIAOqgdgNDKx
+t+YEHF2OUx++/kmKIaLY8PjOcKS3bpDsnWj3MwhnWdf/9iAA9VF5ZuY1vSmFYtPh
+OhyzjO+N
+-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/user.key.pkcs8 b/tests/hwsim/auth_serv/user.key.pkcs8
new file mode 100644 (file)
index 0000000..655503d
--- /dev/null
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIt5s8O/vC7Z0CAggA
+MBQGCCqGSIb3DQMHBAh1l9fSi61IRASCAoDGCULhl5nYsWTyimj9idh/1z78xJu6
+Q+Ap6u/UiEQh3riX5DYojJPZfYTJ44IOh/Jfbv/ipr4IynDnAiZyhs8NWYAXTk2i
+U5yb1Zsf3lRxKQG8u8BhkxDdUs9GSbajvF81fWkZVpMQw1aBWVxRfXlNrqx0ObZD
+HdxyJX/wGMlV41r50LlyMOH9fiULX0ylGI9HtTNkxmUWtj9F7ATHp7qPdFGMoWzV
+LOoR5KqGmi4WhE3t+02wmlyeSXe4T4kiLGZ6T7sR6szjNHUFkWgwe2oFfd0HZDvO
+wC1HoUKeRM/c4bP+HtNo6ZeudSbXd4p822WvqbKgDldXqeq5KUHye6hQfF06E/mH
+2GnHLiGBvgMIOERitm9OTW4V2hPDGOVsyfu/fUdWoo0AoLmfDStRk7zqt8mkpRyZ
+sfqltTvbCYA9E1GT86WjF+Ugq2iEITf9rQZAyAb6pNM2CWyLGihjKhXRvR19w0rQ
+33KlccnDwbZMCwBV6njWnNYF5ir3gWMDvTaC+DGUbACNHo3hVQyHWEi7X5YdbBy/
+1Y94+5pbGohTQRWuMmwzc5sFWeweewoXWBsauK4EU5P4WxT3D8iCr96qsftmTn2V
+tD3k2W4vXBcqZkIswllqSQDYSnaxnSe/cUoYm3iehZRQutZ0PaBWmOy6jmJpEU/Q
+RTWsu7zyD/18o+yxkZR68eQn11zbIuBWjj1xDeqmjbYkh8XDC1Q6fVeFJxF9mhyF
+ttK/SPXuqyBi8eX13ViPEbIVOLpsr6S2ig3hN0/OIWVPblchYEXy1+VV4nwhA8Np
+J89pD8vfbcVTDjHCu9HhcMdT/zFsWehe8yw5zM3WsGx6NB/xJS2onRhs
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/hwsim/auth_serv/user.key.pkcs8.pkcs5v15 b/tests/hwsim/auth_serv/user.key.pkcs8.pkcs5v15
new file mode 100644 (file)
index 0000000..2626d3b
--- /dev/null
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICoTAbBgkqhkiG9w0BBQMwDgQIJ5xD8pUUfDsCAggABIICgKaalc1M4urq1NJ8
+AJoiuAcp1sNon6FUdDUtcQNFnG9H9/nt5FseYBA4tlRtJq1Qj9ow04VViJB9guTp
+kxEt2onIyPSwblGtwkM0mboyVilmqyWEPWzI2T59nphWTnLfSmBSs756k581duks
+qtaIm+yvUyI1cA1BHHaOhMApgNFzI7OFkAto55OG7kfJgcmMj1gSjSpNJ6XsofEp
+BYLl9yPzbAF/Cxci7zTiKhYe/FbvW6qEJw+EKk5L+nKx+UlP7Ssjr+rhmeB142pb
+7x4Zbelyo4SipWSpru7dZEyKFd/ZcXByoORjQT8sQaF36zVXmmv6gURKrWlznfFz
+WwaeeI+4erld98A4tXuRjwmGbkzYnUNjq1cz2y7zvW34Dgse6KaP1iOsvmHA7K+j
+hJI4jJFHvCRDGxIFZm4qZPBapPWqlN6vRJSVAX7YASqRcaNO2m6Y0umUgCtab2uF
+k4D3ahHMg0XtcLvEr0HaklGWT5YIkcDuH+Los2NwSn1z5Q4nLnmLBfmfm75oKv1O
+X/f627b4MLQxAnrcjQ2Wk0sL4a+Rnbenbi7MlyqA7Gz9fxLQdB7qrRehAiJxo+3e
+ddhvsZ9pgZeUY+o/QkX4t4oxG09BhGVF5l+d46FU6hgPjFeRiSt7st5SdU2MK4la
+Kqw6a7rDpfhb6WLMsnJyN0JwOaoOoy4UOpZYrdvSHwDvHur8YScd2DsPLMQMs0Zo
+1mjfsYiElQLRk/wSjpyqBw/3ULFTsM17Z4mTgvTdDzBd5UycvbGJ/tnDV0cpXuJg
+FVboPYqrGk5ChPePubyRa2e57HFQVu7kjzuS9NSdnKr/IVEr9Qn9OkRmprpm5Y6J
+PgfA5wA=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/hwsim/multi-bss-iface-per_sta_vif.conf b/tests/hwsim/multi-bss-iface-per_sta_vif.conf
new file mode 100644 (file)
index 0000000..f07c13b
--- /dev/null
@@ -0,0 +1,42 @@
+driver=nl80211
+
+hw_mode=g
+channel=1
+ieee80211n=1
+
+interface=wlan3
+ctrl_interface=/var/run/hostapd
+
+ssid=bss-1
+dynamic_vlan=1
+vlan_tagged_interface=dummy0
+vlan_bridge=brvlan
+wpa=2
+wpa_key_mgmt=WPA-EAP
+rsn_pairwise=CCMP
+ieee8021x=1
+auth_server_addr=127.0.0.1
+auth_server_port=18128
+auth_server_shared_secret=radius
+nas_identifier=nas.w1.fi
+vlan_naming=1
+per_sta_vif=1
+
+bss=wlan3-2
+bssid=02:00:00:00:03:01
+ctrl_interface=/var/run/hostapd
+ssid=bss-2
+
+dynamic_vlan=1
+vlan_tagged_interface=dummy0
+vlan_bridge=brvlan
+wpa=2
+wpa_key_mgmt=WPA-EAP
+rsn_pairwise=CCMP
+ieee8021x=1
+auth_server_addr=127.0.0.1
+auth_server_port=18128
+auth_server_shared_secret=radius
+nas_identifier=nas.w1.fi
+vlan_naming=1
+per_sta_vif=1
diff --git a/tests/hwsim/p2p_utils.py b/tests/hwsim/p2p_utils.py
new file mode 100644 (file)
index 0000000..6c71834
--- /dev/null
@@ -0,0 +1,372 @@
+# P2P helper functions
+# Copyright (c) 2013-2015, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import logging
+logger = logging.getLogger()
+import threading
+import time
+import Queue
+
+import hwsim_utils
+
+MGMT_SUBTYPE_PROBE_REQ = 4
+MGMT_SUBTYPE_ACTION = 13
+ACTION_CATEG_PUBLIC = 4
+
+P2P_GO_NEG_REQ = 0
+P2P_GO_NEG_RESP = 1
+P2P_GO_NEG_CONF = 2
+P2P_INVITATION_REQ = 3
+P2P_INVITATION_RESP = 4
+P2P_DEV_DISC_REQ = 5
+P2P_DEV_DISC_RESP = 6
+P2P_PROV_DISC_REQ = 7
+P2P_PROV_DISC_RESP = 8
+
+P2P_ATTR_STATUS = 0
+P2P_ATTR_MINOR_REASON_CODE = 1
+P2P_ATTR_CAPABILITY = 2
+P2P_ATTR_DEVICE_ID = 3
+P2P_ATTR_GROUP_OWNER_INTENT = 4
+P2P_ATTR_CONFIGURATION_TIMEOUT = 5
+P2P_ATTR_LISTEN_CHANNEL = 6
+P2P_ATTR_GROUP_BSSID = 7
+P2P_ATTR_EXT_LISTEN_TIMING = 8
+P2P_ATTR_INTENDED_INTERFACE_ADDR = 9
+P2P_ATTR_MANAGEABILITY = 10
+P2P_ATTR_CHANNEL_LIST = 11
+P2P_ATTR_NOTICE_OF_ABSENCE = 12
+P2P_ATTR_DEVICE_INFO = 13
+P2P_ATTR_GROUP_INFO = 14
+P2P_ATTR_GROUP_ID = 15
+P2P_ATTR_INTERFACE = 16
+P2P_ATTR_OPERATING_CHANNEL = 17
+P2P_ATTR_INVITATION_FLAGS = 18
+P2P_ATTR_OOB_GO_NEG_CHANNEL = 19
+P2P_ATTR_SERVICE_HASH = 21
+P2P_ATTR_SESSION_INFORMATION_DATA = 22
+P2P_ATTR_CONNECTION_CAPABILITY = 23
+P2P_ATTR_ADVERTISEMENT_ID = 24
+P2P_ATTR_ADVERTISED_SERVICE = 25
+P2P_ATTR_SESSION_ID = 26
+P2P_ATTR_FEATURE_CAPABILITY = 27
+P2P_ATTR_PERSISTENT_GROUP = 28
+P2P_ATTR_VENDOR_SPECIFIC = 221
+
+P2P_SC_SUCCESS = 0
+P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE = 1
+P2P_SC_FAIL_INCOMPATIBLE_PARAMS = 2
+P2P_SC_FAIL_LIMIT_REACHED = 3
+P2P_SC_FAIL_INVALID_PARAMS = 4
+P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE = 5
+P2P_SC_FAIL_PREV_PROTOCOL_ERROR = 6
+P2P_SC_FAIL_NO_COMMON_CHANNELS = 7
+P2P_SC_FAIL_UNKNOWN_GROUP = 8
+P2P_SC_FAIL_BOTH_GO_INTENT_15 = 9
+P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10
+P2P_SC_FAIL_REJECTED_BY_USER = 11
+
+WSC_ATTR_CONFIG_METHODS = 0x1008
+
+WLAN_EID_SSID = 0
+WLAN_EID_SUPP_RATES = 1
+WLAN_EID_VENDOR_SPECIFIC = 221
+
+def go_neg_pin_authorized_persistent(i_dev, r_dev, i_intent=None, r_intent=None,
+                                     i_method='enter', r_method='display',
+                                     test_data=True, r_listen=True):
+    if r_listen:
+        r_dev.p2p_listen()
+    i_dev.p2p_listen()
+    pin = r_dev.wps_read_pin()
+    logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname)
+    r_dev.p2p_go_neg_auth(i_dev.p2p_dev_addr(), pin, r_method,
+                          go_intent=r_intent, persistent=True)
+    if r_listen:
+        r_dev.p2p_listen()
+    i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), pin, i_method,
+                                  timeout=20, go_intent=i_intent,
+                                  persistent=True)
+    r_res = r_dev.p2p_go_neg_auth_result()
+    logger.debug("i_res: " + str(i_res))
+    logger.debug("r_res: " + str(r_res))
+    r_dev.dump_monitor()
+    i_dev.dump_monitor()
+    logger.info("Group formed")
+    if test_data:
+        hwsim_utils.test_connectivity_p2p(r_dev, i_dev)
+    return [i_res, r_res]
+
+def terminate_group(go, cli):
+    logger.info("Terminate persistent group")
+    go.remove_group()
+    cli.wait_go_ending_session()
+
+def invite(inv, resp, extra=None, persistent_reconnect=True, use_listen=True):
+    addr = resp.p2p_dev_addr()
+    if persistent_reconnect:
+        resp.global_request("SET persistent_reconnect 1")
+    else:
+        resp.global_request("SET persistent_reconnect 0")
+    if use_listen:
+        resp.p2p_listen()
+    else:
+        resp.p2p_find(social=True)
+    if not inv.discover_peer(addr, social=True):
+        raise Exception("Peer " + addr + " not found")
+    inv.dump_monitor()
+    peer = inv.get_peer(addr)
+    cmd = "P2P_INVITE persistent=" + peer['persistent'] + " peer=" + addr
+    if extra:
+        cmd = cmd + " " + extra
+    inv.global_request(cmd)
+
+def check_result(go, cli):
+    ev = go.wait_global_event(["P2P-GROUP-STARTED",
+                               "Failed to start AP functionality"], timeout=30)
+    if ev is None:
+        raise Exception("Timeout on group re-invocation (on GO)")
+    if "P2P-GROUP-STARTED" not in ev:
+        raise Exception("GO failed to start the group for re-invocation")
+    if "[PERSISTENT]" not in ev:
+        raise Exception("Re-invoked group not marked persistent")
+    go_res = go.group_form_result(ev)
+    if go_res['role'] != 'GO':
+        raise Exception("Persistent group GO did not become GO")
+    if not go_res['persistent']:
+        raise Exception("Persistent group not re-invoked as persistent (GO)")
+    ev = cli.wait_global_event(["P2P-GROUP-STARTED"], timeout=30)
+    if ev is None:
+        raise Exception("Timeout on group re-invocation (on client)")
+    if "[PERSISTENT]" not in ev:
+        raise Exception("Re-invoked group not marked persistent")
+    cli_res = cli.group_form_result(ev)
+    if cli_res['role'] != 'client':
+        raise Exception("Persistent group client did not become client")
+    if not cli_res['persistent']:
+        raise Exception("Persistent group not re-invoked as persistent (cli)")
+    return [go_res, cli_res]
+
+def form(go, cli, test_data=True, reverse_init=False, r_listen=True):
+    logger.info("Form a persistent group")
+    if reverse_init:
+        [i_res, r_res] = go_neg_pin_authorized_persistent(i_dev=cli, i_intent=0,
+                                                          r_dev=go, r_intent=15,
+                                                          test_data=test_data,
+                                                          r_listen=r_listen)
+    else:
+        [i_res, r_res] = go_neg_pin_authorized_persistent(i_dev=go, i_intent=15,
+                                                          r_dev=cli, r_intent=0,
+                                                          test_data=test_data,
+                                                          r_listen=r_listen)
+    if not i_res['persistent'] or not r_res['persistent']:
+        raise Exception("Formed group was not persistent")
+    terminate_group(go, cli)
+    if reverse_init:
+        return r_res
+    else:
+        return i_res
+
+def invite_from_cli(go, cli, terminate=True):
+    logger.info("Re-invoke persistent group from client")
+    invite(cli, go)
+    [go_res, cli_res] = check_result(go, cli)
+    hwsim_utils.test_connectivity_p2p(go, cli)
+    if terminate:
+        terminate_group(go, cli)
+    return [go_res, cli_res]
+
+def invite_from_go(go, cli, terminate=True):
+    logger.info("Re-invoke persistent group from GO")
+    invite(go, cli)
+    [go_res, cli_res] = check_result(go, cli)
+    hwsim_utils.test_connectivity_p2p(go, cli)
+    if terminate:
+        terminate_group(go, cli)
+    return [go_res, cli_res]
+
+def autogo(go, freq=None, persistent=None):
+    logger.info("Start autonomous GO " + go.ifname)
+    res = go.p2p_start_go(freq=freq, persistent=persistent)
+    logger.debug("res: " + str(res))
+    return res
+
+def connect_cli(go, client, social=False, freq=None):
+    logger.info("Try to connect the client to the GO")
+    pin = client.wps_read_pin()
+    go.p2p_go_authorize_client(pin)
+    res = client.p2p_connect_group(go.p2p_dev_addr(), pin, timeout=60,
+                                   social=social, freq=freq)
+    logger.info("Client connected")
+    hwsim_utils.test_connectivity_p2p(go, client)
+    return res
+
+def check_grpform_results(i_res, r_res):
+    if i_res['result'] != 'success' or r_res['result'] != 'success':
+        raise Exception("Failed group formation")
+    if i_res['ssid'] != r_res['ssid']:
+        raise Exception("SSID mismatch")
+    if i_res['freq'] != r_res['freq']:
+        raise Exception("freq mismatch")
+    if 'go_neg_freq' in r_res and i_res['go_neg_freq'] != r_res['go_neg_freq']:
+        raise Exception("go_neg_freq mismatch")
+    if i_res['freq'] != i_res['go_neg_freq']:
+        raise Exception("freq/go_neg_freq mismatch")
+    if i_res['role'] != i_res['go_neg_role']:
+        raise Exception("role/go_neg_role mismatch")
+    if 'go_neg_role' in r_res and r_res['role'] != r_res['go_neg_role']:
+        raise Exception("role/go_neg_role mismatch")
+    if i_res['go_dev_addr'] != r_res['go_dev_addr']:
+        raise Exception("GO Device Address mismatch")
+
+def go_neg_init(i_dev, r_dev, pin, i_method, i_intent, res):
+    logger.debug("Initiate GO Negotiation from i_dev")
+    try:
+        i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), pin, i_method, timeout=20, go_intent=i_intent)
+        logger.debug("i_res: " + str(i_res))
+    except Exception, e:
+        i_res = None
+        logger.info("go_neg_init thread caught an exception from p2p_go_neg_init: " + str(e))
+    res.put(i_res)
+
+def go_neg_pin(i_dev, r_dev, i_intent=None, r_intent=None, i_method='enter', r_method='display'):
+    r_dev.p2p_listen()
+    i_dev.p2p_listen()
+    pin = r_dev.wps_read_pin()
+    logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname)
+    r_dev.dump_monitor()
+    res = Queue.Queue()
+    t = threading.Thread(target=go_neg_init, args=(i_dev, r_dev, pin, i_method, i_intent, res))
+    t.start()
+    logger.debug("Wait for GO Negotiation Request on r_dev")
+    ev = r_dev.wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=15)
+    if ev is None:
+        raise Exception("GO Negotiation timed out")
+    r_dev.dump_monitor()
+    logger.debug("Re-initiate GO Negotiation from r_dev")
+    r_res = r_dev.p2p_go_neg_init(i_dev.p2p_dev_addr(), pin, r_method, go_intent=r_intent, timeout=20)
+    logger.debug("r_res: " + str(r_res))
+    r_dev.dump_monitor()
+    t.join()
+    i_res = res.get()
+    if i_res is None:
+        raise Exception("go_neg_init thread failed")
+    logger.debug("i_res: " + str(i_res))
+    logger.info("Group formed")
+    hwsim_utils.test_connectivity_p2p(r_dev, i_dev)
+    i_dev.dump_monitor()
+    return [i_res, r_res]
+
+def go_neg_pin_authorized(i_dev, r_dev, i_intent=None, r_intent=None,
+                          expect_failure=False, i_go_neg_status=None,
+                          i_method='enter', r_method='display', test_data=True,
+                          i_freq=None, r_freq=None,
+                          i_freq2=None, r_freq2=None,
+                          i_max_oper_chwidth=None, r_max_oper_chwidth=None,
+                          i_ht40=False, i_vht=False, r_ht40=False, r_vht=False):
+    i_dev.p2p_listen()
+    pin = r_dev.wps_read_pin()
+    logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname)
+    r_dev.p2p_go_neg_auth(i_dev.p2p_dev_addr(), pin, r_method,
+                          go_intent=r_intent, freq=r_freq, freq2=r_freq2,
+                          max_oper_chwidth=r_max_oper_chwidth, ht40=r_ht40,
+                          vht=r_vht)
+    r_dev.p2p_listen()
+    i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), pin, i_method,
+                                  timeout=20, go_intent=i_intent,
+                                  expect_failure=expect_failure, freq=i_freq,
+                                  freq2=i_freq2,
+                                  max_oper_chwidth=i_max_oper_chwidth,
+                                  ht40=i_ht40, vht=i_vht)
+    r_res = r_dev.p2p_go_neg_auth_result(expect_failure=expect_failure)
+    logger.debug("i_res: " + str(i_res))
+    logger.debug("r_res: " + str(r_res))
+    r_dev.dump_monitor()
+    i_dev.dump_monitor()
+    if i_go_neg_status:
+        if i_res['result'] != 'go-neg-failed':
+            raise Exception("Expected GO Negotiation failure not reported")
+        if i_res['status'] != i_go_neg_status:
+            raise Exception("Expected GO Negotiation status not seen")
+    if expect_failure:
+        return
+    logger.info("Group formed")
+    if test_data:
+        hwsim_utils.test_connectivity_p2p(r_dev, i_dev)
+    return [i_res, r_res]
+
+def go_neg_init_pbc(i_dev, r_dev, i_intent, res, freq, provdisc):
+    logger.debug("Initiate GO Negotiation from i_dev")
+    try:
+        i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), None, "pbc",
+                                      timeout=20, go_intent=i_intent, freq=freq,
+                                      provdisc=provdisc)
+        logger.debug("i_res: " + str(i_res))
+    except Exception, e:
+        i_res = None
+        logger.info("go_neg_init_pbc thread caught an exception from p2p_go_neg_init: " + str(e))
+    res.put(i_res)
+
+def go_neg_pbc(i_dev, r_dev, i_intent=None, r_intent=None, i_freq=None, r_freq=None, provdisc=False, r_listen=False):
+    if r_listen:
+        r_dev.p2p_listen()
+    else:
+        r_dev.p2p_find(social=True)
+    i_dev.p2p_find(social=True)
+    logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname)
+    r_dev.dump_monitor()
+    res = Queue.Queue()
+    t = threading.Thread(target=go_neg_init_pbc, args=(i_dev, r_dev, i_intent, res, i_freq, provdisc))
+    t.start()
+    logger.debug("Wait for GO Negotiation Request on r_dev")
+    ev = r_dev.wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=15)
+    if ev is None:
+        raise Exception("GO Negotiation timed out")
+    r_dev.dump_monitor()
+    # Allow some time for the GO Neg Resp to go out before initializing new
+    # GO Negotiation.
+    time.sleep(0.2)
+    logger.debug("Re-initiate GO Negotiation from r_dev")
+    r_res = r_dev.p2p_go_neg_init(i_dev.p2p_dev_addr(), None, "pbc",
+                                  go_intent=r_intent, timeout=20, freq=r_freq)
+    logger.debug("r_res: " + str(r_res))
+    r_dev.dump_monitor()
+    t.join()
+    i_res = res.get()
+    if i_res is None:
+        raise Exception("go_neg_init_pbc thread failed")
+    logger.debug("i_res: " + str(i_res))
+    logger.info("Group formed")
+    hwsim_utils.test_connectivity_p2p(r_dev, i_dev)
+    i_dev.dump_monitor()
+    return [i_res, r_res]
+
+def go_neg_pbc_authorized(i_dev, r_dev, i_intent=None, r_intent=None,
+                          expect_failure=False, i_freq=None, r_freq=None):
+    i_dev.p2p_listen()
+    logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname)
+    r_dev.p2p_go_neg_auth(i_dev.p2p_dev_addr(), None, "pbc",
+                          go_intent=r_intent, freq=r_freq)
+    r_dev.p2p_listen()
+    i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), None, "pbc", timeout=20,
+                                  go_intent=i_intent,
+                                  expect_failure=expect_failure, freq=i_freq)
+    r_res = r_dev.p2p_go_neg_auth_result(expect_failure=expect_failure)
+    logger.debug("i_res: " + str(i_res))
+    logger.debug("r_res: " + str(r_res))
+    r_dev.dump_monitor()
+    i_dev.dump_monitor()
+    if expect_failure:
+        return
+    logger.info("Group formed")
+    return [i_res, r_res]
+
+def remove_group(dev1, dev2):
+    dev1.remove_group()
+    try:
+        dev2.remove_group()
+    except:
+        pass
diff --git a/tests/hwsim/remotehost.py b/tests/hwsim/remotehost.py
new file mode 100644 (file)
index 0000000..bf1ccd2
--- /dev/null
@@ -0,0 +1,108 @@
+# Host class
+# Copyright (c) 2016, Qualcomm Atheros, Inc.
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import logging
+import subprocess
+import threading
+
+logger = logging.getLogger()
+
+def remote_compatible(func):
+    func.remote_compatible = True
+    return func
+
+def execute_thread(command, reply):
+    cmd = ' '.join(command)
+    logger.debug("thread run: " + cmd)
+    try:
+        status = 0
+        buf = subprocess.check_output(command, stderr=subprocess.STDOUT)
+    except subprocess.CalledProcessError as e:
+        status = e.returncode
+        buf = e.output
+
+    logger.debug("thread cmd: " + cmd)
+    logger.debug("thread exit status: " + str(status))
+    logger.debug("thread exit buf: " + str(buf))
+    reply.append(status)
+    reply.append(buf)
+
+class Host():
+    def __init__(self, host=None, ifname=None, port=None, name="", user="root"):
+        self.host = host
+        self.name = name
+        self.user = user
+        self.monitors = []
+        self.monitor_thread = None
+        self.logs = []
+        self.ifname = ifname
+        self.port = port
+        self.dev = None
+        if self.name == "" and host != None:
+            self.name = host
+
+    def local_execute(self, command):
+        logger.debug("execute: " + str(command))
+        try:
+            status = 0
+            buf = subprocess.check_output(command, stderr=subprocess.STDOUT)
+        except subprocess.CalledProcessError as e:
+            status = e.returncode
+            buf = e.output
+
+        logger.debug("status: " + str(status))
+        logger.debug("buf: " + str(buf))
+        return status, buf
+
+    def execute(self, command):
+        if self.host is None:
+            return self.local_execute(command)
+
+        cmd = ["ssh", self.user + "@" + self.host, ' '.join(command)]
+        _cmd = self.name + " execute: " + ' '.join(cmd)
+        logger.debug(_cmd)
+        try:
+            status = 0
+            buf = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
+        except subprocess.CalledProcessError as e:
+            status = e.returncode
+            buf = e.output
+
+        logger.debug(self.name + " status: " + str(status))
+        logger.debug(self.name + " buf: " + str(buf))
+        return status, buf
+
+    # async execute
+    def execute_run(self, command, res):
+        if self.host is None:
+            cmd = command
+        else:
+            cmd = ["ssh",  self.user + "@" + self.host, ' '.join(command)]
+        _cmd = self.name + " execute_run: " + ' '.join(cmd)
+        logger.debug(_cmd)
+        t = threading.Thread(target = execute_thread, args=(cmd, res))
+        t.start()
+        return t
+
+    def wait_execute_complete(self, t, wait=None):
+        if wait == None:
+            wait_str = "infinite"
+        else:
+            wait_str = str(wait) + "s"
+
+        logger.debug(self.name + " wait_execute_complete(" + wait_str + "): ")
+        if t.isAlive():
+            t.join(wait)
+
+    def add_log(self, log_file):
+        self.logs.append(log_file)
+
+    def get_logs(self, local_log_dir=None):
+        for log in self.logs:
+            if local_log_dir:
+                self.local_execute(["scp", self.user + "@[" + self.host + "]:" + log, local_log_dir])
+            self.execute(["rm", log])
+        del self.logs[:]
diff --git a/tests/hwsim/test_hs20_filter.py b/tests/hwsim/test_hs20_filter.py
new file mode 100644 (file)
index 0000000..a88f3ed
--- /dev/null
@@ -0,0 +1,199 @@
+# Hotspot 2.0 filtering tests
+# Copyright (c) 2015, Intel Deutschland GmbH
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import hostapd
+import hwsim_utils
+import socket
+import subprocess
+import binascii
+from utils import HwsimSkip, require_under_vm
+import os
+import time
+from test_ap_hs20 import build_arp, build_na, hs20_ap_params
+from test_ap_hs20 import interworking_select, interworking_connect
+import struct
+import logging
+logger = logging.getLogger()
+
+class IPAssign(object):
+    def __init__(self, iface, addr, ipv6=False):
+        self._iface = iface
+        self._addr = addr
+        self._cmd = ['ip']
+        if ipv6:
+            self._cmd.append('-6')
+        self._cmd.append('addr')
+        self._ipv6 = ipv6
+    def __enter__(self):
+        subprocess.call(self._cmd + ['add', self._addr, 'dev', self._iface])
+        if self._ipv6:
+            # wait for DAD to finish
+            while True:
+                o = subprocess.check_output(self._cmd + ['show', 'tentative', 'dev', self._iface])
+                if not self._addr in o:
+                    break
+                time.sleep(0.1)
+    def __exit__(self, type, value, traceback):
+        subprocess.call(self._cmd + ['del', self._addr, 'dev', self._iface])
+
+def hs20_filters_connect(dev, apdev, disable_dgaf=False, proxy_arp=False):
+    bssid = apdev[0]['bssid']
+    params = hs20_ap_params()
+    params['hessid'] = bssid
+
+    # Do not disable dgaf, to test that the station drops unicast IP packets
+    # encrypted with GTK.
+    params['disable_dgaf'] = '0'
+    params['proxy_arp'] = '1'
+    params['ap_isolate'] = '1'
+    params['bridge'] = 'ap-br0'
+
+    try:
+        hapd = hostapd.add_ap(apdev[0], params)
+    except:
+        # For now, do not report failures due to missing kernel support.
+        raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in the kernel")
+
+    subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
+    subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
+
+    dev[0].hs20_enable()
+
+    id = dev[0].add_cred_values({ 'realm': "example.com",
+                                  'username': "hs20-test",
+                                  'password': "password",
+                                  'ca_cert': "auth_serv/ca.pem",
+                                  'domain': "example.com",
+                                  'update_identifier': "1234" })
+    interworking_select(dev[0], bssid, "home", freq="2412")
+    interworking_connect(dev[0], bssid, "TTLS")
+
+    time.sleep(0.1)
+
+    return dev[0], hapd
+
+def _test_ip4_gtk_drop(devs, apdevs, params, dst):
+    require_under_vm()
+    procfile = '/proc/sys/net/ipv4/conf/%s/drop_unicast_in_l2_multicast' % devs[0].ifname
+    if not os.path.exists(procfile):
+        raise HwsimSkip("kernel doesn't have capability")
+
+    [dev, hapd] = hs20_filters_connect(devs, apdevs)
+    with IPAssign(dev.ifname, '10.0.0.1/24'):
+        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+        s.bind(("10.0.0.1", 12345))
+        s.settimeout(0.1)
+
+        pkt = dst
+        pkt += hapd.own_addr().replace(':', '')
+        pkt += '0800'
+        pkt += '45000020786840004011ae600a0000040a000001'
+        pkt += '30393039000c0000'
+        pkt += '61736466' # "asdf"
+        if "OK" not in hapd.request('DATA_TEST_FRAME ' + pkt):
+            raise Exception("DATA_TEST_FRAME failed")
+        try:
+            logger.info(s.recvfrom(1024))
+            logger.info("procfile=" + procfile + " val=" + open(procfile,'r').read().rstrip())
+            raise Exception("erroneously received frame!")
+        except socket.timeout:
+            # this is the expected behaviour
+            pass
+
+def test_ip4_gtk_drop_bcast(devs, apdevs, params):
+    _test_ip4_gtk_drop(devs, apdevs, params, dst='ffffffffffff')
+
+def test_ip4_gtk_drop_mcast(devs, apdevs, params):
+    _test_ip4_gtk_drop(devs, apdevs, params, dst='ff0000000000')
+
+def _test_ip6_gtk_drop(devs, apdevs, params, dst):
+    require_under_vm()
+    dev = devs[0]
+    procfile = '/proc/sys/net/ipv6/conf/%s/drop_unicast_in_l2_multicast' % devs[0].ifname
+    if not os.path.exists(procfile):
+        raise HwsimSkip("kernel doesn't have capability")
+
+    [dev, hapd] = hs20_filters_connect(devs, apdevs)
+
+    with IPAssign(dev.ifname, 'fdaa::1/48', ipv6=True):
+        s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
+        s.bind(("fdaa::1", 12345))
+        s.settimeout(0.1)
+
+        pkt = dst
+        pkt += hapd.own_addr().replace(':', '')
+        pkt += '86dd'
+        pkt += '60000000000c1140fdaa0000000000000000000000000002fdaa0000000000000000000000000001'
+        pkt += '30393039000cde31'
+        pkt += '61736466' # "asdf"
+        if "OK" not in hapd.request('DATA_TEST_FRAME ' + pkt):
+            raise Exception("DATA_TEST_FRAME failed")
+        try:
+            logger.info(s.recvfrom(1024))
+            logger.info("procfile=" + procfile + " val=" + open(procfile,'r').read().rstrip())
+            raise Exception("erroneously received frame!")
+        except socket.timeout:
+            # this is the expected behaviour
+            pass
+
+def test_ip6_gtk_drop_bcast(devs, apdevs, params):
+    _test_ip6_gtk_drop(devs, apdevs, params, dst='ffffffffffff')
+
+def test_ip6_gtk_drop_mcast(devs, apdevs, params):
+    _test_ip6_gtk_drop(devs, apdevs, params, dst='ff0000000000')
+
+def test_ip4_drop_gratuitous_arp(devs, apdevs, params):
+    require_under_vm()
+    procfile = '/proc/sys/net/ipv4/conf/%s/drop_gratuitous_arp' % devs[0].ifname
+    if not os.path.exists(procfile):
+        raise HwsimSkip("kernel doesn't have capability")
+
+    [dev, hapd] = hs20_filters_connect(devs, apdevs)
+
+    with IPAssign(dev.ifname, '10.0.0.2/24'):
+        # add an entry that can be updated by gratuitous ARP
+        subprocess.call(['ip', 'neigh', 'add', '10.0.0.1', 'lladdr', '02:00:00:00:00:ff', 'nud', 'reachable', 'dev', dev.ifname])
+        # wait for lock-time
+        time.sleep(1)
+        try:
+            ap_addr = hapd.own_addr()
+            cl_addr = dev.own_addr()
+            pkt = build_arp(cl_addr, ap_addr, 2, ap_addr, '10.0.0.1', ap_addr, '10.0.0.1')
+            pkt = binascii.hexlify(pkt)
+
+            if "OK" not in hapd.request('DATA_TEST_FRAME ' + pkt):
+                raise Exception("DATA_TEST_FRAME failed")
+
+            if hapd.own_addr() in subprocess.check_output(['ip', 'neigh', 'show']):
+                raise Exception("gratuitous ARP frame updated erroneously")
+        finally:
+            subprocess.call(['ip', 'neigh', 'del', '10.0.0.1', 'dev', dev.ifname])
+
+def test_ip6_drop_unsolicited_na(devs, apdevs, params):
+    require_under_vm()
+    procfile = '/proc/sys/net/ipv6/conf/%s/drop_unsolicited_na' % devs[0].ifname
+    if not os.path.exists(procfile):
+        raise HwsimSkip("kernel doesn't have capability")
+
+    [dev, hapd] = hs20_filters_connect(devs, apdevs)
+
+    with IPAssign(dev.ifname, 'fdaa::1/48', ipv6=True):
+        # add an entry that can be updated by unsolicited NA
+        subprocess.call(['ip', '-6', 'neigh', 'add', 'fdaa::2', 'lladdr', '02:00:00:00:00:ff', 'nud', 'reachable', 'dev', dev.ifname])
+        try:
+            ap_addr = hapd.own_addr()
+            cl_addr = dev.own_addr()
+            pkt = build_na(ap_addr, 'fdaa::2', 'ff02::1', 'fdaa::2', flags=0x20,
+                           opt=binascii.unhexlify('0201' + ap_addr.replace(':', '')))
+            pkt = binascii.hexlify(pkt)
+
+            if "OK" not in hapd.request('DATA_TEST_FRAME ' + pkt):
+                raise Exception("DATA_TEST_FRAME failed")
+
+            if hapd.own_addr() in subprocess.check_output(['ip', 'neigh', 'show']):
+                raise Exception("unsolicited NA frame updated erroneously")
+        finally:
+            subprocess.call(['ip', '-6', 'neigh', 'del', 'fdaa::2', 'dev', dev.ifname])
diff --git a/tests/hwsim/test_mbo.py b/tests/hwsim/test_mbo.py
new file mode 100644 (file)
index 0000000..b549245
--- /dev/null
@@ -0,0 +1,454 @@
+# MBO tests
+# Copyright (c) 2016, Intel Deutschland GmbH
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+from remotehost import remote_compatible
+import logging
+logger = logging.getLogger()
+
+import hostapd
+import os
+import time
+
+import hostapd
+from tshark import run_tshark
+from utils import alloc_fail, fail_test
+
+def set_reg(country_code, apdev0=None, apdev1=None, dev0=None):
+    if apdev0:
+        hostapd.cmd_execute(apdev0, ['iw', 'reg', 'set', country_code])
+    if apdev1:
+        hostapd.cmd_execute(apdev1, ['iw', 'reg', 'set', country_code])
+    if dev0:
+        dev0.cmd_execute(['iw', 'reg', 'set', country_code])
+
+def run_mbo_supp_oper_classes(dev, apdev, hapd, hapd2, country):
+    """MBO and supported operating classes"""
+    addr = dev[0].own_addr()
+
+    res2 = None
+    res5 = None
+
+    dev[0].flush_scan_cache()
+    dev[0].dump_monitor()
+
+    logger.info("Country: " + country)
+    set_reg(country, apdev[0], apdev[1], dev[0])
+    for j in range(5):
+        ev = dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=5)
+        if ev is None:
+            raise Exception("No regdom change event")
+        if "alpha2=" + country in ev:
+            break
+    dev[0].dump_monitor()
+    dev[1].dump_monitor()
+    dev[2].dump_monitor()
+    if hapd:
+        hapd.set("country_code", country)
+        hapd.enable()
+        dev[0].scan_for_bss(hapd.own_addr(), 5180, force_scan=True)
+        dev[0].connect("test-wnm-mbo", key_mgmt="NONE", scan_freq="5180")
+        sta = hapd.get_sta(addr)
+        res5 = sta['supp_op_classes'][2:]
+        dev[0].request("REMOVE_NETWORK all")
+        hapd.disable()
+        dev[0].wait_disconnected()
+        dev[0].dump_monitor()
+
+    hapd2.set("country_code", country)
+    hapd2.enable()
+    dev[0].scan_for_bss(hapd2.own_addr(), 2412, force_scan=True)
+    dev[0].connect("test-wnm-mbo-2", key_mgmt="NONE", scan_freq="2412")
+    sta = hapd2.get_sta(addr)
+    res2 = sta['supp_op_classes'][2:]
+    dev[0].request("REMOVE_NETWORK all")
+    hapd2.disable()
+    dev[0].wait_disconnected()
+    dev[0].dump_monitor()
+
+    return res2, res5
+
+def test_mbo_supp_oper_classes(dev, apdev):
+    """MBO and supported operating classes"""
+    params = { 'ssid': "test-wnm-mbo",
+               'mbo': '1',
+               "country_code": "US",
+               'ieee80211d': '1',
+               "ieee80211n": "1",
+               "hw_mode": "a",
+               "channel": "36" }
+    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
+
+    params = { 'ssid': "test-wnm-mbo-2",
+               'mbo': '1',
+               "country_code": "US",
+               'ieee80211d': '1',
+               "ieee80211n": "1",
+               "hw_mode": "g",
+               "channel": "1" }
+    hapd2 = hostapd.add_ap(apdev[1], params, no_enable=True)
+
+    try:
+        za2, za5 = run_mbo_supp_oper_classes(dev, apdev, hapd, hapd2, "ZA")
+        fi2, fi5 = run_mbo_supp_oper_classes(dev, apdev, hapd, hapd2, "FI")
+        us2, us5 = run_mbo_supp_oper_classes(dev, apdev, hapd, hapd2, "US")
+        jp2, jp5 = run_mbo_supp_oper_classes(dev, apdev, hapd, hapd2, "JP")
+        bd2, bd5 = run_mbo_supp_oper_classes(dev, apdev, None, hapd2, "BD")
+        kz2, kz5 = run_mbo_supp_oper_classes(dev, apdev, None, hapd2, "KZ")
+    finally:
+        dev[0].dump_monitor()
+        set_reg("00", apdev[0], apdev[1], dev[0])
+        ev = dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=1)
+
+    za = "515354737475767778797a7b808182"
+    fi = "515354737475767778797a7b808182"
+    us = "515354737475767778797a7b7c7d7e7f808182"
+    jp = "51525354737475767778797a7b808182"
+    bd = "5153547c7d7e7f80"
+    kz = "515354"
+
+    tests = [ ("ZA", za, za2, za5, True),
+              ("FI", fi, fi2, fi5, True),
+              ("US", us, us2, us5, True),
+              ("JP", jp, jp2, jp5, True),
+              ("BD", bd, bd2, bd5, False),
+              ("KZ", kz, kz2, kz5, False) ]
+    for country, expected, res2, res5, inc5 in tests:
+        # For now, allow operating class 129 to be missing since not all
+        # installed regdb files include the 160 MHz channels.
+        expected2 = expected.replace('808182', '8082')
+        # For now, allow operating classes 121-123 to be missing since not all
+        # installed regdb files include the related US DFS channels.
+        expected2 = expected2.replace('78797a7b7c', '787c')
+        if res2 != expected and res2 != expected2:
+            raise Exception("Unexpected supp_op_class string (country=%s, 2.4 GHz): %s (expected: %s)" % (country, res2, expected))
+        if inc5 and res5 != expected and res5 != expected2:
+            raise Exception("Unexpected supp_op_class string (country=%s, 5 GHz): %s (expected: %s)" % (country, res5, expected))
+
+def test_mbo_assoc_disallow(dev, apdev, params):
+    """MBO and association disallowed"""
+    hapd1 = hostapd.add_ap(apdev[0], { "ssid": "MBO", "mbo": "1" })
+    hapd2 = hostapd.add_ap(apdev[1], { "ssid": "MBO", "mbo": "1" })
+
+    logger.debug("Set mbo_assoc_disallow with invalid value")
+    if "FAIL" not in hapd1.request("SET mbo_assoc_disallow 2"):
+        raise Exception("Set mbo_assoc_disallow for AP1 succeeded unexpectedly with value 2")
+
+    logger.debug("Disallow associations to AP1 and allow association to AP2")
+    if "OK" not in hapd1.request("SET mbo_assoc_disallow 1"):
+        raise Exception("Failed to set mbo_assoc_disallow for AP1")
+    if "OK" not in hapd2.request("SET mbo_assoc_disallow 0"):
+        raise Exception("Failed to set mbo_assoc_disallow for AP2")
+
+    dev[0].connect("MBO", key_mgmt="NONE", scan_freq="2412")
+
+    out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
+                     "wlan.fc.type == 0 && wlan.fc.type_subtype == 0x00",
+                     wait=False)
+    if "Destination address: " + hapd1.own_addr() in out:
+        raise Exception("Association request sent to disallowed AP")
+
+    timestamp = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
+                           "wlan.fc.type_subtype == 0x00",
+                           display=['frame.time'], wait=False)
+
+    logger.debug("Allow associations to AP1 and disallow associations to AP2")
+    if "OK" not in hapd1.request("SET mbo_assoc_disallow 0"):
+        raise Exception("Failed to set mbo_assoc_disallow for AP1")
+    if "OK" not in hapd2.request("SET mbo_assoc_disallow 1"):
+        raise Exception("Failed to set mbo_assoc_disallow for AP2")
+
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected()
+
+    # Force new scan, so the assoc_disallowed indication is updated */
+    dev[0].request("FLUSH")
+
+    dev[0].connect("MBO", key_mgmt="NONE", scan_freq="2412")
+
+    filter = 'wlan.fc.type == 0 && wlan.fc.type_subtype == 0x00 && frame.time > "' + timestamp.rstrip() + '"'
+    out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
+                     filter, wait=False)
+    if "Destination address: " + hapd2.own_addr() in out:
+        raise Exception("Association request sent to disallowed AP 2")
+
+def test_mbo_assoc_disallow_ignore(dev, apdev):
+    """MBO and ignoring disallowed association"""
+    try:
+        _test_mbo_assoc_disallow_ignore(dev, apdev)
+    finally:
+        dev[0].request("SCAN_INTERVAL 5")
+
+def _test_mbo_assoc_disallow_ignore(dev, apdev):
+    hapd1 = hostapd.add_ap(apdev[0], { "ssid": "MBO", "mbo": "1" })
+    if "OK" not in hapd1.request("SET mbo_assoc_disallow 1"):
+        raise Exception("Failed to set mbo_assoc_disallow for AP1")
+
+    if "OK" not in dev[0].request("SCAN_INTERVAL 1"):
+        raise Exception("Failed to set scan interval")
+    dev[0].connect("MBO", key_mgmt="NONE", scan_freq="2412", wait_connect=False)
+    ev = dev[0].wait_event(["CTRL-EVENT-NETWORK-NOT-FOUND"], timeout=10)
+    if ev is None:
+        raise Exception("CTRL-EVENT-NETWORK-NOT-FOUND not seen")
+
+    if "OK" not in dev[0].request("SET ignore_assoc_disallow 1"):
+        raise Exception("Failed to set ignore_assoc_disallow")
+    ev = dev[0].wait_event(["CTRL-EVENT-ASSOC-REJECT"], timeout=10)
+    if ev is None:
+        raise Exception("CTRL-EVENT-ASSOC-REJECT not seen")
+    if "status_code=17" not in ev:
+        raise Exception("Unexpected association reject reason: " + ev)
+
+    if "OK" not in hapd1.request("SET mbo_assoc_disallow 0"):
+        raise Exception("Failed to set mbo_assoc_disallow for AP1")
+    dev[0].wait_connected()
+
+@remote_compatible
+def test_mbo_cell_capa_update(dev, apdev):
+    """MBO cellular data capability update"""
+    ssid = "test-wnm-mbo"
+    params = { 'ssid': ssid, 'mbo': '1' }
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+    if "OK" not in dev[0].request("SET mbo_cell_capa 1"):
+        raise Exception("Failed to set STA as cellular data capable")
+
+    dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
+
+    addr = dev[0].own_addr()
+    sta = hapd.get_sta(addr)
+    if 'mbo_cell_capa' not in sta or sta['mbo_cell_capa'] != '1':
+        raise Exception("mbo_cell_capa missing after association")
+
+    if "OK" not in dev[0].request("SET mbo_cell_capa 3"):
+        raise Exception("Failed to set STA as cellular data not-capable")
+    # Duplicate update for additional code coverage
+    if "OK" not in dev[0].request("SET mbo_cell_capa 3"):
+        raise Exception("Failed to set STA as cellular data not-capable")
+
+    time.sleep(0.2)
+    sta = hapd.get_sta(addr)
+    if 'mbo_cell_capa' not in sta:
+        raise Exception("mbo_cell_capa missing after update")
+    if sta['mbo_cell_capa'] != '3':
+        raise Exception("mbo_cell_capa not updated properly")
+
+@remote_compatible
+def test_mbo_cell_capa_update_pmf(dev, apdev):
+    """MBO cellular data capability update with PMF required"""
+    ssid = "test-wnm-mbo"
+    passphrase = "12345678"
+    params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
+    params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
+    params["ieee80211w"] = "2"
+    params['mbo'] = '1'
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+    if "OK" not in dev[0].request("SET mbo_cell_capa 1"):
+        raise Exception("Failed to set STA as cellular data capable")
+
+    dev[0].connect(ssid, psk=passphrase, key_mgmt="WPA-PSK-SHA256",
+                   proto="WPA2", ieee80211w="2", scan_freq="2412")
+
+    addr = dev[0].own_addr()
+    sta = hapd.get_sta(addr)
+    if 'mbo_cell_capa' not in sta or sta['mbo_cell_capa'] != '1':
+        raise Exception("mbo_cell_capa missing after association")
+
+    if "OK" not in dev[0].request("SET mbo_cell_capa 3"):
+        raise Exception("Failed to set STA as cellular data not-capable")
+
+    time.sleep(0.2)
+    sta = hapd.get_sta(addr)
+    if 'mbo_cell_capa' not in sta:
+        raise Exception("mbo_cell_capa missing after update")
+    if sta['mbo_cell_capa'] != '3':
+        raise Exception("mbo_cell_capa not updated properly")
+
+def test_mbo_wnm_token_wrap(dev, apdev):
+    """MBO WNM token wrap around"""
+    ssid = "test-wnm-mbo"
+    params = { 'ssid': ssid, 'mbo': '1' }
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+
+    dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
+
+    # Trigger transmission of 256 WNM-Notification frames to wrap around the
+    # 8-bit mbo_wnm_token counter.
+    for i in range(128):
+        if "OK" not in dev[0].request("SET mbo_cell_capa 1"):
+            raise Exception("Failed to set STA as cellular data capable")
+        if "OK" not in dev[0].request("SET mbo_cell_capa 3"):
+            raise Exception("Failed to set STA as cellular data not-capable")
+
+@remote_compatible
+def test_mbo_non_pref_chan(dev, apdev):
+    """MBO non-preferred channel list"""
+    ssid = "test-wnm-mbo"
+    params = { 'ssid': ssid, 'mbo': '1' }
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+    if "FAIL" not in dev[0].request("SET non_pref_chan 81:7:200:99"):
+        raise Exception("Invalid non_pref_chan value accepted")
+    if "FAIL" not in dev[0].request("SET non_pref_chan 81:15:200:3"):
+        raise Exception("Invalid non_pref_chan value accepted")
+    if "FAIL" not in dev[0].request("SET non_pref_chan 81:7:200:3 81:7:201:3"):
+        raise Exception("Invalid non_pref_chan value accepted")
+    if "OK" not in dev[0].request("SET non_pref_chan 81:7:200:3"):
+        raise Exception("Failed to set non-preferred channel list")
+    if "OK" not in dev[0].request("SET non_pref_chan 81:7:200:1 81:9:100:2"):
+        raise Exception("Failed to set non-preferred channel list")
+
+    dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
+
+    addr = dev[0].own_addr()
+    sta = hapd.get_sta(addr)
+    logger.debug("STA: " + str(sta))
+    if 'non_pref_chan[0]' not in sta:
+        raise Exception("Missing non_pref_chan[0] value (assoc)")
+    if sta['non_pref_chan[0]'] != '81:200:1:7':
+        raise Exception("Unexpected non_pref_chan[0] value (assoc)")
+    if 'non_pref_chan[1]' not in sta:
+        raise Exception("Missing non_pref_chan[1] value (assoc)")
+    if sta['non_pref_chan[1]'] != '81:100:2:9':
+        raise Exception("Unexpected non_pref_chan[1] value (assoc)")
+    if 'non_pref_chan[2]' in sta:
+        raise Exception("Unexpected non_pref_chan[2] value (assoc)")
+
+    if "OK" not in dev[0].request("SET non_pref_chan 81:9:100:2"):
+        raise Exception("Failed to update non-preferred channel list")
+    time.sleep(0.1)
+    sta = hapd.get_sta(addr)
+    logger.debug("STA: " + str(sta))
+    if 'non_pref_chan[0]' not in sta:
+        raise Exception("Missing non_pref_chan[0] value (update 1)")
+    if sta['non_pref_chan[0]'] != '81:100:2:9':
+        raise Exception("Unexpected non_pref_chan[0] value (update 1)")
+    if 'non_pref_chan[1]' in sta:
+        raise Exception("Unexpected non_pref_chan[1] value (update 1)")
+
+    if "OK" not in dev[0].request("SET non_pref_chan 81:9:100:2 81:10:100:2 81:8:100:2 81:7:100:1 81:5:100:1"):
+        raise Exception("Failed to update non-preferred channel list")
+    time.sleep(0.1)
+    sta = hapd.get_sta(addr)
+    logger.debug("STA: " + str(sta))
+    if 'non_pref_chan[0]' not in sta:
+        raise Exception("Missing non_pref_chan[0] value (update 2)")
+    if sta['non_pref_chan[0]'] != '81:100:1:7,5':
+        raise Exception("Unexpected non_pref_chan[0] value (update 2)")
+    if 'non_pref_chan[1]' not in sta:
+        raise Exception("Missing non_pref_chan[1] value (update 2)")
+    if sta['non_pref_chan[1]'] != '81:100:2:9,10,8':
+        raise Exception("Unexpected non_pref_chan[1] value (update 2)")
+    if 'non_pref_chan[2]' in sta:
+        raise Exception("Unexpected non_pref_chan[2] value (update 2)")
+
+    if "OK" not in dev[0].request("SET non_pref_chan 81:5:90:2 82:14:91:2"):
+        raise Exception("Failed to update non-preferred channel list")
+    time.sleep(0.1)
+    sta = hapd.get_sta(addr)
+    logger.debug("STA: " + str(sta))
+    if 'non_pref_chan[0]' not in sta:
+        raise Exception("Missing non_pref_chan[0] value (update 3)")
+    if sta['non_pref_chan[0]'] != '81:90:2:5':
+        raise Exception("Unexpected non_pref_chan[0] value (update 3)")
+    if 'non_pref_chan[1]' not in sta:
+        raise Exception("Missing non_pref_chan[1] value (update 3)")
+    if sta['non_pref_chan[1]'] != '82:91:2:14':
+        raise Exception("Unexpected non_pref_chan[1] value (update 3)")
+    if 'non_pref_chan[2]' in sta:
+        raise Exception("Unexpected non_pref_chan[2] value (update 3)")
+
+    if "OK" not in dev[0].request("SET non_pref_chan "):
+        raise Exception("Failed to update non-preferred channel list")
+    time.sleep(0.1)
+    sta = hapd.get_sta(addr)
+    logger.debug("STA: " + str(sta))
+    if 'non_pref_chan[0]' in sta:
+        raise Exception("Unexpected non_pref_chan[0] value (update 4)")
+
+@remote_compatible
+def test_mbo_sta_supp_op_classes(dev, apdev):
+    """MBO STA supported operating classes"""
+    ssid = "test-wnm-mbo"
+    params = { 'ssid': ssid, 'mbo': '1' }
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
+
+    addr = dev[0].own_addr()
+    sta = hapd.get_sta(addr)
+    logger.debug("STA: " + str(sta))
+    if 'supp_op_classes' not in sta:
+        raise Exception("No supp_op_classes")
+    supp = bytearray(sta['supp_op_classes'].decode("hex"))
+    if supp[0] != 81:
+        raise Exception("Unexpected current operating class %d" % supp[0])
+    if 115 not in supp:
+        raise Exception("Operating class 115 missing")
+
+def test_mbo_failures(dev, apdev):
+    """MBO failure cases"""
+    ssid = "test-wnm-mbo"
+    params = { 'ssid': ssid, 'mbo': '1' }
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    with alloc_fail(dev[0], 1, "wpas_mbo_ie"):
+        dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
+
+    with alloc_fail(dev[0], 1, "wpas_mbo_send_wnm_notification"):
+        if "OK" not in dev[0].request("SET mbo_cell_capa 1"):
+            raise Exception("Failed to set STA as cellular data capable")
+    with fail_test(dev[0], 1, "wpas_mbo_send_wnm_notification"):
+        if "OK" not in dev[0].request("SET mbo_cell_capa 3"):
+            raise Exception("Failed to set STA as cellular data not-capable")
+    with alloc_fail(dev[0], 1, "wpas_mbo_update_non_pref_chan"):
+        if "FAIL" not in dev[0].request("SET non_pref_chan 81:7:200:3"):
+            raise Exception("non_pref_chan value accepted during OOM")
+    with alloc_fail(dev[0], 2, "wpas_mbo_update_non_pref_chan"):
+        if "FAIL" not in dev[0].request("SET non_pref_chan 81:7:200:3"):
+            raise Exception("non_pref_chan value accepted during OOM")
+
+def test_mbo_wnm_bss_tm_ie_parsing(dev, apdev):
+    """MBO BSS transition request MBO IE parsing"""
+    ssid = "test-wnm-mbo"
+    params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+    addr = dev[0].own_addr()
+    dev[0].connect(ssid, psk="12345678", key_mgmt="WPA-PSK",
+                   proto="WPA2", ieee80211w="0", scan_freq="2412")
+
+    dev[0].request("SET ext_mgmt_frame_handling 1")
+    hdr = "d0003a01" + addr.replace(':', '') + bssid.replace(':', '') + bssid.replace(':', '') + "3000"
+    btm_hdr = "0a070100030001"
+
+    tests = [ ("Truncated attribute in MBO IE", "dd06506f9a160101"),
+              ("Unexpected cell data capa attribute length in MBO IE",
+               "dd09506f9a160501030500"),
+              ("Unexpected transition reason attribute length in MBO IE",
+               "dd06506f9a160600"),
+              ("Unexpected assoc retry delay attribute length in MBO IE",
+               "dd0c506f9a160100080200000800"),
+              ("Unknown attribute id 255 in MBO IE",
+               "dd06506f9a16ff00") ]
+
+    for test, mbo_ie in tests:
+        logger.info(test)
+        dev[0].request("NOTE " + test)
+        frame = hdr + btm_hdr + mbo_ie
+        if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + frame):
+            raise Exception("MGMT_RX_PROCESS failed")
+
+    logger.info("Unexpected association retry delay")
+    dev[0].request("NOTE Unexpected association retry delay")
+    btm_hdr = "0a070108030001112233445566778899aabbcc"
+    mbo_ie = "dd08506f9a1608020000"
+    frame = hdr + btm_hdr + mbo_ie
+    if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + frame):
+        raise Exception("MGMT_RX_PROCESS failed")
+
+    dev[0].request("SET ext_mgmt_frame_handling 0")
diff --git a/tests/hwsim/test_rrm.py b/tests/hwsim/test_rrm.py
new file mode 100644 (file)
index 0000000..a33280e
--- /dev/null
@@ -0,0 +1,323 @@
+# Radio measurement
+# Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+# Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import re
+import logging
+logger = logging.getLogger()
+
+import hostapd
+from utils import HwsimSkip
+
+nr="00112233445500000000510107"
+lci="01000800101298c0b512926666f6c2f1001c00004104050000c00012"
+civic="01000b0011223344556677889900998877665544332211aabbccddeeff"
+
+def check_nr_results(dev, bssids=None, lci=False, civic=False):
+    if bssids is None:
+        ev = dev.wait_event(["RRM-NEIGHBOR-REP-REQUEST-FAILED" ], timeout=10)
+        if ev is None:
+            raise Exception("RRM neighbor report failure not received")
+        return
+
+    received = []
+    for bssid in bssids:
+        ev = dev.wait_event(["RRM-NEIGHBOR-REP-RECEIVED"], timeout=10)
+        if ev is None:
+            raise Exception("RRM report result not indicated")
+        received.append(ev)
+
+    for bssid in bssids:
+        found = False
+        for r in received:
+            if "RRM-NEIGHBOR-REP-RECEIVED bssid=" + bssid in r:
+                if lci and "lci=" not in r:
+                    raise Exception("LCI data not reported for %s" % bssid)
+                if civic and "civic=" not in r:
+                    raise Exception("civic data not reported for %s" % bssid)
+                received.remove(r)
+                found = True
+                break
+        if not found:
+            raise Exception("RRM report result for %s not indicated" % bssid)
+
+def test_rrm_neighbor_db(dev, apdev):
+    """hostapd ctrl_iface SET_NEIGHBOR"""
+    params = { "ssid": "test", "rrm_neighbor_report": "1" }
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    # Bad BSSID
+    if "FAIL" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:gg ssid=\"test1\" nr=" + nr):
+        raise Exception("Set neighbor succeeded unexpectedly")
+
+    # Bad SSID
+    if "FAIL" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=test1 nr=" + nr):
+        raise Exception("Set neighbor succeeded unexpectedly")
+
+    # No SSID
+    if "FAIL" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 nr=" + nr):
+        raise Exception("Set neighbor succeeded unexpectedly")
+
+    # No NR
+    if "FAIL" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\""):
+        raise Exception("Set neighbor succeeded unexpectedly")
+
+    # Odd length of NR
+    if "FAIL" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\" nr=" + nr[:-1]):
+        raise Exception("Set neighbor succeeded unexpectedly")
+
+    # No entry yet in database
+    if "FAIL" not in hapd.request("REMOVE_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\""):
+        raise Exception("Remove neighbor succeeded unexpectedly")
+
+    # Add a neighbor entry
+    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\" nr=" + nr + " lci=" + lci + " civic=" + civic):
+        raise Exception("Set neighbor failed")
+
+    # Another BSSID with the same SSID
+    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:56 ssid=\"test1\" nr=" + nr + " lci=" + lci + " civic=" + civic):
+        raise Exception("Set neighbor failed")
+
+    # Fewer parameters
+    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\" nr=" + nr):
+        raise Exception("Set neighbor failed")
+
+    # SSID in hex format
+    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=7465737431 nr=" + nr):
+        raise Exception("Set neighbor failed")
+
+    # With more parameters
+    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\" nr=" + nr + " civic=" + civic):
+        raise Exception("Set neighbor failed")
+
+    # With all parameters
+    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\" nr=" + nr + " lci=" + lci + " civic=" + civic):
+        raise Exception("Set neighbor failed")
+
+    # Another SSID on the same BSSID
+    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test2\" nr=" + nr + " lci=" + lci):
+        raise Exception("Set neighbor failed")
+
+    if "OK" not in hapd.request("REMOVE_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\""):
+        raise Exception("Remove neighbor failed")
+
+    if "OK" not in hapd.request("REMOVE_NEIGHBOR 00:11:22:33:44:56 ssid=\"test1\""):
+        raise Exception("Remove neighbor failed")
+
+    if "OK" not in hapd.request("REMOVE_NEIGHBOR 00:11:22:33:44:55 ssid=\"test2\""):
+        raise Exception("Remove neighbor failed")
+
+    # Double remove
+    if "FAIL" not in hapd.request("REMOVE_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\""):
+        raise Exception("Remove neighbor succeeded unexpectedly")
+
+def test_rrm_neighbor_rep_req(dev, apdev):
+    """wpa_supplicant ctrl_iface NEIGHBOR_REP_REQUEST"""
+    nr1="00112233445500000000510107"
+    nr2="00112233445600000000510107"
+    nr3="dd112233445500000000510107"
+
+    params = { "ssid": "test" }
+    hostapd.add_ap(apdev[0]['ifname'], params)
+    params = { "ssid": "test2", "rrm_neighbor_report": "1" }
+    hapd = hostapd.add_ap(apdev[1]['ifname'], params)
+
+    bssid1 = apdev[1]['bssid']
+
+    dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
+    if "FAIL" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
+        raise Exception("Request succeeded unexpectedly (AP without RRM)")
+    if "FAIL" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"abcdef\""):
+        raise Exception("Request succeeded unexpectedly (AP without RRM 2)")
+    dev[0].request("DISCONNECT")
+
+    rrm = int(dev[0].get_driver_status_field("capa.rrm_flags"), 16)
+    if rrm & 0x5 != 0x5 and rrm & 0x10 != 0x10:
+        raise HwsimSkip("Required RRM capabilities are not supported")
+
+    dev[0].connect("test2", key_mgmt="NONE", scan_freq="2412")
+
+    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
+        raise Exception("Request failed")
+    check_nr_results(dev[0], [bssid1])
+
+    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST lci"):
+        raise Exception("Request failed")
+    check_nr_results(dev[0], [bssid1])
+
+    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST lci civic"):
+        raise Exception("Request failed")
+    check_nr_results(dev[0], [bssid1])
+
+    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test3\""):
+        raise Exception("Request failed")
+    check_nr_results(dev[0])
+
+    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test3\" lci civic"):
+        raise Exception("Request failed")
+    check_nr_results(dev[0])
+
+    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test3\" nr=" + nr1 + " lci=" + lci + " civic=" + civic):
+        raise Exception("Set neighbor failed")
+    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:56 ssid=\"test3\" nr=" + nr2 + " lci=" + lci + " civic=" + civic):
+        raise Exception("Set neighbor failed")
+    if "OK" not in hapd.request("SET_NEIGHBOR 00:11:22:33:44:56 ssid=\"test4\" nr=" + nr2 + " lci=" + lci + " civic=" + civic):
+        raise Exception("Set neighbor failed")
+    if "OK" not in hapd.request("SET_NEIGHBOR dd:11:22:33:44:55 ssid=\"test5\" nr=" + nr3 + " lci=" + lci):
+        raise Exception("Set neighbor failed")
+
+    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test3\""):
+        raise Exception("Request failed")
+    check_nr_results(dev[0], ["00:11:22:33:44:55", "00:11:22:33:44:56"])
+
+    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test3\" lci"):
+        raise Exception("Request failed")
+    check_nr_results(dev[0], ["00:11:22:33:44:55", "00:11:22:33:44:56"],
+                     lci=True)
+
+    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test3\" civic"):
+        raise Exception("Request failed")
+    check_nr_results(dev[0], ["00:11:22:33:44:55", "00:11:22:33:44:56"],
+                     civic=True)
+
+    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test3\" lci civic"):
+        raise Exception("Request failed")
+    check_nr_results(dev[0], ["00:11:22:33:44:55", "00:11:22:33:44:56"],
+                     lci=True, civic=True)
+
+    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test4\""):
+        raise Exception("Request failed")
+    check_nr_results(dev[0], ["00:11:22:33:44:56"])
+
+    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test4\" lci"):
+        raise Exception("Request failed")
+    check_nr_results(dev[0], ["00:11:22:33:44:56"], lci=True)
+
+    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test4\" civic"):
+        raise Exception("Request failed")
+    check_nr_results(dev[0], ["00:11:22:33:44:56"], civic=True)
+
+    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test4\" lci civic"):
+        raise Exception("Request failed")
+    check_nr_results(dev[0], ["00:11:22:33:44:56"], lci=True, civic=True)
+
+    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test5\""):
+        raise Exception("Request failed")
+    check_nr_results(dev[0], ["dd:11:22:33:44:55"])
+
+    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test5\" lci"):
+        raise Exception("Request failed")
+    check_nr_results(dev[0], ["dd:11:22:33:44:55"], lci=True)
+
+    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test5\" civic"):
+        raise Exception("Request failed")
+    check_nr_results(dev[0], ["dd:11:22:33:44:55"])
+
+    if "OK" not in dev[0].request("NEIGHBOR_REP_REQUEST ssid=\"test5\" lci civic"):
+        raise Exception("Request failed")
+    check_nr_results(dev[0], ["dd:11:22:33:44:55"], lci=True)
+
+def test_rrm_lci_req(dev, apdev):
+    """hostapd lci request"""
+
+    rrm = int(dev[0].get_driver_status_field("capa.rrm_flags"), 16)
+    if rrm & 0x5 != 0x5 and rrm & 0x10 != 0x10:
+        raise HwsimSkip("Required RRM capabilities are not supported")
+
+    params = { "ssid": "rrm", "rrm_neighbor_report": "1" }
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    # station not specified
+    if "FAIL" not in hapd.request("REQ_LCI "):
+        raise Exception("REQ_LCI with no station succeeded unexpectedly")
+
+    # station that is not connected specified
+    if "FAIL" not in hapd.request("REQ_LCI " + dev[0].own_addr()):
+        raise Exception("REQ_LCI succeeded unexpectedly (station not connected)")
+
+    dev[0].request("SET LCI ")
+    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
+
+    # station connected without LCI
+    if "FAIL" not in hapd.request("REQ_LCI " + dev[0].own_addr()):
+        raise Exception("REQ_LCI succeeded unexpectedly (station without lci)")
+
+    dev[0].request("DISCONNECT")
+    dev[0].wait_disconnected(timeout=2)
+
+    dev[0].request("SET LCI " + lci)
+
+    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
+
+    # station connected with LCI
+    if "OK" not in hapd.request("REQ_LCI " + dev[0].own_addr()):
+        raise Exception("REQ_LCI failed unexpectedly")
+
+def test_rrm_ftm_range_req(dev, apdev):
+    """hostapd FTM range request command"""
+
+    rrm = int(dev[0].get_driver_status_field("capa.rrm_flags"), 16)
+    if rrm & 0x5 != 0x5 and rrm & 0x10 != 0x10:
+        raise HwsimSkip("Required RRM capabilities are not supported")
+
+    params = { "ssid": "rrm", "rrm_neighbor_report": "1" }
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    # station not specified
+    if "FAIL" not in hapd.request("REQ_RANGE "):
+        raise Exception("REQ_RANGE with no station succeeded unexpectedly")
+
+    # station that is not connected specified
+    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr()):
+        raise Exception("REQ_RANGE succeeded unexpectedly (station not connected)")
+
+    # No responders specified
+    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr() + " 10 10"):
+        raise Exception("REQ_RANGE succeeded unexpectedly (no responder)")
+
+    # Bad responder address
+    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr() + " 10 10 00:11:22:33:44:"):
+        raise Exception("REQ_RANGE succeeded unexpectedly (bad responder address)")
+
+    # Bad responder address
+    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr() + " 10 10 00:11:22:33:44:55 00:11:22:33:44"):
+        raise Exception("REQ_RANGE succeeded unexpectedly (bad responder address 2)")
+
+    # Bad min_ap value
+    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr() + " 20 10 00:11:22:33:44:55"):
+        raise Exception("REQ_RANGE succeeded unexpectedly (invalid min_ap value)")
+
+    # Bad rand value
+    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr() + " 10 300 00:11:22:33:44:55"):
+        raise Exception("REQ_RANGE succeeded unexpectedly (invalid rand value)")
+
+    dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
+
+    # Responder not in database
+    # Note: this check would pass since the station does not support FTM range
+    # request and not because the responder is not in the database.
+    if "FAIL" not in hapd.request("REQ_RANGE " + dev[0].own_addr() + " 10 10 00:11:22:33:44:55"):
+        raise Exception("REQ_RANGE succeeded unexpectedly (responder not in database)")
+
+def test_rrm_ftm_capa_indication(dev, apdev):
+    """FTM capability indication"""
+    try:
+        _test_rrm_ftm_capa_indication(dev, apdev)
+    finally:
+        dev[0].request("SET ftm_initiator 0")
+        dev[0].request("SET ftm_responder 0")
+
+def _test_rrm_ftm_capa_indication(dev, apdev):
+    params = { "ssid": "ftm",
+               "ftm_responder": "1",
+               "ftm_initiator": "1", }
+    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+    if "OK" not in dev[0].request("SET ftm_initiator 1"):
+        raise Exception("could not set ftm_initiator")
+    if "OK" not in dev[0].request("SET ftm_responder 1"):
+        raise Exception("could not set ftm_responder")
+    dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412, force_scan=True)
diff --git a/tests/hwsim/test_wmediumd.py b/tests/hwsim/test_wmediumd.py
new file mode 100644 (file)
index 0000000..3319673
--- /dev/null
@@ -0,0 +1,44 @@
+# wmediumd sanity checks
+# Copyright (c) 2015, Intel Deutschland GmbH
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import tempfile, os, subprocess, errno
+from utils import HwsimSkip
+from test_ap_open import _test_ap_open
+
+CFG = """
+ifaces :
+{
+    ids = ["%s", "%s" ];
+    links = (
+        (0, 1, 30)
+    );
+};
+"""
+
+def test_wmediumd_simple(dev, apdev):
+    """test a simple wmediumd configuration"""
+    fd, fn = tempfile.mkstemp()
+    try:
+        f = os.fdopen(fd, 'w')
+        f.write(CFG % (apdev[0]['bssid'], dev[0].own_addr()))
+        f.close()
+        try:
+            p = subprocess.Popen(['wmediumd', '-c', fn],
+                                 stdout=open('/dev/null', 'a'),
+                                 stderr=subprocess.STDOUT)
+        except OSError, e:
+            if e.errno == errno.ENOENT:
+                raise HwsimSkip("wmediumd not available")
+            raise
+        try:
+            _test_ap_open(dev, apdev)
+        finally:
+            p.terminate()
+            p.wait()
+        # test that releasing hwsim works correctly
+        _test_ap_open(dev, apdev)
+    finally:
+        os.unlink(fn)
diff --git a/tests/hwsim/wps-ctrl-cred b/tests/hwsim/wps-ctrl-cred
new file mode 100644 (file)
index 0000000..b02b783
Binary files /dev/null and b/tests/hwsim/wps-ctrl-cred differ
diff --git a/tests/hwsim/wps-ctrl-cred2 b/tests/hwsim/wps-ctrl-cred2
new file mode 100644 (file)
index 0000000..696a576
Binary files /dev/null and b/tests/hwsim/wps-ctrl-cred2 differ
diff --git a/tests/remote/config.py b/tests/remote/config.py
new file mode 100644 (file)
index 0000000..cf3b77f
--- /dev/null
@@ -0,0 +1,85 @@
+# Environment configuration
+# Copyright (c) 2016, Tieto Corporation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+#
+# Currently static definition, in the future this could be a config file,
+# or even common database with host management.
+#
+
+import logging
+logger = logging.getLogger()
+
+#
+# You can put your settings in cfg.py file with setup_params, devices
+# definitions in the format as below. In other case HWSIM cfg will be used.
+#
+setup_params = { "setup_hw" : "./tests/setup_hw.sh",
+                 "hostapd" : "./tests/hostapd",
+                 "wpa_supplicant" : "./tests/wpa_supplicant",
+                 "iperf" : "iperf",
+                 "wlantest" : "./tests/wlantest",
+                 "wlantest_cli" : "./tests/wlantest_cli",
+                 "country" : "US",
+                 "log_dir" : "/tmp/",
+                 "ipv4_test_net" : "192.168.12.0",
+                 "trace_start" : "./tests/trace_start.sh",
+                 "trace_stop" : "./tests/trace_stop.sh",
+                 "perf_start" : "./tests/perf_start.sh",
+                 "perf_stop" : "./tests/perf_stop.sh" }
+
+#
+#devices = [{"hostname": "192.168.254.58", "ifname" : "wlan0", "port": "9877", "name" : "t2-ath9k", "flags" : "AP_HT40 STA_HT40"},
+#           {"hostname": "192.168.254.58", "ifname" : "wlan1", "port": "9877", "name" : "t2-ath10k", "flags" : "AP_VHT80"},
+#           {"hostname": "192.168.254.58", "ifname" : "wlan3", "port": "9877", "name" : "t2-intel7260", "flags" : "STA_VHT80"},
+#           {"hostname": "192.168.254.55", "ifname" : "wlan0, wlan1, wlan2", "port": "", "name" : "t3-monitor"},
+#           {"hostname": "192.168.254.50", "ifname" : "wlan0", "port": "9877", "name" : "t1-ath9k"},
+#           {"hostname": "192.168.254.50", "ifname" : "wlan1", "port": "9877", "name" : "t1-ath10k"}]
+
+#
+# HWSIM - ifaces available after modprobe mac80211_hwsim
+#
+devices = [{"hostname": "localhost", "ifname": "wlan0", "port": "9868", "name": "hwsim0", "flags": "AP_VHT80 STA_VHT80"},
+           {"hostname": "localhost", "ifname": "wlan1", "port": "9878", "name": "hwsim1", "flags": "AP_VHT80 STA_VHT80"},
+           {"hostname": "localhost", "ifname": "wlan2", "port": "9888", "name": "hwsim2", "flags": "AP_VHT80 STA_VHT80"},
+           {"hostname": "localhost", "ifname": "wlan3", "port": "9898", "name": "hwsim3", "flags": "AP_VHT80 STA_VHT80"},
+           {"hostname": "localhost", "ifname": "wlan4", "port": "9908", "name": "hwsim4", "flags": "AP_VHT80 STA_VHT80"}]
+
+
+def get_setup_params(filename="cfg.py"):
+    try:
+       mod = __import__(filename.split(".")[0])
+       return mod.setup_params
+    except:
+       logger.debug("__import__(" + filename + ") failed, using static settings")
+       pass
+    return setup_params
+
+def get_devices(filename="cfg.py"):
+    try:
+       mod = __import__(filename.split(".")[0])
+       return mod.devices
+    except:
+       logger.debug("__import__(" + filename + ") failed, using static settings")
+       pass
+    return devices
+
+def get_device(devices, name=None, flags=None, lock=False):
+    if name is None and flags is None:
+        raise Exception("Failed to get device")
+    for device in devices:
+        if device['name'] == name:
+            return device
+    for device in devices:
+        try:
+            device_flags = device['flags']
+            if device_flags.find(flags) != -1:
+                return device
+        except:
+            pass
+    raise Exception("Failed to get device " + name)
+
+def put_device(devices, name):
+    pass
diff --git a/tests/remote/hwsim_wrapper.py b/tests/remote/hwsim_wrapper.py
new file mode 100644 (file)
index 0000000..d2598ab
--- /dev/null
@@ -0,0 +1,124 @@
+# Hwsim wrapper
+# Copyright (c) 2016, Tieto Corporation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import remotehost
+from wpasupplicant import WpaSupplicant
+import hostapd
+import config
+import rutils
+import monitor
+import traceback
+import wlantest
+
+import logging
+logger = logging.getLogger()
+
+def run_hwsim_test(devices, setup_params, refs, duts, monitors, hwsim_test):
+    try:
+        ref_hosts = []
+        dut_hosts = []
+        dev = []
+        apdev = []
+
+        # get hosts
+        for ref in refs:
+            ref_host = rutils.get_host(devices, ref)
+            ref_hosts.append(ref_host)
+        for dut in duts:
+            dut_host = rutils.get_host(devices, dut)
+            dut_hosts.append(dut_host)
+
+        # setup log dir
+        local_log_dir = setup_params['local_log_dir']
+
+        # setup hw before test
+        rutils.setup_hw(ref_hosts, setup_params)
+        rutils.setup_hw(dut_hosts, setup_params)
+
+        # run monitors if requested/possible
+        for ref_host in ref_hosts:
+            monitor.add(ref_host, monitors)
+            monitor.run(ref_host, setup_params)
+        for dut_host in dut_hosts:
+            monitor.add(dut_host, monitors)
+            monitor.run(dut_host, setup_params)
+
+        monitor_hosts = monitor.create(devices, setup_params, refs, duts,
+                                       monitors)
+        mon = None
+        if len(monitor_hosts) > 0:
+            mon = monitor_hosts[0]
+            wlantest.Wlantest.reset_remote_wlantest()
+            wlantest.Wlantest.register_remote_wlantest(mon, setup_params,
+                                                       monitor)
+
+        # run hostapd/wpa_supplicant
+        for ref_host in ref_hosts:
+            rutils.run_wpasupplicant(ref_host, setup_params)
+            wpas = WpaSupplicant(hostname=ref_host.host, global_iface="udp",
+                                 global_port=ref_host.port)
+            wpas.interface_add(ref_host.ifname)
+            dev.append(wpas)
+        for dut_host in dut_hosts:
+            rutils.run_hostapd(dut_host, setup_params)
+            dut_host.dev['bssid'] = rutils.get_mac_addr(dut_host)
+            apdev.append(dut_host.dev)
+
+        # run hwsim test/currently only 2 params tests
+        if hwsim_test.func_code.co_argcount == 1:
+            hwsim_test(dev)
+        elif hwsim_test.func_code.co_argcount == 2:
+            hwsim_test(dev, apdev)
+        else:
+            raise Exception("more than 2 arguments required")
+
+       # hostapd/wpa_supplicant cleanup
+        for wpas in dev:
+            wpas.interface_remove(wpas.host.ifname)
+            wpas.terminate()
+        dev = []
+
+        # remove monitors
+        for ref_host in ref_hosts:
+            monitor.remove(ref_host)
+        for dut_host in dut_hosts:
+            monitor.remove(dut_host)
+
+        for ref_host in ref_hosts:
+            ref_host.execute(["killall", "wpa_supplicant"])
+            ref_host.get_logs(local_log_dir)
+        for dut_host in dut_hosts:
+            dut_host.execute(["killall", "hostapd"])
+            dut_host.get_logs(local_log_dir)
+        if mon is not None:
+            wlantest.Wlantest.reset_remote_wlantest()
+            mon.get_logs(local_log_dir)
+
+        return ""
+    except:
+        logger.info(traceback.format_exc())
+        for wpas in dev:
+            try:
+                wpas.interface_remove(wpas.host.ifname)
+                wpas.terminate()
+            except:
+                pass
+
+        for ref_host in ref_hosts:
+            monitor.remove(ref_host)
+        for dut_host in dut_hosts:
+            monitor.remove(dut_host)
+
+        for ref_host in ref_hosts:
+            ref_host.execute(["killall", "wpa_supplicant"])
+            ref_host.get_logs(local_log_dir)
+        for dut_host in dut_hosts:
+            dut_host.execute(["killall", "hostapd"])
+            dut_host.get_logs(local_log_dir)
+        if mon is not None:
+            wlantest.Wlantest.reset_remote_wlantest()
+            mon.get_logs(local_log_dir)
+        raise
diff --git a/tests/remote/monitor.py b/tests/remote/monitor.py
new file mode 100644 (file)
index 0000000..a715010
--- /dev/null
@@ -0,0 +1,181 @@
+# Monitor support
+# Copyright (c) 2016, Tieto Corporation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import time
+from remotehost import Host
+import config
+import rutils
+import re
+import traceback
+import logging
+logger = logging.getLogger()
+import hostapd
+
+# standalone monitor with multi iface support
+def create(devices, setup_params, refs, duts, monitors):
+    mons = []
+    mhosts = []
+    hosts = duts + refs
+
+    # choose only standalone monitors
+    for monitor in monitors:
+        if monitor not in hosts and monitor != "all":
+            mons.append(monitor)
+
+    for mon in mons:
+        dev = config.get_device(devices, mon)
+        if dev is None:
+            continue
+
+        host = Host(host = dev['hostname'],
+                    ifname = dev['ifname'],
+                    port = dev['port'],
+                    name = dev['name'])
+
+        try:
+            host.execute(["iw", "reg", "set", setup_params['country']])
+            rutils.setup_hw_host(host, setup_params, True)
+        except:
+            pass
+        mhosts.append(host)
+
+    return mhosts
+
+def destroy(devices, hosts):
+    for host in hosts:
+        stop(host)
+        for monitor in host.monitors:
+            host.execute(["ifconfig", monitor, "down"])
+
+def setup(host, monitor_params):
+    if host is None:
+        return
+
+    ifaces = re.split('; | |, ', host.ifname)
+    count = 0
+    for param in monitor_params:
+        try:
+            iface = ifaces[count]
+        except:
+            logger.debug(traceback.format_exc())
+            break
+        host.execute(["ifconfig", iface, " down"])
+        host.execute(["iw", iface, "set type monitor"])
+        host.execute(["ifconfig", iface, "up"])
+        status, buf = host.execute(["iw", iface, "set", "freq", param['freq'],
+                                    param['bw'], param['center_freq1'],
+                                    param['center_freq2']])
+        if status != 0:
+            logger.debug("Could not setup monitor interface: " + buf)
+            continue
+        host.monitors.append(iface)
+        count = count + 1
+
+def run(host, setup_params):
+    monitor_res = []
+    log_monitor = ""
+    if host is None:
+        return None
+    if len(host.monitors) == 0:
+        return None
+    try:
+        log_dir = setup_params['log_dir']
+        tc_name = setup_params['tc_name']
+    except:
+        return None
+
+    tshark = "tshark"
+    for monitor in host.monitors:
+        host.execute(["ifconfig", monitor, "up"])
+        tshark = tshark + " -i " + monitor
+        log_monitor = log_monitor + "_" + monitor
+
+    log = log_dir + tc_name + "_" + host.name + log_monitor + ".pcap"
+    host.add_log(log)
+    thread = host.execute_run([tshark, "-w", log], monitor_res)
+    host.thread = thread
+
+
+def stop(host):
+    if host is None:
+        return
+    if len(host.monitors) == 0:
+        return
+    if host.thread is None:
+        return
+
+    host.execute(["killall", "-s", "INT", "tshark"])
+    host.wait_execute_complete(host.thread, 5)
+    if host.thread.isAlive():
+       raise Exception("tshark still alive")
+    host.thread = None
+
+# Add monitor to existing interface
+def add(host, monitors):
+    if host is None:
+        return
+
+    for monitor in monitors:
+        if monitor != "all" and monitor != host.name:
+            continue
+        mon = "mon_" + host.ifname
+        status, buf = host.execute(["iw", host.ifname, "interface", "add", mon,
+                                    "type", "monitor"])
+        if status == 0:
+            host.monitors.append(mon)
+            host.execute(["ifconfig", mon, "up"])
+        else:
+            logger.debug("Could not add monitor for " + host.name)
+
+def remove(host):
+    stop(host)
+    for monitor in host.monitors:
+        host.execute(["iw", monitor, "del"])
+        host.monitors.remove(monitor)
+
+
+# get monitor params from hostapd/wpa_supplicant
+def get_monitor_params(wpa, is_p2p=False):
+    if is_p2p:
+        get_status_field_f = wpa.get_group_status_field
+    else:
+        get_status_field_f = wpa.get_status_field
+    freq = get_status_field_f("freq")
+    bw = "20"
+    center_freq1=""
+    center_freq2=""
+
+    vht_oper_chwidth = get_status_field_f("vht_oper_chwidth")
+    secondary_channel = get_status_field_f("secondary_channel")
+    vht_oper_centr_freq_seg0_idx = get_status_field_f("vht_oper_centr_freq_seg0_idx")
+    vht_oper_centr_freq_seg1_idx = get_status_field_f("vht_oper_centr_freq_seg1_idx")
+    if vht_oper_chwidth == "0" or vht_oper_chwidth is None:
+        if secondary_channel == "1":
+            bw = "40"
+            center_freq1 = str(int(freq) + 10)
+        elif secondary_channel == "-1":
+            center_freq1 = str(int(freq) - 10)
+        else:
+            pass
+    elif vht_oper_chwidth == "1":
+        bw = "80"
+        center_freq1 = str(int(vht_oper_centr_freq_seg0_idx) * 5 + 5000)
+    elif vht_oper_chwidth == "2":
+        bw = "160"
+        center_freq1 = str(int(vht_oper_centr_freq_seg0_idx) * 5 + 5000)
+    elif vht_oper_chwidth == "3":
+        bw = "80+80"
+        center_freq1 = str(int(vht_oper_centr_freq_seg0_idx) * 5 + 5000)
+        center_freq2 = str(int(vht_oper_centr_freq_seg1_idx) * 5 + 5000)
+    else:
+        pass
+
+    monitor_params = { "freq" : freq,
+                       "bw" : bw,
+                       "center_freq1" : center_freq1,
+                       "center_freq2" : center_freq2 }
+
+    return monitor_params
diff --git a/tests/remote/run-tests.py b/tests/remote/run-tests.py
new file mode 100755 (executable)
index 0000000..b438815
--- /dev/null
@@ -0,0 +1,373 @@
+#!/usr/bin/env python2
+#
+# Remote test case executor
+# Copyright (c) 2016, Tieto Corporation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import re
+import sys
+import time
+import traceback
+import getopt
+from datetime import datetime
+
+import logging
+logger = logging.getLogger()
+
+scriptsdir = os.path.dirname(os.path.realpath(sys.modules[__name__].__file__))
+sys.path.append(os.path.join(scriptsdir, '..', '..', 'wpaspy'))
+sys.path.append(os.path.join(scriptsdir, '..', 'hwsim'))
+
+import wpaspy
+import config
+from test_devices import show_devices
+from test_devices import check_devices
+from rutils import TestSkip
+from utils import HwsimSkip
+from hwsim_wrapper import run_hwsim_test
+
+def usage():
+    print "USAGE: " + sys.argv[0] + " -t devices"
+    print "USAGE: " + sys.argv[0] + " -t check_devices"
+    print "USAGE: " + sys.argv[0] + " -d <dut_name> -t <all|sanity|tests_to_run> [-r <ref_name>] [-c <cfg_file.py>] [-m <all|monitor_name>] [-h hwsim_tests][-R][-T][-P][-v]"
+    print "USAGE: " + sys.argv[0]
+
+def get_devices(devices, duts, refs, monitors):
+    for dut in duts:
+        config.get_device(devices, dut, lock=True)
+    for ref in refs:
+        config.get_device(devices, ref, lock=True)
+    for monitor in monitors:
+        if monitor == "all":
+            continue
+        if monitor in duts:
+            continue
+        if monitor in refs:
+            continue
+        config.get_device(devices, monitor, lock=True)
+
+def put_devices(devices, duts, refs, monitors):
+    for dut in duts:
+        config.put_device(devices, dut)
+    for ref in refs:
+        config.put_device(devices, ref)
+    for monitor in monitors:
+        if monitor == "all":
+            continue
+        if monitor in duts:
+            continue
+        if monitor in refs:
+            continue
+        config.put_device(devices, monitor)
+
+def main():
+    duts = []
+    refs = []
+    monitors = []
+    filter_keys = []
+    requested_tests = ["help"]
+    requested_hwsim_tests = []
+    hwsim_tests = []
+    cfg_file = "cfg.py"
+    log_dir = "./logs/"
+    verbose = False
+    trace = False
+    restart = False
+    perf = False
+
+    # parse input parameters
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], "d:r:t:l:k:c:m:h:vRPT",
+                                   ["dut=", "ref=", "tests=", "log-dir=",
+                                    "cfg=", "key=", "monitor=", "hwsim="])
+    except getopt.GetoptError as err:
+        print(err)
+        usage()
+        sys.exit(2)
+
+    for option, argument in opts:
+        if option == "-v":
+            verbose = True
+        elif option == "-R":
+            restart = True
+        elif option == "-T":
+            trace = True
+        elif option == "-P":
+            perf = True
+        elif option in ("-d", "--dut"):
+            duts.append(argument)
+        elif option in ("-r", "--ref"):
+            refs.append(argument)
+        elif option in ("-t", "--tests"):
+            requested_tests = re.split('; | |, ', argument)
+        elif option in ("-l", "--log-dir"):
+            log_dir = argument
+        elif option in ("-k", "--key"):
+            filter_keys.append(argument)
+        elif option in ("-m", "--monitor"):
+            monitors.append(argument)
+        elif option in ("-c", "--cfg"):
+            cfg_file = argument
+        elif option in ("-h", "--hwsim"):
+            requested_hwsim_tests = re.split('; | |, ', argument)
+        else:
+            assert False, "unhandled option"
+
+    # get env configuration
+    setup_params = config.get_setup_params(cfg_file)
+    devices = config.get_devices(cfg_file)
+
+    # put logs in log_dir
+    symlink = os.path.join(log_dir, "current");
+    if os.path.exists(symlink):
+        os.unlink(symlink)
+    log_dir = os.path.join(log_dir, time.strftime("%Y_%m_%d_%H_%M_%S"))
+    if not os.path.exists(log_dir):
+        os.makedirs(log_dir)
+    os.symlink(os.path.join("../", log_dir), symlink)
+
+    # setup restart/trace/perf request
+    setup_params['local_log_dir'] = log_dir
+    setup_params['restart_device'] = restart
+    setup_params['trace'] = trace
+    setup_params['perf'] = perf
+
+    # configure logger
+    logger.setLevel(logging.DEBUG)
+
+    stdout_handler = logging.StreamHandler()
+    stdout_handler.setLevel(logging.WARNING)
+    if verbose:
+        stdout_handler.setLevel(logging.DEBUG)
+    logger.addHandler(stdout_handler)
+
+    formatter = logging.Formatter('%(asctime)s - %(message)s')
+    file_name = os.path.join(log_dir, 'run-tests.log')
+    log_handler = logging.FileHandler(file_name)
+    log_handler.setLevel(logging.DEBUG)
+    log_handler.setFormatter(formatter)
+    logger.addHandler(log_handler)
+
+    # import available tests
+    tests = []
+    failed = []
+    test_modules = []
+    files = os.listdir(scriptsdir)
+    for t in files:
+        m = re.match(r'(test_.*)\.py$', t)
+        if m:
+            mod = __import__(m.group(1))
+            test_modules.append(mod.__name__.replace('test_', '', 1))
+            for key,val in mod.__dict__.iteritems():
+                if key.startswith("test_"):
+                    tests.append(val)
+    test_names = list(set([t.__name__.replace('test_', '', 1) for t in tests]))
+
+    # import test_*
+    files = os.listdir("../hwsim/")
+    for t in files:
+        m = re.match(r'(test_.*)\.py$', t)
+        if m:
+            mod = __import__(m.group(1))
+            test_modules.append(mod.__name__.replace('test_', '', 1))
+            for key,val in mod.__dict__.iteritems():
+                if key.startswith("test_"):
+                    hwsim_tests.append(val)
+
+    # setup hwsim tests
+    hwsim_tests_to_run = []
+    if len(requested_hwsim_tests) > 0:
+        # apply filters
+        for filter_key in filter_keys:
+            filtered_tests = []
+            for hwsim_test in hwsim_tests:
+                if re.search(filter_key, hwsim_test.__name__):
+                    filtered_tests.append(hwsim_test)
+            hwsim_tests = filtered_tests
+
+        # setup hwsim_test we should run
+        if requested_hwsim_tests[0] == "all":
+            hwsim_tests_to_run = hwsim_tests
+        elif requested_hwsim_tests[0] == "remote":
+            hwsim_tests_to_run = [t for t in hwsim_tests
+                                  if hasattr(t, "remote_compatible") and
+                                     t.remote_compatible]
+        else:
+            for test in requested_hwsim_tests:
+                t = None
+                for tt in hwsim_tests:
+                    name = tt.__name__.replace('test_', '', 1)
+                    if name == test and tt.func_code.co_argcount <= 2:
+                        t = tt
+                        break
+                if not t:
+                    logger.warning("hwsim test case: " + test + " NOT-FOUND")
+                    continue
+                hwsim_tests_to_run.append(t)
+
+    # sort the list
+    test_names.sort()
+    tests.sort()
+
+    # print help
+    if requested_tests[0] == "help" and len(requested_hwsim_tests) == 0:
+        usage()
+        print "\nAvailable Devices:"
+        for device in devices:
+            print "\t", device['name']
+        print "\nAvailable tests:"
+        for test in test_names:
+            print "\t", test
+        print "\nAvailable hwsim tests:"
+        for hwsim_test in hwsim_tests:
+            print "\t", hwsim_test.__name__.replace('test_', '', 1)
+        return
+
+    # show/check devices
+    if requested_tests[0] == "devices":
+        show_devices(devices, setup_params)
+        return
+
+    # apply filters
+    for filter_key in filter_keys:
+        filtered_tests = []
+        for test in tests:
+            if re.search(filter_key, test.__name__):
+                filtered_tests.append(test)
+        tests = filtered_tests
+
+    # setup test we should run
+    tests_to_run = []
+    if requested_tests[0] == "all":
+        tests_to_run = tests
+    if requested_tests[0] == "help":
+        pass
+    elif requested_tests[0] == "sanity":
+        for test in tests:
+            if test.__name__.startswith("test_sanity_"):
+                tests_to_run.append(test)
+    else:
+        for test in requested_tests:
+            t = None
+            for tt in tests:
+                name = tt.__name__.replace('test_', '', 1)
+                if name == test:
+                    t = tt
+                    break
+            if not t:
+                logger.warning("test case: " + test + " NOT-FOUND")
+                continue
+            tests_to_run.append(t)
+
+    # lock devices
+    try:
+        get_devices(devices, duts, refs, monitors)
+    except Exception, e:
+        logger.warning("get devices failed: " + str(e))
+        logger.info(traceback.format_exc())
+        put_devices(devices, duts, refs, monitors)
+        return
+    except:
+        logger.warning("get devices failed")
+        logger.info(traceback.format_exc())
+        put_devices(devices, duts, refs, monitors)
+        return
+
+    # now run test cases
+    for dut in duts:
+        logger.warning("DUT: " + str(dut))
+    for ref in refs:
+        logger.warning("REF: " + str(ref))
+    for monitor in monitors:
+        logger.warning("MON: " + str(monitor))
+
+    # run check_devices at begining
+    logger.warning("RUN check_devices")
+    try:
+        check_devices(devices, setup_params, refs, duts, monitors)
+    except Exception, e:
+        logger.warning("FAILED: " + str(e))
+        logger.info(traceback.format_exc())
+        put_devices(devices, duts, refs, monitors)
+        return
+    except:
+        logger.warning("FAILED")
+        logger.info(traceback.format_exc())
+        put_devices(devices, duts, refs, monitors)
+        return
+    logger.warning("PASS")
+
+    test_no = 1
+    for test in tests_to_run:
+        try:
+            start = datetime.now()
+            setup_params['tc_name'] = test.__name__.replace('test_', '', 1)
+            logger.warning("START - " + setup_params['tc_name'] + " (" + str(test_no) + "/" + str(len(tests_to_run)) + ")")
+            if test.__doc__:
+                logger.info("Test: " + test.__doc__)
+
+            # run tc
+            res = test(devices, setup_params, refs, duts, monitors)
+
+            end = datetime.now()
+            logger.warning("PASS (" + res + ") - " + str((end - start).total_seconds()) + "s")
+        except KeyboardInterrupt:
+            put_devices(devices, duts, refs, monitors)
+            raise
+        except TestSkip, e:
+            end = datetime.now()
+            logger.warning("SKIP (" + str(e) + ") - " + str((end - start).total_seconds()) + "s")
+        except Exception, e:
+            end = datetime.now()
+            logger.warning("FAILED (" + str(e) + ") - " + str((end - start).total_seconds()) + "s")
+            logger.info(traceback.format_exc())
+            failed.append(test.__name__.replace('test_', '', 1))
+        except:
+            end = datetime.now()
+            logger.warning("FAILED - " + str((end - start).total_seconds()) + "s")
+            logger.info(traceback.format_exc())
+            failed.append(test.__name__.replace('test_', '', 1))
+        test_no += 1
+
+    test_no = 1
+    for hwsim_test in hwsim_tests_to_run:
+        try:
+            start = datetime.now()
+            setup_params['tc_name'] = hwsim_test.__name__.replace('test_', '', 1)
+            logger.warning("START - " + setup_params['tc_name'] + " (" + str(test_no) + "/" + str(len(hwsim_tests_to_run)) + ")")
+            res = run_hwsim_test(devices, setup_params, refs, duts, monitors, hwsim_test)
+            end = datetime.now()
+            logger.warning("PASS (" + res + ") - " + str((end - start).total_seconds()) + "s")
+        except KeyboardInterrupt:
+            put_devices(devices, duts, refs, monitors)
+            raise
+        except HwsimSkip,e:
+            end = datetime.now()
+            logger.warning("SKIP (" + str(e) + ") - " + str((end - start).total_seconds()) + "s")
+            failed.append(hwsim_test.__name__.replace('test_', '', 1))
+        except Exception, e:
+            end = datetime.now()
+            logger.warning("FAILED (" + str(e) + ") - " + str((end - start).total_seconds()) + "s")
+            logger.info(traceback.format_exc())
+            failed.append(hwsim_test.__name__.replace('test_', '', 1))
+        except:
+            end = datetime.now()
+            logger.warning("FAILED - " + str((end - start).total_seconds()) + "s")
+            logger.info(traceback.format_exc())
+            failed.append(hwsim_test.__name__.replace('test_', '', 1))
+        test_no += 1
+
+    # unlock devices
+    put_devices(devices, duts, refs, monitors)
+
+    if len(failed) > 0:
+        logger.warning("Failed test cases:")
+        for test in failed:
+            logger.warning("\t" + test)
+
+
+if __name__ == "__main__":
+        main()
diff --git a/tests/remote/rutils.py b/tests/remote/rutils.py
new file mode 100644 (file)
index 0000000..879fadc
--- /dev/null
@@ -0,0 +1,553 @@
+# Utils
+# Copyright (c) 2016, Tieto Corporation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import re
+import time
+from remotehost import Host
+import hostapd
+import config
+
+class TestSkip(Exception):
+    def __init__(self, reason):
+        self.reason = reason
+    def __str__(self):
+        return self.reason
+
+# get host based on name
+def get_host(devices, dev_name):
+    dev = config.get_device(devices, dev_name)
+    host = Host(host = dev['hostname'],
+                ifname = dev['ifname'],
+                port = dev['port'],
+                name = dev['name'])
+    host.dev = dev
+    return host
+
+# Run setup_hw - hardware specific
+def setup_hw_host_iface(host, iface, setup_params, force_restart=False):
+    try:
+        setup_hw = setup_params['setup_hw']
+        restart = ""
+        try:
+            if setup_params['restart_device'] == True:
+                restart = "-R"
+        except:
+            pass
+
+        if force_restart:
+            restart = "-R"
+
+        host.execute([setup_hw, "-I", iface, restart])
+    except:
+        pass
+
+def setup_hw_host(host, setup_params, force_restart=False):
+    ifaces = re.split('; | |, ', host.ifname)
+    for iface in ifaces:
+        setup_hw_host_iface(host, iface, setup_params, force_restart)
+
+def setup_hw(hosts, setup_params, force_restart=False):
+    for host in hosts:
+        setup_hw_host(host, setup_params, force_restart)
+
+# get traces - hw specific
+def trace_start(hosts, setup_params):
+    for host in hosts:
+        trace_start_stop(host, setup_params, start=True)
+
+def trace_stop(hosts, setup_params):
+    for host in hosts:
+        trace_start_stop(host, setup_params, start=False)
+
+def trace_start_stop(host, setup_params, start):
+    if setup_params['trace'] == False:
+        return
+    try:
+        start_trace = setup_params['trace_start']
+        stop_trace = setup_params['trace_stop']
+        if start:
+            cmd = start_trace
+        else:
+            cmd = stop_trace
+        trace_dir = setup_params['log_dir'] + host.ifname + "/remote_traces"
+        host.add_log(trace_dir + "/*")
+        host.execute([cmd, "-I", host.ifname, "-D", trace_dir])
+    except:
+        pass
+
+# get perf
+def perf_start(hosts, setup_params):
+    for host in hosts:
+        perf_start_stop(host, setup_params, start=True)
+
+def perf_stop(hosts, setup_params):
+    for host in hosts:
+        perf_start_stop(host, setup_params, start=False)
+
+def perf_start_stop(host, setup_params, start):
+    if setup_params['perf'] == False:
+        return
+    try:
+        perf_start = setup_params['perf_start']
+        perf_stop = setup_params['perf_stop']
+        if start:
+            cmd = perf_start
+        else:
+            cmd = perf_stop
+        perf_dir = setup_params['log_dir'] + host.ifname + "/remote_perf"
+        host.add_log(perf_dir + "/*")
+        host.execute([cmd, "-I", host.ifname, "-D", perf_dir])
+    except:
+        pass
+
+# hostapd/wpa_supplicant helpers
+def run_hostapd(host, setup_params):
+    log_file = None
+    try:
+        tc_name = setup_params['tc_name']
+        log_dir = setup_params['log_dir']
+        log_file = log_dir + tc_name + "_hostapd_" + host.name + "_" + host.ifname + ".log"
+        host.execute(["rm", log_file])
+        log = " -f " + log_file
+    except:
+        log = ""
+
+    if log_file:
+        host.add_log(log_file)
+    status, buf = host.execute([setup_params['hostapd'], "-B", "-ddt", "-g", "udp:" + host.port, log])
+    if status != 0:
+        raise Exception("Could not run hostapd: " + buf)
+
+def run_wpasupplicant(host, setup_params):
+    log_file = None
+    try:
+        tc_name = setup_params['tc_name']
+        log_dir = setup_params['log_dir']
+        log_file = log_dir + tc_name + "_wpa_supplicant_" + host.name + "_" + host.ifname + ".log"
+        host.execute(["rm", log_file])
+        log = " -f " + log_file
+    except:
+        log = ""
+
+    if log_file:
+        host.add_log(log_file)
+    status, buf = host.execute([setup_params['wpa_supplicant'], "-B", "-ddt", "-g", "udp:" + host.port, log])
+    if status != 0:
+        raise Exception("Could not run wpa_supplicant: " + buf)
+
+def get_ap_params(channel="1", bw="HT20", country="US", security="open", ht_capab=None, vht_capab=None):
+    ssid = "test_" + channel + "_" + security + "_" + bw
+
+    if bw == "b_only":
+        params = hostapd.b_only_params(channel, ssid, country)
+    elif bw == "g_only":
+        params = hostapd.g_only_params(channel, ssid, country)
+    elif bw == "g_only_wmm":
+        params = hostapd.g_only_params(channel, ssid, country)
+        params['wmm_enabled'] = "1"
+    elif bw == "a_only":
+        params = hostapd.a_only_params(channel, ssid, country)
+    elif bw == "a_only_wmm":
+        params = hostapd.a_only_params(channel, ssid, country)
+        params['wmm_enabled'] = "1"
+    elif bw == "HT20":
+        params = hostapd.ht20_params(channel, ssid, country)
+        if ht_capab:
+            try:
+                params['ht_capab'] = params['ht_capab'] + ht_capab
+            except:
+                params['ht_capab'] = ht_capab
+    elif bw == "HT40+":
+        params = hostapd.ht40_plus_params(channel, ssid, country)
+        if ht_capab:
+            params['ht_capab'] = params['ht_capab'] + ht_capab
+    elif bw == "HT40-":
+        params = hostapd.ht40_minus_params(channel, ssid, country)
+        if ht_capab:
+            params['ht_capab'] = params['ht_capab'] + ht_capab
+    elif bw == "VHT80":
+        params = hostapd.ht40_plus_params(channel, ssid, country)
+        if ht_capab:
+            params['ht_capab'] = params['ht_capab'] + ht_capab
+        if vht_capab:
+            try:
+                params['vht_capab'] = params['vht_capab'] + vht_capab
+            except:
+                params['vht_capab'] = vht_capab
+        params['ieee80211ac'] = "1"
+        params['vht_oper_chwidth'] = "1"
+        params['vht_oper_centr_freq_seg0_idx'] = str(int(channel) + 6)
+    else:
+        params = {}
+
+    # now setup security params
+    if security == "tkip":
+        sec_params = hostapd.wpa_params(passphrase="testtest")
+    elif security == "ccmp":
+        sec_params = hostapd.wpa2_params(passphrase="testtest")
+    elif security == "mixed":
+        sec_params = hostapd.wpa_mixed_params(passphrase="testtest")
+    elif security == "wep":
+        sec_params = { "wep_key0" : "123456789a",
+                       "wep_default_key" : "0",
+                       "auth_algs" : "1"}
+    elif security == "wep_shared":
+        sec_params = { "wep_key0" : "123456789a",
+                       "wep_default_key" : "0",
+                       "auth_algs" : "2" }
+    else:
+        sec_params = {}
+
+    params.update(sec_params)
+
+    return params
+
+# ip helpers
+def get_ipv4(client, ifname=None):
+    if ifname is None:
+        ifname = client.ifname
+    status, buf = client.execute(["ifconfig", ifname])
+    lines = buf.splitlines()
+
+    for line in lines:
+        res = line.find("inet addr:")
+        if res != -1:
+            break
+
+    if res != -1:
+        words = line.split()
+        addr = words[1].split(":")
+        return addr[1]
+
+    return "unknown"
+
+def get_ipv6(client, ifname=None):
+    res = -1
+    if ifname is None:
+        ifname = client.ifname
+    status, buf = client.execute(["ifconfig", ifname])
+    lines = buf.splitlines()
+
+    for line in lines:
+        res = line.find("Scope:Link")
+        if res != -1:
+            break
+
+    if res != -1:
+        words = line.split()
+        if words[0] == "inet6" and words[1] == "addr:":
+            addr_mask = words[2]
+            addr = addr_mask.split("/")
+            return addr[0]
+
+    return "unknown"
+
+def get_ip(client, addr_type="ipv6", iface=None):
+    if addr_type == "ipv6":
+        return get_ipv6(client, iface)
+    elif addr_type == "ipv4":
+        return get_ipv4(client, iface)
+    else:
+        return "unknown addr_type: " + addr_type
+
+def get_ipv4_addr(setup_params, number):
+    try:
+        ipv4_base = setup_params['ipv4_test_net']
+    except:
+        ipv4_base = "172.16.12.0"
+
+    parts = ipv4_base.split('.')
+    ipv4 = parts[0] + "." + parts[1] + "." + parts[2] + "." + str(number)
+
+    return ipv4
+
+def get_mac_addr(host, iface=None):
+    if iface == None:
+        iface = host.ifname
+    status, buf = host.execute(["ifconfig", iface])
+    if status != 0:
+        raise Exception("ifconfig " + iface)
+    words = buf.split()
+    found = 0
+    for word in words:
+        if found == 1:
+            return word
+        if word == "HWaddr":
+            found = 1
+    raise Exception("Could not find HWaddr")
+
+# connectivity/ping helpers
+def get_ping_packet_loss(ping_res):
+    loss_line = ""
+    lines = ping_res.splitlines()
+    for line in lines:
+        if line.find("packet loss") != -1:
+            loss_line = line
+            break;
+
+    if loss_line == "":
+        return "100%"
+
+    sections = loss_line.split(",")
+
+    for section in sections:
+        if section.find("packet loss") != -1:
+            words = section.split()
+            return words[0]
+
+    return "100%"
+
+def ac_to_ping_ac(qos):
+    if qos == "be":
+        qos_param = "0x00"
+    elif qos == "bk":
+        qos_param = "0x20"
+    elif qos == "vi":
+        qos_param = "0xA0"
+    elif qos == "vo":
+        qos_param = "0xE0"
+    else:
+        qos_param = "0x00"
+    return qos_param
+
+def ping_run(host, ip, result, ifname=None, addr_type="ipv4", deadline="5", qos=None):
+    if ifname is None:
+       ifname = host.ifname
+    if addr_type == "ipv6":
+        ping = ["ping6"]
+    else:
+        ping = ["ping"]
+
+    ping = ping + ["-w", deadline, "-I", ifname]
+    if qos:
+        ping = ping + ["-Q", ac_to_ping_ac(qos)]
+    ping = ping + [ip]
+
+    flush_arp_cache(host)
+
+    thread = host.execute_run(ping, result)
+    return thread
+
+def ping_wait(host, thread, timeout=None):
+    host.wait_execute_complete(thread, timeout)
+    if thread.isAlive():
+        raise Exception("ping thread still alive")
+
+def flush_arp_cache(host):
+    host.execute(["ip", "-s", "-s", "neigh", "flush", "all"])
+
+def check_connectivity(a, b, addr_type = "ipv4", deadline="5", qos=None):
+    addr_a = get_ip(a, addr_type)
+    addr_b = get_ip(b, addr_type)
+
+    if addr_type == "ipv4":
+        ping = ["ping"]
+    else:
+        ping = ["ping6"]
+
+    ping_a_b = ping + ["-w", deadline, "-I", a.ifname]
+    ping_b_a = ping + ["-w", deadline, "-I", b.ifname]
+    if qos:
+        ping_a_b = ping_a_b + ["-Q", ac_to_ping_ac(qos)]
+        ping_b_a = ping_b_a + ["-Q", ac_to_ping_ac(qos)]
+    ping_a_b = ping_a_b + [addr_b]
+    ping_b_a = ping_b_a + [addr_a]
+
+    # Clear arp cache
+    flush_arp_cache(a)
+    flush_arp_cache(b)
+
+    status, buf = a.execute(ping_a_b)
+    if status == 2 and ping == "ping6":
+        # tentative possible for a while, try again
+        time.sleep(3)
+        status, buf = a.execute(ping_a_b)
+    if status != 0:
+        raise Exception("ping " + a.name + "/" + a.ifname + " >> " + b.name + "/" + b.ifname)
+
+    a_b = get_ping_packet_loss(buf)
+
+    # Clear arp cache
+    flush_arp_cache(a)
+    flush_arp_cache(b)
+
+    status, buf = b.execute(ping_b_a)
+    if status != 0:
+        raise Exception("ping " + b.name + "/" + b.ifname + " >> " + a.name + "/" + a.ifname)
+
+    b_a = get_ping_packet_loss(buf)
+
+    if int(a_b[:-1]) > 40:
+        raise Exception("Too high packet lost: " + a_b)
+
+    if int(b_a[:-1]) > 40:
+        raise Exception("Too high packet lost: " + b_a)
+
+    return a_b, b_a
+
+
+# iperf helpers
+def get_iperf_speed(iperf_res, pattern="Mbits/sec"):
+    lines = iperf_res.splitlines()
+    sum_line = ""
+    last_line = ""
+    count = 0
+    res = -1
+
+    # first find last SUM line
+    for line in lines:
+        res  = line.find("[SUM]")
+        if res != -1:
+            sum_line = line
+
+    # next check SUM status
+    if sum_line != "":
+        words = sum_line.split()
+        for word in words:
+            res = word.find(pattern)
+            if res != -1:
+                return words[count - 1] + " " + pattern
+            count = count + 1
+
+    # no SUM - one thread - find last line
+    for line in lines:
+        res = line.find(pattern)
+        if res != -1:
+            last_line = line
+
+    if last_line == "":
+        return "0 " + pattern
+
+    count = 0
+    words = last_line.split()
+    for word in words:
+        res = word.find(pattern)
+        if res != -1:
+            return words[count - 1] + " " + pattern
+            break;
+        count = count + 1
+    return "0 " + pattern
+
+def ac_to_iperf_ac(qos):
+    if qos == "be":
+        qos_param = "0x00"
+    elif qos == "bk":
+        qos_param = "0x20"
+    elif qos == "vi":
+        qos_param = "0xA0"
+    elif qos == "vo":
+        qos_param = "0xE0"
+    else:
+        qos_param = "0x00"
+    return qos_param
+
+def iperf_run(server, client, server_ip, client_res, server_res,
+              l4="udp", bw="30M", test_time="30", parallel="5",
+              qos="be", param=" -i 5 ", ifname=None, l3="ipv4",
+              port="5001", iperf="iperf"):
+    if ifname == None:
+        ifname = client.ifname
+
+    if iperf == "iperf":
+        iperf_server = [iperf]
+    elif iperf == "iperf3":
+        iperf_server = [iperf, "-1"]
+
+    if l3 == "ipv4":
+        iperf_client = [iperf, "-c", server_ip, "-p", port]
+        iperf_server = iperf_server + ["-p", port]
+    elif l3 == "ipv6":
+        iperf_client = [iperf, "-V", "-c", server_ip  + "%" + ifname, "-p", port]
+        iperf_server = iperf_server + ["-V", "-p",  port]
+    else:
+        return -1, -1
+
+    iperf_server = iperf_server + ["-s", "-f", "m", param]
+    iperf_client = iperf_client + ["-f", "m", "-t", test_time]
+
+    if parallel != "1":
+        iperf_client = iperf_client + ["-P", parallel]
+
+    if l4 == "udp":
+        if iperf != "iperf3":
+            iperf_server = iperf_server + ["-u"]
+        iperf_client = iperf_client + ["-u", "-b",  bw]
+
+    if qos:
+        iperf_client = iperf_client + ["-Q", ac_to_iperf_ac(qos)]
+
+    flush_arp_cache(server)
+    flush_arp_cache(client)
+
+    server_thread = server.execute_run(iperf_server, server_res)
+    time.sleep(1)
+    client_thread = client.execute_run(iperf_client, client_res)
+
+    return server_thread, client_thread
+
+def iperf_wait(server, client, server_thread, client_thread, timeout=None, iperf="iperf"):
+    client.wait_execute_complete(client_thread, timeout)
+    if client_thread.isAlive():
+        raise Exception("iperf client thread still alive")
+
+    server.wait_execute_complete(server_thread, 5)
+    if server_thread.isAlive():
+        server.execute(["killall", "-s", "INT", iperf])
+        time.sleep(1)
+
+    server.wait_execute_complete(server_thread, 5)
+    if server_thread.isAlive():
+        raise Execption("iperf server thread still alive")
+
+    return
+
+def run_tp_test(server, client, l3="ipv4", iperf="iperf", l4="tcp", test_time="10", parallel="5",
+                qos="be", bw="30M", ifname=None, port="5001"):
+    client_res = []
+    server_res = []
+
+    server_ip = get_ip(server, l3)
+    time.sleep(1)
+    server_thread, client_thread = iperf_run(server, client, server_ip, client_res, server_res,
+                                             l3=l3, iperf=iperf, l4=l4, test_time=test_time,
+                                             parallel=parallel, qos=qos, bw=bw, ifname=ifname,
+                                             port=port)
+    iperf_wait(server, client, server_thread, client_thread, iperf=iperf, timeout=int(test_time) + 10)
+
+    if client_res[0] != 0:
+        raise Exception(iperf + " client: " + client_res[1])
+    if server_res[0] != 0:
+        raise Exception(iperf + " server: " + server_res[1])
+    if client_res[1] is None:
+        raise Exception(iperf + " client result issue")
+    if server_res[1] is None:
+        raise Exception(iperf + " server result issue")
+
+    if iperf == "iperf":
+          result = server_res[1]
+    if iperf == "iperf3":
+          result = client_res[1]
+
+    speed = get_iperf_speed(result)
+    return speed
+
+def get_iperf_bw(bw, parallel, spacial_streams=2):
+    if bw == "b_only":
+        max_tp = 11
+    elif bw == "g_only" or bw == "g_only_wmm" or bw == "a_only" or bw == "a_only_wmm":
+        max_tp = 54
+    elif bw == "HT20":
+        max_tp = 72 * spacial_streams
+    elif bw == "HT40+" or bw == "HT40-":
+        max_tp = 150 * spacial_streams
+    elif bw == "VHT80":
+        max_tp = 433 * spacial_streams
+    else:
+        max_tp = 150
+
+    max_tp = 1.2 * max_tp
+
+    return str(int(max_tp/int(parallel))) + "M"
diff --git a/tests/remote/test_devices.py b/tests/remote/test_devices.py
new file mode 100644 (file)
index 0000000..6d84d11
--- /dev/null
@@ -0,0 +1,124 @@
+#!/usr/bin/env python2
+#
+# Show/check devices
+# Copyright (c) 2016, Tieto Corporation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import time
+import traceback
+import config
+import os
+import sys
+import getopt
+import re
+
+import logging
+logger = logging.getLogger()
+
+import rutils
+from remotehost import Host
+from wpasupplicant import WpaSupplicant
+import hostapd
+
+def show_devices(devices, setup_params):
+    """Show/check available devices"""
+    print "Devices:"
+    for device in devices:
+        host = rutils.get_host(devices, device['name'])
+        # simple check if authorized_keys works correctly
+        status, buf = host.execute(["id"])
+        if status != 0:
+            print "[" + host.name + "] - ssh communication:  FAILED"
+            continue
+        else:
+            print "[" + host.name + "] - ssh communication: OK"
+        # check setup_hw works correctly
+        rutils.setup_hw_host(host, setup_params)
+
+        # show uname
+        status, buf = host.execute(["uname", "-s", "-n", "-r", "-m", "-o"])
+        print "\t" + buf
+        # show ifconfig
+        ifaces = re.split('; | |, ', host.ifname)
+        for iface in ifaces:
+            status, buf = host.execute(["ifconfig", iface])
+            if status != 0:
+                print "\t" + iface + " failed\n"
+                continue
+            lines = buf.splitlines()
+            for line in lines:
+                print "\t" + line
+        # check hostapd, wpa_supplicant, iperf exist
+        status, buf = host.execute([setup_params['wpa_supplicant'], "-v"])
+        if status != 0:
+            print "\t" + setup_params['wpa_supplicant'] + " not find\n"
+            continue
+        lines = buf.splitlines()
+        for line in lines:
+            print "\t" + line
+        print ""
+        status, buf = host.execute([setup_params['hostapd'], "-v"])
+        if status != 1:
+            print "\t" + setup_params['hostapd'] + " not find\n"
+            continue
+        lines = buf.splitlines()
+        for line in lines:
+            print "\t" + line
+        print ""
+        status, buf = host.execute([setup_params['iperf'], "-v"])
+        if status != 0 and status != 1:
+            print "\t" + setup_params['iperf'] + " not find\n"
+            continue
+        lines = buf.splitlines()
+        for line in lines:
+            print "\t" + line
+        print ""
+
+def check_device(devices, setup_params, dev_name, monitor=False):
+    host = rutils.get_host(devices, dev_name)
+    # simple check if authorized_keys works correctly
+    status, buf = host.execute(["id"])
+    if status != 0:
+        raise Exception(dev_name + " - ssh communication FAILED: " + buf)
+
+    rutils.setup_hw_host(host, setup_params)
+
+    ifaces = re.split('; | |, ', host.ifname)
+    # check interfaces (multi for monitor)
+    for iface in ifaces:
+        status, buf = host.execute(["ifconfig", iface])
+        if status != 0:
+            raise Exception(dev_name + " ifconfig " + iface + " failed: " + buf)
+
+    # monitor doesn't need wpa_supplicant/hostapd ...
+    if monitor == True:
+        return
+
+    status, buf = host.execute(["ls", "-l", setup_params['wpa_supplicant']])
+    if status != 0:
+        raise Exception(dev_name + " - wpa_supplicant: " + buf)
+
+    status, buf = host.execute(["ls", "-l", setup_params['hostapd']])
+    if status != 0:
+        raise Exception(dev_name + " - hostapd: " + buf)
+
+    status, buf = host.execute(["which", setup_params['iperf']])
+    if status != 0:
+        raise Exception(dev_name + " - iperf: " + buf)
+
+    status, buf = host.execute(["which", "tshark"])
+    if status != 0:
+        logger.debug(dev_name + " - tshark: " + buf)
+
+def check_devices(devices, setup_params, refs, duts, monitors):
+    """Check duts/refs/monitors devices"""
+    for dut in duts:
+        check_device(devices, setup_params, dut)
+    for ref in refs:
+        check_device(devices, setup_params, ref)
+    for monitor in monitors:
+        if monitor == "all":
+            continue
+        check_device(devices, setup_params, monitor, monitor=True)
diff --git a/tests/remote/test_example.py b/tests/remote/test_example.py
new file mode 100644 (file)
index 0000000..09c7e77
--- /dev/null
@@ -0,0 +1,141 @@
+# Example test case
+# Copyright (c) 2016, Tieto Corporation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import remotehost
+from wpasupplicant import WpaSupplicant
+import hostapd
+import config
+import rutils
+import monitor
+
+import logging
+logger = logging.getLogger()
+
+def test_example(devices, setup_params, refs, duts, monitors):
+    """TC example - simple connect and ping test"""
+    try:
+        sta = None
+        ap = None
+        hapd = None
+        wpas = None
+        mon = None
+
+        # get hosts based on name
+        sta = rutils.get_host(devices, duts[0])
+        ap = rutils.get_host(devices, refs[0])
+
+        # setup log dir
+        local_log_dir = setup_params['local_log_dir']
+
+        # setup hw before test
+        rutils.setup_hw([sta, ap], setup_params)
+
+        # run traces if requested
+        rutils.trace_start([sta], setup_params)
+
+        # run perf if requested
+        rutils.perf_start([sta], setup_params)
+
+        # run hostapd/wpa_supplicant
+        rutils.run_wpasupplicant(sta, setup_params)
+        rutils.run_hostapd(ap, setup_params)
+
+        # get ap_params
+        ap_params = rutils.get_ap_params(channel="1", bw="HT20", country="US",
+                                         security="open")
+
+        # Add monitors if requested
+        monitor_hosts = monitor.create(devices, setup_params, refs, duts,
+                                       monitors)
+        if len(monitor_hosts) > 0:
+            mon = monitor_hosts[0]
+        monitor.add(sta, monitors)
+        monitor.add(ap, monitors)
+
+        # connect to hostapd/wpa_supplicant UDP CTRL iface
+        hapd = hostapd.add_ap(ap.dev, ap_params)
+        freq = hapd.get_status_field("freq")
+        wpas = WpaSupplicant(hostname = sta.host, global_iface="udp",
+                             global_port = sta.port)
+        wpas.interface_add(sta.ifname)
+
+        # setup standalone monitor based on hapd; could be multi interface
+        # monitor
+        monitor_param = monitor.get_monitor_params(hapd)
+        monitor.setup(mon, [monitor_param])
+
+        # run monitors
+        monitor.run(sta, setup_params)
+        monitor.run(ap, setup_params)
+        monitor.run(mon, setup_params)
+
+        # connect wpa_supplicant to hostapd
+        wpas.connect(ap_params['ssid'], key_mgmt="NONE", scan_freq=freq)
+
+        # run ping test
+        ap_sta, sta_ap = rutils.check_connectivity(ap, sta, "ipv6")
+
+        # remove/destroy monitors
+        monitor.remove(sta)
+        monitor.remove(ap)
+        monitor.destroy(devices, monitor_hosts)
+
+        # hostapd/wpa_supplicant cleanup
+        wpas.interface_remove(sta.ifname)
+        wpas.terminate()
+
+        hapd.close_ctrl()
+        hostapd.remove_bss(ap.dev)
+        hostapd.terminate(ap.dev)
+
+        # stop perf
+        rutils.perf_stop([sta], setup_params)
+
+        # stop traces
+        rutils.trace_stop([sta], setup_params)
+
+        # get wpa_supplicant/hostapd/tshark logs
+        sta.get_logs(local_log_dir)
+        ap.get_logs(local_log_dir)
+        if mon:
+            mon.get_logs(local_log_dir)
+
+        return "packet_loss: " + ap_sta + ", " + sta_ap
+    except:
+        rutils.perf_stop([sta], setup_params)
+        rutils.trace_stop([sta], setup_params)
+        if wpas:
+            try:
+                wpas.interface_remove(sta.ifname)
+                wpas.terminate()
+            except:
+                pass
+        if hapd:
+            try:
+                hapd.close_ctrl()
+                hostapd.remove_bss(ap.dev)
+                hostapd.terminate(ap.dev)
+            except:
+                pass
+        if mon:
+            monitor.destroy(devices, monitor_hosts)
+            mon.get_logs(local_log_dir)
+
+        if sta:
+            monitor.remove(sta)
+            dmesg = setup_params['log_dir'] + setup_params['tc_name'] + "_" + sta.name + "_" + sta.ifname + ".dmesg"
+            sta.execute(["dmesg", "-c", ">", dmesg])
+            sta.add_log(dmesg)
+            sta.get_logs(local_log_dir)
+            sta.execute(["ifconfig", sta.ifname, "down"])
+        if ap:
+            monitor.remove(ap)
+            dmesg = setup_params['log_dir'] + setup_params['tc_name'] + "_" + ap.name + "_" + ap.ifname + ".dmesg"
+            ap.execute(["dmesg", "-c", ">", dmesg])
+            ap.add_log(dmesg)
+            ap.get_logs(local_log_dir)
+            ap.execute(["ifconfig", ap.ifname, " down"])
+        raise
diff --git a/wpa_supplicant/binder/.clang-format b/wpa_supplicant/binder/.clang-format
new file mode 100644 (file)
index 0000000..dbfdabf
--- /dev/null
@@ -0,0 +1,9 @@
+BasedOnStyle: LLVM
+IndentWidth: 8
+UseTab: Always
+BreakBeforeBraces: Mozilla
+AllowShortIfStatementsOnASingleLine: false
+IndentCaseLabels: false
+AccessModifierOffset: -8
+AlignAfterOpenBracket: AlwaysBreak
+SortIncludes: false
diff --git a/wpa_supplicant/binder/binder.cpp b/wpa_supplicant/binder/binder.cpp
new file mode 100644 (file)
index 0000000..750e878
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include "binder_manager.h"
+
+extern "C" {
+#include "binder.h"
+#include "binder_i.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/includes.h"
+}
+
+void wpas_binder_sock_handler(int sock, void *eloop_ctx, void *sock_ctx)
+{
+       struct wpa_global *global = (wpa_global *)eloop_ctx;
+       struct wpas_binder_priv *priv = (wpas_binder_priv *)sock_ctx;
+
+       wpa_printf(
+           MSG_DEBUG, "Processing binder events on FD %d", priv->binder_fd);
+       android::IPCThreadState::self()->handlePolledCommands();
+}
+
+struct wpas_binder_priv *wpas_binder_init(struct wpa_global *global)
+{
+       struct wpas_binder_priv *priv;
+       wpa_supplicant_binder::BinderManager *binder_manager;
+
+       priv = (wpas_binder_priv *)os_zalloc(sizeof(*priv));
+       if (!priv)
+               return NULL;
+       priv->global = global;
+
+       android::ProcessState::self()->setThreadPoolMaxThreadCount(0);
+       android::IPCThreadState::self()->disableBackgroundScheduling(true);
+       android::IPCThreadState::self()->setupPolling(&priv->binder_fd);
+       wpa_printf(MSG_INFO, "Process binder events on FD %d", priv->binder_fd);
+       if (priv->binder_fd < 0)
+               goto err;
+       /* Look for read events from the binder socket in the eloop. */
+       if (eloop_register_read_sock(
+               priv->binder_fd, wpas_binder_sock_handler, global, priv) < 0)
+               goto err;
+
+       binder_manager = wpa_supplicant_binder::BinderManager::getInstance();
+       if (!binder_manager)
+               goto err;
+       binder_manager->registerBinderService(global);
+       /* We may not need to store this binder manager reference in the
+        * global data strucure because we've made it a singleton class. */
+       priv->binder_manager = (void *)binder_manager;
+
+       return priv;
+
+err:
+       wpas_binder_deinit(priv);
+       return NULL;
+}
+
+void wpas_binder_deinit(struct wpas_binder_priv *priv)
+{
+       if (!priv)
+               return;
+
+       wpa_supplicant_binder::BinderManager::destroyInstance();
+       eloop_unregister_read_sock(priv->binder_fd);
+       android::IPCThreadState::shutdown();
+}
+
+int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s->global->binder)
+               return 1;
+
+       wpa_supplicant_binder::BinderManager *binder_manager =
+           wpa_supplicant_binder::BinderManager::getInstance();
+       if (!binder_manager)
+               return 1;
+
+       return binder_manager->registerInterface(wpa_s);
+}
+
+int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s->global->binder)
+               return 1;
+
+       wpa_supplicant_binder::BinderManager *binder_manager =
+           wpa_supplicant_binder::BinderManager::getInstance();
+       if (!binder_manager)
+               return 1;
+
+       return binder_manager->unregisterInterface(wpa_s);
+}
diff --git a/wpa_supplicant/binder/binder.h b/wpa_supplicant/binder/binder.h
new file mode 100644 (file)
index 0000000..019e327
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_BINDER_BINDER_H
+#define WPA_SUPPLICANT_BINDER_BINDER_H
+
+#ifdef _cplusplus
+extern "C" {
+#endif /* _cplusplus */
+
+/**
+ * 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.
+ */
+struct wpas_binder_priv;
+struct wpa_global;
+
+struct wpas_binder_priv *wpas_binder_init(struct wpa_global *global);
+void wpas_binder_deinit(struct wpas_binder_priv *priv);
+
+#ifdef CONFIG_CTRL_IFACE_BINDER
+int wpas_binder_register_interface(struct wpa_supplicant *wpa_s);
+int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s);
+#else  /* CONFIG_CTRL_IFACE_BINDER */
+static inline int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
+{
+       return 0;
+}
+static inline int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+       return 0;
+}
+#endif /* CONFIG_CTRL_IFACE_BINDER */
+
+#ifdef _cplusplus
+}
+#endif /* _cplusplus */
+
+#endif /* WPA_SUPPLICANT_BINDER_BINDER_H */
diff --git a/wpa_supplicant/binder/binder_constants.cpp b/wpa_supplicant/binder/binder_constants.cpp
new file mode 100644 (file)
index 0000000..0d452b1
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "binder_constants.h"
+
+namespace wpa_supplicant_binder {
+namespace binder_constants {
+
+const char kServiceName[] = "wpa_supplicant";
+
+} /* namespace binder_constants */
+} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/binder_constants.h b/wpa_supplicant/binder/binder_constants.h
new file mode 100644 (file)
index 0000000..a4d9b55
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H
+#define WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H
+
+namespace wpa_supplicant_binder {
+namespace binder_constants {
+
+extern const char kServiceName[];
+
+} /* namespace binder_constants */
+} /* namespace wpa_supplicant_binder */
+
+#endif /* WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H */
diff --git a/wpa_supplicant/binder/binder_i.h b/wpa_supplicant/binder/binder_i.h
new file mode 100644 (file)
index 0000000..5140d6d
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BINDER_I_H
+#define BINDER_I_H
+
+#ifdef _cplusplus
+extern "C" {
+#endif // _cplusplus
+
+struct wpas_binder_priv
+{
+       int binder_fd;
+       struct wpa_global *global;
+       void *binder_manager;
+};
+
+#ifdef _cplusplus
+}
+#endif /* _cplusplus */
+
+#endif /* BINDER_I_H */
diff --git a/wpa_supplicant/binder/binder_manager.cpp b/wpa_supplicant/binder/binder_manager.cpp
new file mode 100644 (file)
index 0000000..27e8ded
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <binder/IServiceManager.h>
+
+#include "binder_constants.h"
+#include "binder_manager.h"
+
+extern "C" {
+#include "utils/common.h"
+#include "utils/includes.h"
+}
+
+namespace wpa_supplicant_binder {
+
+BinderManager *BinderManager::instance_ = NULL;
+
+BinderManager *BinderManager::getInstance()
+{
+       if (!instance_)
+               instance_ = new BinderManager();
+       return instance_;
+}
+
+void BinderManager::destroyInstance()
+{
+       if (instance_)
+               delete instance_;
+       instance_ = NULL;
+}
+
+int BinderManager::registerBinderService(struct wpa_global *global)
+{
+       /* Create the main binder service object and register with
+        * system service manager. */
+       supplicant_object_ = new Supplicant(global);
+       android::String16 service_name(binder_constants::kServiceName);
+       android::defaultServiceManager()->addService(
+           service_name, android::IInterface::asBinder(supplicant_object_));
+       return 0;
+}
+
+int BinderManager::registerInterface(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s)
+               return 1;
+
+       /* Using the corresponding wpa_supplicant pointer as key to our
+        * object map. */
+       const void *iface_key = wpa_s;
+
+       /* Return failure if we already have an object for that iface_key. */
+       if (iface_object_map_.find(iface_key) != iface_object_map_.end())
+               return 1;
+
+       iface_object_map_[iface_key] = new Iface(wpa_s);
+       if (!iface_object_map_[iface_key].get())
+               return 1;
+
+       wpa_s->binder_object_key = iface_key;
+
+       return 0;
+}
+
+int BinderManager::unregisterInterface(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s || !wpa_s->binder_object_key)
+               return 1;
+
+       const void *iface_key = wpa_s;
+       if (iface_object_map_.find(iface_key) == iface_object_map_.end())
+               return 1;
+
+       /* Delete the corresponding iface object from our map. */
+       iface_object_map_.erase(iface_key);
+       wpa_s->binder_object_key = NULL;
+       return 0;
+}
+
+int BinderManager::getIfaceBinderObjectByKey(
+    const void *iface_object_key,
+    android::sp<fi::w1::wpa_supplicant::IIface> *iface_object)
+{
+       if (!iface_object_key || !iface_object)
+               return 1;
+
+       if (iface_object_map_.find(iface_object_key) == iface_object_map_.end())
+               return 1;
+
+       *iface_object = iface_object_map_[iface_object_key];
+       return 0;
+}
+
+} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/binder_manager.h b/wpa_supplicant/binder/binder_manager.h
new file mode 100644 (file)
index 0000000..d8b7dd0
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H
+#define WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H
+
+#include <map>
+#include <string>
+
+#include "iface.h"
+#include "supplicant.h"
+
+struct wpa_global;
+struct wpa_supplicant;
+
+namespace wpa_supplicant_binder {
+
+/**
+ * BinderManager is responsible for managing the lifetime of all
+ * binder objects created by wpa_supplicant. This is a singleton
+ * class which is created by the supplicant core and can be used
+ * to get references to the binder objects.
+ */
+class BinderManager
+{
+public:
+       static BinderManager *getInstance();
+       static void destroyInstance();
+       int registerBinderService(struct wpa_global *global);
+       int registerInterface(struct wpa_supplicant *wpa_s);
+       int unregisterInterface(struct wpa_supplicant *wpa_s);
+       int getIfaceBinderObjectByKey(
+           const void *iface_object_key,
+           android::sp<fi::w1::wpa_supplicant::IIface> *iface_object);
+
+private:
+       BinderManager() = default;
+       ~BinderManager() = default;
+
+       /* Singleton instance of this class. */
+       static BinderManager *instance_;
+       /* The main binder service object. */
+       android::sp<Supplicant> supplicant_object_;
+       /* Map of all the interface specific binder objects controlled by
+        * wpa_supplicant. This map is keyed in by the corresponding
+        * wpa_supplicant structure pointer. */
+       std::map<const void *, android::sp<Iface>> iface_object_map_;
+};
+
+} /* namespace wpa_supplicant_binder */
+
+#endif /* WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H */
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl
new file mode 100644 (file)
index 0000000..ea11d42
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package fi.w1.wpa_supplicant;
+
+/**
+ * Interface exposed by wpa_supplicant for each network interface it controls.
+ */
+interface IIface {
+}
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl
new file mode 100644 (file)
index 0000000..1cbee20
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * WPA Supplicant - binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package fi.w1.wpa_supplicant;
+
+import android.os.PersistableBundle;
+import fi.w1.wpa_supplicant.IIface;
+
+/**
+ * Interface exposed by the wpa_supplicant binder service registered
+ * with the service manager with name: fi.w1.wpa_supplicant.
+ */
+interface ISupplicant {
+       /* Error values returned by the service to RPC method calls. */
+       const int ERROR_INVALID_ARGS = 1;
+       const int ERROR_UNKNOWN = 2;
+       const int ERROR_IFACE_EXISTS = 3;
+       const int ERROR_IFACE_UNKNOWN = 4;
+
+       /**
+        * Registers a wireless interface in wpa_supplicant.
+        *
+        * @param args A dictionary with arguments used to add the interface to
+        *             wpa_supplicant.
+        * The dictionary may contain the following entries:
+        *   Ifname(String) Name of the network interface to control, e.g.,
+        *   wlan0.
+        *   BridgeIfname(String) Name of the bridge interface to control, e.g.,
+        *   br0.
+        *   Driver(String) Driver name which the interface uses, e.g., nl80211.
+        *   ConfigFile(String) Configuration file path.
+        *
+        * @return Binder object representing the interface.
+        */
+       IIface CreateInterface(in PersistableBundle args);
+
+       /**
+        * Deregisters a wireless interface from wpa_supplicant.
+        *
+        * @param ifname Name of the network interface, e.g., wlan0
+        */
+       void RemoveInterface(in @utf8InCpp String ifname);
+
+       /**
+        * Gets a binder object for the interface corresponding to ifname
+        * which wpa_supplicant already controls.
+        *
+        * @param ifname Name of the network interface, e.g., wlan0
+        *
+        * @return Binder object representing the interface.
+        */
+       IIface GetInterface(in @utf8InCpp String ifname);
+}
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl
new file mode 100644 (file)
index 0000000..d624d91
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package fi.w1.wpa_supplicant;
+
+import android.os.PersistableBundle;
+
+/**
+ * Callback Interface exposed by the wpa_supplicant service. Clients need
+ * to host an instance of this binder object and pass a reference of the object
+ * to wpa_supplicant via the registerCallbacksObject method.
+ */
+interface ISupplicantCallbacks {
+}
diff --git a/wpa_supplicant/binder/iface.cpp b/wpa_supplicant/binder/iface.cpp
new file mode 100644 (file)
index 0000000..c61b3b0
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "iface.h"
+
+namespace wpa_supplicant_binder {
+
+Iface::Iface(struct wpa_supplicant *wpa_s) : wpa_s_(wpa_s) {}
+
+} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/iface.h b/wpa_supplicant/binder/iface.h
new file mode 100644 (file)
index 0000000..c0ee12c
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_BINDER_IFACE_H
+#define WPA_SUPPLICANT_BINDER_IFACE_H
+
+#include "fi/w1/wpa_supplicant/BnIface.h"
+
+extern "C" {
+#include "utils/common.h"
+#include "utils/includes.h"
+#include "../wpa_supplicant_i.h"
+}
+
+namespace wpa_supplicant_binder {
+
+/**
+ * Implementation of Iface binder object. Each unique binder
+ * object is used for control operations on a specific interface
+ * controlled by wpa_supplicant.
+ */
+class Iface : public fi::w1::wpa_supplicant::BnIface
+{
+public:
+       Iface(struct wpa_supplicant *wpa_s);
+       virtual ~Iface() = default;
+
+private:
+       /* Raw pointer to the structure maintained by the core for this
+        * interface. */
+       struct wpa_supplicant *wpa_s_;
+};
+
+} /* namespace wpa_supplicant_binder */
+
+#endif /* WPA_SUPPLICANT_BINDER_IFACE_H */
diff --git a/wpa_supplicant/binder/supplicant.cpp b/wpa_supplicant/binder/supplicant.cpp
new file mode 100644 (file)
index 0000000..76569b1
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "supplicant.h"
+#include "binder_manager.h"
+
+namespace wpa_supplicant_binder {
+
+Supplicant::Supplicant(struct wpa_global *global) : wpa_global_(global) {}
+
+android::binder::Status Supplicant::CreateInterface(
+    const android::os::PersistableBundle &params,
+    android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+{
+       android::String16 driver, ifname, confname, bridge_ifname;
+
+       /* Check if required Ifname argument is missing */
+       if (!params.getString(android::String16("Ifname"), &ifname))
+               return android::binder::Status::fromServiceSpecificError(
+                   ERROR_INVALID_ARGS,
+                   android::String8("Ifname missing in params."));
+       /* Retrieve the remaining params from the dictionary */
+       params.getString(android::String16("Driver"), &driver);
+       params.getString(android::String16("ConfigFile"), &confname);
+       params.getString(android::String16("BridgeIfname"), &bridge_ifname);
+
+       /*
+        * Try to get the wpa_supplicant record for this iface, return
+        * an error if we already control it.
+        */
+       if (wpa_supplicant_get_iface(
+               wpa_global_, android::String8(ifname).string()) != NULL)
+               return android::binder::Status::fromServiceSpecificError(
+                   ERROR_IFACE_EXISTS,
+                   android::String8("wpa_supplicant already controls this "
+                                    "interface."));
+
+       android::binder::Status status;
+       struct wpa_supplicant *wpa_s = NULL;
+       struct wpa_interface iface;
+
+       os_memset(&iface, 0, sizeof(iface));
+       iface.driver = os_strdup(android::String8(driver).string());
+       iface.ifname = os_strdup(android::String8(ifname).string());
+       iface.confname = os_strdup(android::String8(confname).string());
+       iface.bridge_ifname =
+           os_strdup(android::String8(bridge_ifname).string());
+       /* Otherwise, have wpa_supplicant attach to it. */
+       wpa_s = wpa_supplicant_add_iface(wpa_global_, &iface, NULL);
+       /* The supplicant core creates a corresponding binder object via
+        * BinderManager when |wpa_supplicant_add_iface| is called. */
+       if (!wpa_s || !wpa_s->binder_object_key) {
+               status = android::binder::Status::fromServiceSpecificError(
+                   ERROR_UNKNOWN,
+                   android::String8(
+                       "wpa_supplicant couldn't grab this interface."));
+       } else {
+               BinderManager *binder_manager = BinderManager::getInstance();
+
+               if (!binder_manager ||
+                   binder_manager->getIfaceBinderObjectByKey(
+                       wpa_s->binder_object_key, aidl_return))
+                       status =
+                           android::binder::Status::fromServiceSpecificError(
+                               ERROR_UNKNOWN,
+                               android::String8("wpa_supplicant encountered a "
+                                                "binder error."));
+               else
+                       status = android::binder::Status::ok();
+       }
+       os_free((void *)iface.driver);
+       os_free((void *)iface.ifname);
+       os_free((void *)iface.confname);
+       os_free((void *)iface.bridge_ifname);
+       return status;
+}
+
+android::binder::Status Supplicant::RemoveInterface(const std::string &ifname)
+{
+       struct wpa_supplicant *wpa_s;
+
+       wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str());
+       if (!wpa_s || !wpa_s->binder_object_key)
+               return android::binder::Status::fromServiceSpecificError(
+                   ERROR_IFACE_UNKNOWN,
+                   android::String8("wpa_supplicant does not control this "
+                                    "interface."));
+       if (wpa_supplicant_remove_iface(wpa_global_, wpa_s, 0))
+               return android::binder::Status::fromServiceSpecificError(
+                   ERROR_UNKNOWN,
+                   android::String8(
+                       "wpa_supplicant couldn't remove this interface."));
+       return android::binder::Status::ok();
+}
+
+android::binder::Status Supplicant::GetInterface(
+    const std::string &ifname,
+    android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+{
+       struct wpa_supplicant *wpa_s;
+
+       wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str());
+       if (!wpa_s || !wpa_s->binder_object_key)
+               return android::binder::Status::fromServiceSpecificError(
+                   ERROR_IFACE_UNKNOWN,
+                   android::String8(
+                       "wpa_supplicant does not control this interface."));
+
+       BinderManager *binder_manager = BinderManager::getInstance();
+       if (!binder_manager ||
+           binder_manager->getIfaceBinderObjectByKey(
+               wpa_s->binder_object_key, aidl_return))
+               return android::binder::Status::fromServiceSpecificError(
+                   ERROR_UNKNOWN,
+                   android::String8(
+                       "wpa_supplicant encountered a binder error."));
+
+       return android::binder::Status::ok();
+}
+
+} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/supplicant.h b/wpa_supplicant/binder/supplicant.h
new file mode 100644 (file)
index 0000000..136b99b
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_BINDER_SUPPLICANT_H
+#define WPA_SUPPLICANT_BINDER_SUPPLICANT_H
+
+#include "fi/w1/wpa_supplicant/BnSupplicant.h"
+#include "fi/w1/wpa_supplicant/IIface.h"
+#include "fi/w1/wpa_supplicant/ISupplicantCallbacks.h"
+
+extern "C" {
+#include "utils/common.h"
+#include "utils/includes.h"
+#include "../wpa_supplicant_i.h"
+}
+
+namespace wpa_supplicant_binder {
+
+/**
+ * Implementation of the supplicant binder object. This binder
+ * object is used core for global control operations on
+ * wpa_supplicant.
+ */
+class Supplicant : public fi::w1::wpa_supplicant::BnSupplicant
+{
+public:
+       Supplicant(struct wpa_global *global);
+       virtual ~Supplicant() = default;
+
+       android::binder::Status CreateInterface(
+           const android::os::PersistableBundle &params,
+           android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return) override;
+       android::binder::Status
+       RemoveInterface(const std::string &ifname) override;
+       android::binder::Status GetInterface(
+           const std::string &ifname,
+           android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return) override;
+
+private:
+       /* Raw pointer to the global structure maintained by the core. */
+       struct wpa_global *wpa_global_;
+       /* All the callback objects registered by the clients. */
+       std::vector<android::sp<fi::w1::wpa_supplicant::ISupplicantCallbacks>>
+           callbacks_;
+};
+
+} /* namespace wpa_supplicant_binder */
+
+#endif /* WPA_SUPPLICANT_BINDER_SUPPLICANT_H */
diff --git a/wpa_supplicant/libwpa_test.c b/wpa_supplicant/libwpa_test.c
new file mode 100644 (file)
index 0000000..e51ab72
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * libwpa_test - Test program for libwpa_client.* library linking
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common/wpa_ctrl.h"
+
+int main(int argc, char *argv[])
+{
+       struct wpa_ctrl *ctrl;
+
+       ctrl = wpa_ctrl_open("foo");
+       if (!ctrl)
+               return -1;
+       if (wpa_ctrl_attach(ctrl) == 0)
+               wpa_ctrl_detach(ctrl);
+       if (wpa_ctrl_pending(ctrl)) {
+               char buf[10];
+               size_t len;
+
+               len = sizeof(buf);
+               wpa_ctrl_recv(ctrl, buf, &len);
+       }
+       wpa_ctrl_close(ctrl);
+
+       return 0;
+}
diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c
new file mode 100644 (file)
index 0000000..7e049be
--- /dev/null
@@ -0,0 +1,836 @@
+/*
+ * wpa_supplicant - MBO
+ *
+ * Copyright(c) 2015 Intel Deutschland GmbH
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * 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_defs.h"
+#include "common/gas.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "bss.h"
+#include "scan.h"
+
+/* type + length + oui + oui type */
+#define MBO_IE_HEADER 6
+
+
+static int wpas_mbo_validate_non_pref_chan(u8 oper_class, u8 chan, u8 reason)
+{
+       if (reason > MBO_NON_PREF_CHAN_REASON_INT_INTERFERENCE)
+               return -1;
+
+       /* Only checking the validity of the channel and oper_class */
+       if (ieee80211_chan_to_freq(NULL, oper_class, chan) == -1)
+               return -1;
+
+       return 0;
+}
+
+
+const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr)
+{
+       const u8 *mbo, *end;
+
+       if (!bss)
+               return NULL;
+
+       mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
+       if (!mbo)
+               return NULL;
+
+       end = mbo + 2 + mbo[1];
+       mbo += MBO_IE_HEADER;
+
+       return get_ie(mbo, end - mbo, attr);
+}
+
+
+static void wpas_mbo_non_pref_chan_attr_body(struct wpa_supplicant *wpa_s,
+                                            struct wpabuf *mbo,
+                                            u8 start, u8 end)
+{
+       u8 i;
+
+       wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].oper_class);
+
+       for (i = start; i < end; i++)
+               wpabuf_put_u8(mbo, wpa_s->non_pref_chan[i].chan);
+
+       wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].preference);
+       wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].reason);
+}
+
+
+static void wpas_mbo_non_pref_chan_attr(struct wpa_supplicant *wpa_s,
+                                       struct wpabuf *mbo, u8 start, u8 end)
+{
+       size_t size = end - start + 3;
+
+       if (size + 2 > wpabuf_tailroom(mbo))
+               return;
+
+       wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT);
+       wpabuf_put_u8(mbo, size); /* Length */
+
+       wpas_mbo_non_pref_chan_attr_body(wpa_s, mbo, start, end);
+}
+
+
+static void wpas_mbo_non_pref_chan_subelem_hdr(struct wpabuf *mbo, u8 len)
+{
+       wpabuf_put_u8(mbo, WLAN_EID_VENDOR_SPECIFIC);
+       wpabuf_put_u8(mbo, len); /* Length */
+       wpabuf_put_be24(mbo, OUI_WFA);
+       wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT);
+}
+
+
+static void wpas_mbo_non_pref_chan_subelement(struct wpa_supplicant *wpa_s,
+                                             struct wpabuf *mbo, u8 start,
+                                             u8 end)
+{
+       size_t size = end - start + 7;
+
+       if (size + 2 > wpabuf_tailroom(mbo))
+               return;
+
+       wpas_mbo_non_pref_chan_subelem_hdr(mbo, size);
+       wpas_mbo_non_pref_chan_attr_body(wpa_s, mbo, start, end);
+}
+
+
+static void wpas_mbo_non_pref_chan_attrs(struct wpa_supplicant *wpa_s,
+                                        struct wpabuf *mbo, int subelement)
+{
+       u8 i, start = 0;
+       struct wpa_mbo_non_pref_channel *start_pref;
+
+       if (!wpa_s->non_pref_chan || !wpa_s->non_pref_chan_num) {
+               if (subelement)
+                       wpas_mbo_non_pref_chan_subelem_hdr(mbo, 4);
+               return;
+       }
+       start_pref = &wpa_s->non_pref_chan[0];
+
+       for (i = 1; i <= wpa_s->non_pref_chan_num; i++) {
+               struct wpa_mbo_non_pref_channel *non_pref = NULL;
+
+               if (i < wpa_s->non_pref_chan_num)
+                       non_pref = &wpa_s->non_pref_chan[i];
+               if (!non_pref ||
+                   non_pref->oper_class != start_pref->oper_class ||
+                   non_pref->reason != start_pref->reason ||
+                   non_pref->preference != start_pref->preference) {
+                       if (subelement)
+                               wpas_mbo_non_pref_chan_subelement(wpa_s, mbo,
+                                                                 start, i);
+                       else
+                               wpas_mbo_non_pref_chan_attr(wpa_s, mbo, start,
+                                                           i);
+
+                       if (!non_pref)
+                               return;
+
+                       start = i;
+                       start_pref = non_pref;
+               }
+       }
+}
+
+
+int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len)
+{
+       struct wpabuf *mbo;
+       int res;
+
+       if (len < MBO_IE_HEADER + 3 + 7)
+               return 0;
+
+       /* Leave room for the MBO IE header */
+       mbo = wpabuf_alloc(len - MBO_IE_HEADER);
+       if (!mbo)
+               return 0;
+
+       /* Add non-preferred channels attribute */
+       wpas_mbo_non_pref_chan_attrs(wpa_s, mbo, 0);
+
+       /*
+        * Send cellular capabilities attribute even if AP does not advertise
+        * cellular capabilities.
+        */
+       wpabuf_put_u8(mbo, MBO_ATTR_ID_CELL_DATA_CAPA);
+       wpabuf_put_u8(mbo, 1);
+       wpabuf_put_u8(mbo, wpa_s->conf->mbo_cell_capa);
+
+       res = mbo_add_ie(buf, len, wpabuf_head_u8(mbo), wpabuf_len(mbo));
+       if (!res)
+               wpa_printf(MSG_ERROR, "Failed to add MBO IE");
+
+       wpabuf_free(mbo);
+       return res;
+}
+
+
+static void wpas_mbo_send_wnm_notification(struct wpa_supplicant *wpa_s,
+                                          const u8 *data, size_t len)
+{
+       struct wpabuf *buf;
+       int res;
+
+       /*
+        * Send WNM-Notification Request frame only in case of a change in
+        * non-preferred channels list during association, if the AP supports
+        * MBO.
+        */
+       if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_bss ||
+           !wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE))
+               return;
+
+       buf = wpabuf_alloc(4 + len);
+       if (!buf)
+               return;
+
+       wpabuf_put_u8(buf, WLAN_ACTION_WNM);
+       wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
+       wpa_s->mbo_wnm_token++;
+       if (wpa_s->mbo_wnm_token == 0)
+               wpa_s->mbo_wnm_token++;
+       wpabuf_put_u8(buf, wpa_s->mbo_wnm_token);
+       wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); /* Type */
+
+       wpabuf_put_data(buf, data, len);
+
+       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 with non-preferred channel list");
+
+       wpabuf_free(buf);
+}
+
+
+static void wpas_mbo_non_pref_chan_changed(struct wpa_supplicant *wpa_s)
+{
+       struct wpabuf *buf;
+
+       buf = wpabuf_alloc(512);
+       if (!buf)
+               return;
+
+       wpas_mbo_non_pref_chan_attrs(wpa_s, buf, 1);
+       wpas_mbo_send_wnm_notification(wpa_s, wpabuf_head_u8(buf),
+                                      wpabuf_len(buf));
+       wpabuf_free(buf);
+}
+
+
+static int wpa_non_pref_chan_is_eq(struct wpa_mbo_non_pref_channel *a,
+                                  struct wpa_mbo_non_pref_channel *b)
+{
+       return a->oper_class == b->oper_class && a->chan == b->chan;
+}
+
+
+/*
+ * wpa_non_pref_chan_cmp - Compare two channels for sorting
+ *
+ * In MBO IE non-preferred channel subelement we can put many channels in an
+ * attribute if they are in the same operating class and have the same
+ * preference and reason. To make it easy for the functions that build
+ * the IE attributes and WNM Request subelements, save the channels sorted
+ * by their oper_class and reason.
+ */
+static int wpa_non_pref_chan_cmp(const void *_a, const void *_b)
+{
+       const struct wpa_mbo_non_pref_channel *a = _a, *b = _b;
+
+       if (a->oper_class != b->oper_class)
+               return a->oper_class - b->oper_class;
+       if (a->reason != b->reason)
+               return a->reason - b->reason;
+       return a->preference - b->preference;
+}
+
+
+int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
+                                 const char *non_pref_chan)
+{
+       char *cmd, *token, *context = NULL;
+       struct wpa_mbo_non_pref_channel *chans = NULL, *tmp_chans;
+       size_t num = 0, size = 0;
+       unsigned i;
+
+       wpa_printf(MSG_DEBUG, "MBO: Update non-preferred channels, non_pref_chan=%s",
+                  non_pref_chan ? non_pref_chan : "N/A");
+
+       /*
+        * The shortest channel configuration is 10 characters - commas, 3
+        * colons, and 4 values that one of them (oper_class) is 2 digits or
+        * more.
+        */
+       if (!non_pref_chan || os_strlen(non_pref_chan) < 10)
+               goto update;
+
+       cmd = os_strdup(non_pref_chan);
+       if (!cmd)
+               return -1;
+
+       while ((token = str_token(cmd, " ", &context))) {
+               struct wpa_mbo_non_pref_channel *chan;
+               int ret;
+               unsigned int _oper_class;
+               unsigned int _chan;
+               unsigned int _preference;
+               unsigned int _reason;
+
+               if (num == size) {
+                       size = size ? size * 2 : 1;
+                       tmp_chans = os_realloc_array(chans, size,
+                                                    sizeof(*chans));
+                       if (!tmp_chans) {
+                               wpa_printf(MSG_ERROR,
+                                          "Couldn't reallocate non_pref_chan");
+                               goto fail;
+                       }
+                       chans = tmp_chans;
+               }
+
+               chan = &chans[num];
+
+               ret = sscanf(token, "%u:%u:%u:%u", &_oper_class,
+                            &_chan, &_preference, &_reason);
+               if (ret != 4 ||
+                   _oper_class > 255 || _chan > 255 ||
+                   _preference > 255 || _reason > 65535 ) {
+                       wpa_printf(MSG_ERROR, "Invalid non-pref chan input %s",
+                                  token);
+                       goto fail;
+               }
+               chan->oper_class = _oper_class;
+               chan->chan = _chan;
+               chan->preference = _preference;
+               chan->reason = _reason;
+
+               if (wpas_mbo_validate_non_pref_chan(chan->oper_class,
+                                                   chan->chan, chan->reason)) {
+                       wpa_printf(MSG_ERROR,
+                                  "Invalid non_pref_chan: oper class %d chan %d reason %d",
+                                  chan->oper_class, chan->chan, chan->reason);
+                       goto fail;
+               }
+
+               for (i = 0; i < num; i++)
+                       if (wpa_non_pref_chan_is_eq(chan, &chans[i]))
+                               break;
+               if (i != num) {
+                       wpa_printf(MSG_ERROR,
+                                  "oper class %d chan %d is duplicated",
+                                  chan->oper_class, chan->chan);
+                       goto fail;
+               }
+
+               num++;
+       }
+
+       os_free(cmd);
+
+       if (chans) {
+               qsort(chans, num, sizeof(struct wpa_mbo_non_pref_channel),
+                     wpa_non_pref_chan_cmp);
+       }
+
+update:
+       os_free(wpa_s->non_pref_chan);
+       wpa_s->non_pref_chan = chans;
+       wpa_s->non_pref_chan_num = num;
+       wpas_mbo_non_pref_chan_changed(wpa_s);
+
+       return 0;
+
+fail:
+       os_free(chans);
+       os_free(cmd);
+       return -1;
+}
+
+
+void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie)
+{
+       wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+       wpabuf_put_u8(ie, 7);
+       wpabuf_put_be24(ie, OUI_WFA);
+       wpabuf_put_u8(ie, MBO_OUI_TYPE);
+
+       wpabuf_put_u8(ie, MBO_ATTR_ID_CELL_DATA_CAPA);
+       wpabuf_put_u8(ie, 1);
+       wpabuf_put_u8(ie, wpa_s->conf->mbo_cell_capa);
+}
+
+
+enum chan_allowed {
+       NOT_ALLOWED, ALLOWED
+};
+
+static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, u8 chan,
+                                      unsigned int *flags)
+{
+       int i;
+
+       for (i = 0; i < mode->num_channels; i++) {
+               if (mode->channels[i].chan == chan)
+                       break;
+       }
+
+       if (i == mode->num_channels ||
+           (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED))
+               return NOT_ALLOWED;
+
+       if (flags)
+               *flags = mode->channels[i].flag;
+
+       return ALLOWED;
+}
+
+
+static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel)
+{
+       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++) {
+               /*
+                * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
+                * so the center channel is 6 channels away from the start/end.
+                */
+               if (channel >= center_channels[i] - 6 &&
+                   channel <= center_channels[i] + 6)
+                       return center_channels[i];
+       }
+
+       return 0;
+}
+
+
+static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
+{
+       u8 center_chan;
+       unsigned int i;
+
+       center_chan = get_center_80mhz(mode, channel);
+       if (!center_chan)
+               return NOT_ALLOWED;
+
+       /* check all the channels are available */
+       for (i = 0; i < 4; i++) {
+               unsigned int flags;
+               u8 adj_chan = center_chan - 6 + i * 4;
+
+               if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+                       return NOT_ALLOWED;
+
+               if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) ||
+                   (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) ||
+                   (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) ||
+                   (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10)))
+                       return NOT_ALLOWED;
+       }
+
+       return ALLOWED;
+}
+
+
+static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel)
+{
+       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++) {
+               /*
+                * In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
+                * so the center channel is 14 channels away from the start/end.
+                */
+               if (channel >= center_channels[i] - 14 &&
+                   channel <= center_channels[i] + 14)
+                       return center_channels[i];
+       }
+
+       return 0;
+}
+
+
+static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
+                                      u8 channel)
+{
+       u8 center_chan;
+       unsigned int i;
+
+       center_chan = get_center_160mhz(mode, channel);
+       if (!center_chan)
+               return NOT_ALLOWED;
+
+       /* Check all the channels are available */
+       for (i = 0; i < 8; i++) {
+               unsigned int flags;
+               u8 adj_chan = center_chan - 14 + i * 4;
+
+               if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+                       return NOT_ALLOWED;
+
+               if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) ||
+                   (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) ||
+                   (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) ||
+                   (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) ||
+                   (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) ||
+                   (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) ||
+                   (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) ||
+                   (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10)))
+                       return NOT_ALLOWED;
+       }
+
+       return ALLOWED;
+}
+
+
+static enum chan_allowed verify_channel(struct hostapd_hw_modes *mode,
+                                       u8 channel, u8 bw)
+{
+       unsigned int flag = 0;
+       enum chan_allowed res, res2;
+
+       res2 = res = allow_channel(mode, channel, &flag);
+       if (bw == BW40MINUS) {
+               if (!(flag & HOSTAPD_CHAN_HT40MINUS))
+                       return NOT_ALLOWED;
+               res2 = allow_channel(mode, channel - 4, NULL);
+       } else if (bw == BW40PLUS) {
+               if (!(flag & HOSTAPD_CHAN_HT40PLUS))
+                       return NOT_ALLOWED;
+               res2 = allow_channel(mode, 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);
+       } 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);
+       } 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);
+       }
+
+       if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
+               return NOT_ALLOWED;
+
+       return ALLOWED;
+}
+
+
+static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
+                                  const struct oper_class_map *op_class)
+{
+       int chan;
+       size_t i;
+       struct hostapd_hw_modes *mode;
+       int found;
+
+       mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
+       if (!mode)
+               return 0;
+
+       if (op_class->op_class == 128) {
+               u8 channels[] = { 42, 58, 106, 122, 138, 155 };
+
+               for (i = 0; i < ARRAY_SIZE(channels); i++) {
+                       if (verify_channel(mode, channels[i], op_class->bw) ==
+                           ALLOWED)
+                               return 1;
+               }
+
+               return 0;
+       }
+
+       if (op_class->op_class == 129) {
+               /* Check if either 160 MHz channels is allowed */
+               return verify_channel(mode, 50, op_class->bw) == ALLOWED ||
+                       verify_channel(mode, 114, op_class->bw) == 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) == ALLOWED ||
+                   verify_channel(mode, 58, op_class->bw) == ALLOWED)
+                       found++;
+               if (verify_channel(mode, 106, op_class->bw) == ALLOWED ||
+                   verify_channel(mode, 122, op_class->bw) == ALLOWED ||
+                   verify_channel(mode, 138, op_class->bw) == ALLOWED)
+                       found++;
+               if (verify_channel(mode, 106, op_class->bw) == ALLOWED &&
+                   verify_channel(mode, 138, op_class->bw) == ALLOWED)
+                       found++;
+               if (verify_channel(mode, 155, op_class->bw) == ALLOWED)
+                       found++;
+
+               if (found >= 2)
+                       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) == ALLOWED) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       return found;
+}
+
+
+int wpas_mbo_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
+                             size_t len)
+{
+       struct wpabuf *buf;
+       u8 op, current, chan;
+       u8 *ie_len;
+       int res;
+
+       /*
+        * Assume 20 MHz channel for now.
+        * TODO: Use the secondary channel and VHT channel width that will be
+        * used after association.
+        */
+       if (ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
+                                         &current, &chan) == NUM_HOSTAPD_MODES)
+               return 0;
+
+       /*
+        * Need 3 bytes for EID, length, and current operating class, plus
+        * 1 byte for every other supported operating class.
+        */
+       buf = wpabuf_alloc(global_op_class_size + 3);
+       if (!buf)
+               return 0;
+
+       wpabuf_put_u8(buf, WLAN_EID_SUPPORTED_OPERATING_CLASSES);
+       /* Will set the length later, putting a placeholder */
+       ie_len = wpabuf_put(buf, 1);
+       wpabuf_put_u8(buf, current);
+
+       for (op = 0; global_op_class[op].op_class; op++) {
+               if (wpas_op_class_supported(wpa_s, &global_op_class[op]))
+                       wpabuf_put_u8(buf, global_op_class[op].op_class);
+       }
+
+       *ie_len = wpabuf_len(buf) - 2;
+       if (*ie_len < 2 || wpabuf_len(buf) > len) {
+               wpa_printf(MSG_ERROR,
+                          "Failed to add supported operating classes IE");
+               res = 0;
+       } else {
+               os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf));
+               res = wpabuf_len(buf);
+               wpa_hexdump_buf(MSG_DEBUG,
+                               "MBO: Added supported operating classes IE",
+                               buf);
+       }
+
+       wpabuf_free(buf);
+       return res;
+}
+
+
+void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie,
+                          size_t len)
+{
+       const u8 *pos, *cell_pref = NULL, *reason = NULL;
+       u8 id, elen;
+       u16 disallowed_sec = 0;
+
+       if (len <= 4 || WPA_GET_BE24(mbo_ie) != OUI_WFA ||
+           mbo_ie[3] != MBO_OUI_TYPE)
+               return;
+
+       pos = mbo_ie + 4;
+       len -= 4;
+
+       while (len >= 2) {
+               id = *pos++;
+               elen = *pos++;
+               len -= 2;
+
+               if (elen > len)
+                       goto fail;
+
+               switch (id) {
+               case MBO_ATTR_ID_CELL_DATA_PREF:
+                       if (elen != 1)
+                               goto fail;
+
+                       if (wpa_s->conf->mbo_cell_capa ==
+                           MBO_CELL_CAPA_AVAILABLE)
+                               cell_pref = pos;
+                       else
+                               wpa_printf(MSG_DEBUG,
+                                          "MBO: Station does not support Cellular data connection");
+                       break;
+               case MBO_ATTR_ID_TRANSITION_REASON:
+                       if (elen != 1)
+                               goto fail;
+
+                       reason = pos;
+                       break;
+               case MBO_ATTR_ID_ASSOC_RETRY_DELAY:
+                       if (elen != 2)
+                               goto fail;
+
+                       if (wpa_s->wnm_mode &
+                           WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
+                               wpa_printf(MSG_DEBUG,
+                                          "MBO: Unexpected association retry delay, BSS is terminating");
+                               goto fail;
+                       } else if (wpa_s->wnm_mode &
+                                  WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
+                               disallowed_sec = WPA_GET_LE16(pos);
+                       } else {
+                               wpa_printf(MSG_DEBUG,
+                                          "MBO: Association retry delay attribute not in disassoc imminent mode");
+                       }
+
+                       break;
+               case MBO_ATTR_ID_AP_CAPA_IND:
+               case MBO_ATTR_ID_NON_PREF_CHAN_REPORT:
+               case MBO_ATTR_ID_CELL_DATA_CAPA:
+               case MBO_ATTR_ID_ASSOC_DISALLOW:
+               case MBO_ATTR_ID_TRANSITION_REJECT_REASON:
+                       wpa_printf(MSG_DEBUG,
+                                  "MBO: Attribute %d should not be included in BTM Request frame",
+                                  id);
+                       break;
+               default:
+                       wpa_printf(MSG_DEBUG, "MBO: Unknown attribute id %u",
+                                  id);
+                       return;
+               }
+
+               pos += elen;
+               len -= elen;
+       }
+
+       if (cell_pref)
+               wpa_msg(wpa_s, MSG_INFO, MBO_CELL_PREFERENCE "preference=%u",
+                       *cell_pref);
+
+       if (reason)
+               wpa_msg(wpa_s, MSG_INFO, MBO_TRANSITION_REASON "reason=%u",
+                       *reason);
+
+       if (disallowed_sec && wpa_s->current_bss)
+               wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid,
+                                    disallowed_sec);
+
+       return;
+fail:
+       wpa_printf(MSG_DEBUG, "MBO IE parsing failed (id=%u len=%u left=%zu)",
+                  id, elen, len);
+}
+
+
+size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos,
+                                   size_t len,
+                                   enum mbo_transition_reject_reason reason)
+{
+       u8 reject_attr[3];
+
+       reject_attr[0] = MBO_ATTR_ID_TRANSITION_REJECT_REASON;
+       reject_attr[1] = 1;
+       reject_attr[2] = reason;
+
+       return mbo_add_ie(pos, len, reject_attr, sizeof(reject_attr));
+}
+
+
+void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa)
+{
+       u8 cell_capa[7];
+
+       if (wpa_s->conf->mbo_cell_capa == mbo_cell_capa) {
+               wpa_printf(MSG_DEBUG,
+                          "MBO: Cellular capability already set to %u",
+                          mbo_cell_capa);
+               return;
+       }
+
+       wpa_s->conf->mbo_cell_capa = mbo_cell_capa;
+
+       cell_capa[0] = WLAN_EID_VENDOR_SPECIFIC;
+       cell_capa[1] = 5; /* Length */
+       WPA_PUT_BE24(cell_capa + 2, OUI_WFA);
+       cell_capa[5] = MBO_ATTR_ID_CELL_DATA_CAPA;
+       cell_capa[6] = mbo_cell_capa;
+
+       wpas_mbo_send_wnm_notification(wpa_s, cell_capa, 7);
+       wpa_supplicant_set_default_scan_ies(wpa_s);
+}
+
+
+struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s,
+                                  struct wpa_bss *bss)
+{
+       struct wpabuf *anqp_buf;
+       u8 *len_pos;
+
+       if (!wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
+               wpa_printf(MSG_INFO, "MBO: " MACSTR
+                          " does not support MBO - cannot request MBO ANQP elements from it",
+                          MAC2STR(bss->bssid));
+               return NULL;
+       }
+
+       anqp_buf = wpabuf_alloc(10);
+       if (!anqp_buf)
+               return NULL;
+
+       len_pos = gas_anqp_add_element(anqp_buf, ANQP_VENDOR_SPECIFIC);
+       wpabuf_put_be24(anqp_buf, OUI_WFA);
+       wpabuf_put_u8(anqp_buf, MBO_ANQP_OUI_TYPE);
+
+       wpabuf_put_u8(anqp_buf, MBO_ANQP_SUBTYPE_CELL_CONN_PREF);
+       gas_anqp_set_element_len(anqp_buf, len_pos);
+
+       return anqp_buf;
+}