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)
553 files changed:
1  2 
.gitignore
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/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
libeap/src/ap/mbo_ap.h
libeap/src/ap/ndisc_snoop.c
libeap/src/ap/neighbor_db.c
libeap/src/ap/neighbor_db.h
libeap/src/ap/pmksa_cache_auth.c
libeap/src/ap/pmksa_cache_auth.h
libeap/src/ap/rrm.c
libeap/src/ap/rrm.h
libeap/src/ap/sta_info.c
libeap/src/ap/sta_info.h
libeap/src/ap/taxonomy.c
libeap/src/ap/taxonomy.h
libeap/src/ap/vlan.c
libeap/src/ap/vlan.h
libeap/src/ap/vlan_full.c
libeap/src/ap/vlan_ifconfig.c
libeap/src/ap/vlan_init.c
libeap/src/ap/vlan_init.h
libeap/src/ap/vlan_ioctl.c
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
libeap/src/common/cli.h
libeap/src/common/common_module_tests.c
libeap/src/common/ctrl_iface_common.c
libeap/src/common/ctrl_iface_common.h
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
libeap/src/common/linux_vlan.h
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
libeap/src/crypto/sha384_i.h
libeap/src/crypto/sha512-internal.c
libeap/src/crypto/sha512_i.h
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
libeap/src/crypto/tls_openssl_ocsp.c
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
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
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/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

diff --combined .gitignore
@@@ -1,28 -1,11 +1,29 @@@
 +Makefile.in
 +Makefile
 +aclocal.m4
 +autom4te.cache
 +configure
 +config.*
 +ltmain.sh
 +libtool
 +depcomp
 +m4
 +!m4/minuso.m4
 +build-aux
 +!build-aux/compile
 +mech_eap.spec
 +mech_eap*tar*
 +*.lo
+ *.a
  *.o
  *.d
  *.gcno
  *.gcda
  *.gcov
  *.pyc
 +*#
  *~
 +*.orig
  .config
  tests/hwsim/logs
  wpaspy/build
@@@ -37,6 -20,8 +38,8 @@@ wpa_supplicant/wpa_gui/Makefil
  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
@@@ -46,10 -31,3 +49,10 @@@ wlantest/libwlantest.
  wlantest/test_vectors
  wlantest/wlantest
  wlantest/wlantest_cli
 +libeap/.deps
 +libeap/.libs
 +libeap/Makefile
 +libeap/libeap.la
 +libeap/tests/hwsim/logs/
 +libeap/tests/test-rsa-sig-ver
 +stamp-h1
diff --combined libeap/COPYING
@@@ -1,7 -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.
  
  
diff --combined libeap/README
--- 2/README
@@@ -1,7 -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
diff --combined libeap/build_release
@@@ -30,13 -30,13 +30,13 @@@ mkdir $TM
  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
@@@ -557,7 -557,7 +557,7 @@@ Device Address>" to indicate the entry 
  
  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).
  
  
diff --combined libeap/doc/dbus.doxygen
@@@ -97,6 -97,11 +97,11 @@@ registered in the bus with fi.w1.wpa_su
          <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 +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>
        </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>
        <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 +1637,20 @@@ Interface for performing P2P (Wi-Fi Pee
    </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>
  
diff --combined libeap/doc/doxygen.conf
@@@ -31,7 -31,7 +31,7 @@@ PROJECT_NAME           = "wpa_supplican
  # 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.
diff --combined libeap/doc/p2p.doxygen
@@@ -313,7 -313,7 +313,7 @@@ services. This value is included in al
  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.
  
  
@@@ -46,7 -46,6 +46,6 @@@ endi
  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 +96,8 @@@ OBJS += src/ap/pmksa_cache_auth.
  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 +177,25 @@@ ifdef CONFIG_NO_VLA
  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 +271,11 @@@ ifdef CONFIG_IEEE80211A
  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 +569,7 @@@ endi
  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 +666,8 @@@ CONFIG_INTERNAL_SHA1=
  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 +826,16 @@@ L_CFLAGS += -DCONFIG_SHA38
  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 +877,6 @@@ ifdef CONFIG_DRIVER_RADIUS_AC
  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 +947,10 @@@ ifdef CONFIG_ANDROID_LO
  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 +995,7 @@@ endi
  LOCAL_CFLAGS := $(L_CFLAGS)
  LOCAL_SRC_FILES := $(OBJS)
  LOCAL_C_INCLUDES := $(INCLUDES)
+ LOCAL_INIT_RC := hostapd.android.rc
  include $(BUILD_EXECUTABLE)
  
  endif # ifeq ($(WPA_BUILD_HOSTAPD),true)
diff --combined libeap/hostapd/ChangeLog
@@@ -1,5 -1,78 +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)
diff --combined libeap/hostapd/Makefile
@@@ -6,18 -6,39 +6,39 @@@ ifndef CFLAG
  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 +84,13 @@@ OBJS += ../src/ap/pmksa_cache_auth.
  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 +100,11 @@@ NEED_SHA1=
  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 +146,10 @@@ ifdef CONFIG_ELOOP_EPOL
  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 +200,53 @@@ ifdef CONFIG_NO_VLA
  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 +318,11 @@@ ifdef CONFIG_IEEE80211A
  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 +605,7 @@@ endi
  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 +706,8 @@@ CONFIG_INTERNAL_SHA1=
  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 +868,16 @@@ CFLAGS += -DCONFIG_SHA38
  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 +919,6 @@@ ifdef CONFIG_DRIVER_RADIUS_AC
  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
diff --combined libeap/hostapd/README
@@@ -2,7 -2,7 +2,7 @@@ hostapd - user space IEEE 802.11 AP an
          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
@@@ -25,6 -25,9 +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 +194,8 @@@ CONFIG_AP=
  
  # 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
@@@ -97,6 -97,8 +97,8 @@@ static int hostapd_config_read_vlan_fil
                }
  
                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 +199,10 @@@ static int hostapd_config_read_maclist(
  
                *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 +636,7 @@@ hostapd_parse_radius_attr(const char *v
  }
  
  
- 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;
  
        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 +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 +1919,6 @@@ static int hs20_parse_osu_service_desc(
  #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 +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)
        } 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);
        } 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 */
                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);
                }
        } 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);
                }
        } 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);
                        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) {
  #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'",
                                   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);
                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);
                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 */
        } 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) {
                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) {
        } 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) {                \
        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, ':');
                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;
                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) {
                        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);
        } 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 +3511,7 @@@ struct hostapd_config * hostapd_config_
  {
        struct hostapd_config *conf;
        FILE *f;
-       char buf[512], *pos;
+       char buf[4096], *pos;
        int line = 0;
        int errors = 0;
        size_t i;
  #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 +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,
  
  
  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 +839,8 @@@ static int hostapd_ctrl_iface_bss_tm_re
        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");
        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 +1333,28 @@@ static int hostapd_ctrl_iface_set(struc
        } 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)
                                            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);
                                            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 +1591,8 @@@ static u16 ipv4_hdr_checksum(const voi
  #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 +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 +1802,6 @@@ static int hostapd_ctrl_get_alloc_fail(
                                       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 */
  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 +1836,6 @@@ static int hostapd_ctrl_get_fail(struc
                                 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 +1899,13 @@@ static int hostapd_ctrl_iface_vendor(st
  
        /* 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 +2040,9 @@@ static int hostapd_ctrl_iface_track_sta
        struct hostapd_sta_info *info;
        struct os_reltime now;
  
+       if (!iface->num_sta_seen)
+               return 0;
        sta_track_expire(iface, 0);
  
        pos = buf;
  #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;
        } 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;
                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 +2569,15 @@@ static void hostapd_ctrl_iface_receive(
        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);
                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) {
                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",
  }
  
  
+ #ifndef CONFIG_CTRL_IFACE_UDP
  static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
  {
        char *buf;
        buf[len - 1] = '\0';
        return buf;
  }
+ #endif /* CONFIG_CTRL_IFACE_UDP */
  
  
  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;
                return 0;
        }
  
+       dl_list_init(&hapd->ctrl_dst);
        if (hapd->conf->ctrl_interface == NULL)
                return 0;
  
@@@ -2520,6 -2926,7 +2926,7 @@@ fail
                os_free(fname);
        }
        return -1;
+ #endif /* CONFIG_CTRL_IFACE_UDP */
  }
  
  
@@@ -2528,10 -2935,14 +2935,14 @@@ void hostapd_ctrl_iface_deinit(struct h
        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);
                                           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 +2998,18 @@@ static int hostapd_ctrl_iface_remove(st
  
  
  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 +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 +3256,7 @@@ static int hostapd_global_ctrl_iface_if
                                            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 +3280,18 @@@ static void hostapd_global_ctrl_iface_r
                                              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",
        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, ' ');
  
                        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 */
                        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 +3428,7 @@@ send_reply
  }
  
  
+ #ifndef CONFIG_CTRL_IFACE_UDP
  static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
  {
        char *buf;
        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 +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);
                                           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 +3694,7 @@@ static void hostapd_ctrl_iface_send(str
                                    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];
  
        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);
        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) {
                                dst->errors = 0;
                }
                idx++;
-               dst = next;
        }
  }
  
diff --combined libeap/hostapd/defconfig
@@@ -18,6 -18,9 +18,9 @@@ CONFIG_DRIVER_HOSTAP=
  # 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 +249,9 @@@ CONFIG_IPV6=
  # 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
  # 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
@@@ -9,6 -9,7 +9,7 @@@
  #include "utils/includes.h"
  
  #include "utils/common.h"
+ #include "utils/module_tests.h"
  
  int hapd_module_tests(void)
  {
@@@ -1,6 -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 +284,7 @@@ static int read_gsm_triplets(const cha
  
        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;
        }
  
                }
  
                /* 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 +424,58 @@@ static int read_milenage(const char *fn
                }
  
                /* 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 +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>] "
@@@ -3,6 -3,8 +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 +127,13 @@@ ssid=tes
  # 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 +177,7 @@@ channel=
  # 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 +196,16 @@@ dtim_period=
  # (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 +271,27 @@@ auth_algs=
  #     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 +488,7 @@@ wmm_ac_vo_acm=
  # 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)
  # 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)
  # 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]
  #
  #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 +815,11 @@@ eap_server=
  #     -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
  #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:
  # 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
  # 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
  #
  # DAS require Event-Timestamp
  #radius_das_require_event_timestamp=1
+ #
+ # DAS require Message-Authenticator
+ #radius_das_require_message_authenticator=1
  
  ##### RADIUS authentication server configuration ##############################
  
  
  # 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)
  # 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
  # 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
  #
  # 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 ##################################################
  #
  # - 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"
@@@ -1,6 -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 +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)
                "   -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)
        ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
        free(cfile);
        return ctrl_conn;
+ #endif /* CONFIG_CTRL_IFACE_UDP */
  }
  
  
@@@ -166,6 -137,7 +137,7 @@@ static void hostapd_cli_close_connectio
        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 +187,22 @@@ static inline int wpa_ctrl_command(stru
  }
  
  
+ 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 +318,21 @@@ static int hostapd_cli_cmd_deauthentica
  }
  
  
+ 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[])
  {
  }
  
  
+ 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 +754,30 @@@ static int hostapd_cli_cmd_all_sta(stru
  
  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 +888,28 @@@ static int hostapd_cli_cmd_level(struc
  }
  
  
+ 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 +951,7 @@@ static int hostapd_cli_cmd_interface(st
                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");
  }
  
  
+ 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 +1158,245 @@@ static int hostapd_cli_cmd_log_level(st
  }
  
  
+ 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;
  }
  
  
+ 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)
  {
                        if (action_monitor)
                                hostapd_cli_action_process(buf, len);
                        else {
+                               cli_event(buf);
                                if (in_read && first)
                                        printf("\n");
                                first = 0;
  }
  
  
- #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 +1510,7 @@@ static void hostapd_cli_ping(void *eloo
                        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 +1545,82 @@@ static void hostapd_cli_edit_eof_cb(voi
  }
  
  
+ 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 +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())
        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)
                }
        }
  
-       if (daemonize && os_daemonize(pid_file))
+       if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
                return -1;
  
        if (interactive)
        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 */
diff --combined libeap/hostapd/main.c
@@@ -1,6 -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 +171,8 @@@ static int hostapd_driver_init(struct h
  
                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'",
                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))
   * 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;
        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++) {
  
        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 +346,7 @@@ static int hostapd_global_init(struct h
                wpa_printf(MSG_ERROR, "Failed to initialize event loop");
                return -1;
        }
+       interfaces->eloop_initialized = 1;
  
        random_init(entropy_file);
  
  }
  
  
- static void hostapd_global_deinit(const char *pid_file)
+ static void hostapd_global_deinit(const char *pid_file, int eloop_initialized)
  {
        int i;
  
  
        random_deinit();
  
-       eloop_destroy();
+       if (eloop_initialized)
+               eloop_destroy();
  
  #ifndef CONFIG_NATIVE_WINDOWS
        closelog();
@@@ -408,9 -427,16 +427,16 @@@ static int hostapd_global_run(struct ha
        }
  #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 +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 +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"
                "   -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");
  
  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;
  }
  
  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 "
  
        *pos = '\0';
        interfaces->global_iface_name = pos + 1;
+ #endif /* !CONFIG_CTRL_IFACE_UDP */
  
        return 0;
  }
@@@ -513,6 -547,43 +547,43 @@@ static int hostapd_get_ctrl_iface_group
  }
  
  
+ 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 +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;
        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) {
                        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;
  
        /* 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 */
        }
        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)
  
        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();
@@@ -4,7 -4,6 +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 +54,7 @@@ OBJS += ../../src/crypto/crypto_interna
  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
  
@@@ -76,6 -76,7 +76,7 @@@ LIBS += -lcur
  endif
  
  CFLAGS += -DEAP_TLS_OPENSSL
+ OBJS += ../../src/crypto/tls_openssl_ocsp.o
  LIBS += -lssl -lcrypto
  
  hs20-osu-client: $(OBJS)
diff --combined libeap/hs20/client/est.c
@@@ -16,6 -16,9 +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 +71,7 @@@
                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");
        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 +335,23 @@@ static void add_csrattrs(struct hs20_os
        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);
                        break;
                }
        }
+ #endif /* OPENSSL_IS_BORINGSSL */
  }
  
  
@@@ -340,6 -383,7 +383,7 @@@ static int generate_csr(struct hs20_osu
        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");
        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;
                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) {
                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;
@@@ -2229,7 -2229,7 +2229,7 @@@ static int cmd_osu_select(struct hs20_o
                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 +2339,23 @@@ static int cmd_signup(struct hs20_osu_c
                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 +2570,7 @@@ static int cmd_pol_upd(struct hs20_osu_
        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 +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) {
@@@ -96,7 -96,8 +96,8 @@@ els
    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");
  
@@@ -61,7 -61,7 +61,7 @@@ static void start_example(void *eloop_c
                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)) {
@@@ -1,6 -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 +41,7 @@@ static struct radius_msg * accounting_m
        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));
                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);
  
                        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 +171,25 @@@ static int accounting_sta_update_stats(
        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 +230,14 @@@ void accounting_sta_start(struct hostap
  
        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 +266,7 @@@ static void accounting_sta_report(struc
        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;
        }
  
        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)) {
                        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 +382,17 @@@ void accounting_sta_stop(struct hostapd
                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 +439,14 @@@ static void accounting_report_state(str
        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)
  }
  
  
+ 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
   */
  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);
  
  #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 +35,7 @@@ static inline void accounting_deinit(st
  {
  }
  #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);
diff --combined libeap/src/ap/acs.c
@@@ -599,8 -599,7 +599,7 @@@ acs_find_ideal_chan(struct hostapd_ifac
        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 +932,9 @@@ enum hostapd_chan_status acs_init(struc
                return HOSTAPD_CHAN_ACS;
        }
  
+       if (!iface->current_mode)
+               return HOSTAPD_CHAN_INVALID;
        acs_cleanup(iface);
  
        err = acs_request_scan(iface);
@@@ -38,6 -38,8 +38,8 @@@ static void hostapd_config_free_vlan(st
  
  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 +65,7 @@@
        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 +183,7 @@@ struct hostapd_config * hostapd_config_
        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 +202,6 @@@ int hostapd_mac_comp(const void *a, con
  }
  
  
- 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 +407,19 @@@ void hostapd_config_clear_wpa_psk(struc
  }
  
  
+ 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;
        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);
        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);
  #endif /* CONFIG_HS20 */
  
        wpabuf_free(conf->vendor_elements);
+       wpabuf_free(conf->assocresp_elements);
  
        os_free(conf->sae_groups);
  
@@@ -594,6 -607,8 +607,8 @@@ void hostapd_config_free(struct hostapd
  #ifdef CONFIG_ACS
        os_free(conf->acs_chan_bias);
  #endif /* CONFIG_ACS */
+       wpabuf_free(conf->lci);
+       wpabuf_free(conf->civic);
  
        os_free(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 +665,26 @@@ int hostapd_rate_found(int *list, int r
  }
  
  
- 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 +786,7 @@@ static int hostapd_config_check_bss(str
                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++) {
        }
  #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 "
        }
  #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;
  }
  
  #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 +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 +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 +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 */
  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;
  };
  
  #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 +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 +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;
        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;
        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;
  
        int ap_max_inactivity;
        int ignore_broadcast_ssid;
+       int no_probe_resp_if_max_sta;
  
        int wmm_enabled;
        int wmm_uapsd;
        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;
  #endif /* CONFIG_RADIUS_TEST */
  
        struct wpabuf *vendor_elements;
+       struct wpabuf *assocresp_elements;
  
        unsigned int sae_anti_clogging_threshold;
        int *sae_groups;
  #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 +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 */
        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
        } *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 +718,14 @@@ void hostapd_config_clear_wpa_psk(struc
  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 *
@@@ -33,10 -33,36 +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,
  
        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
  #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 */
        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 +363,8 @@@ int hostapd_sta_add(struct hostapd_dat
                    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;
  
        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 +444,7 @@@ int hostapd_if_add(struct hostapd_data 
                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 +623,28 @@@ int hostapd_drv_set_key(const char *ifn
  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);
  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 +675,36 @@@ int hostapd_drv_send_action(struct host
                            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 +754,7 @@@ int hostapd_start_dfs_cac(struct hostap
  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 +780,20 @@@ static void hostapd_get_hw_mode_any_cha
  }
  
  
+ 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;
@@@ -41,7 -41,8 +41,8 @@@ int hostapd_sta_add(struct hostapd_dat
                    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 +89,9 @@@ int hostapd_drv_set_key(const char *ifn
                        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,
  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 +128,8 @@@ int hostapd_drv_wnm_oper(struct hostapd
  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 +160,7 @@@ static inline int hostapd_drv_get_inact
  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 +283,7 @@@ static inline int hostapd_drv_switch_ch
  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 +342,7 @@@ static inline int hostapd_drv_vendor_cm
  
  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);
  }
diff --combined libeap/src/ap/ap_mlme.c
@@@ -59,6 -59,7 +59,7 @@@ void mlme_authenticate_indication(struc
                       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 +107,7 @@@ void mlme_associate_indication(struct h
                       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 +132,7 @@@ void mlme_reassociate_indication(struc
                       MAC2STR(sta->addr));
        if (sta->auth_alg != WLAN_AUTH_FT)
                mlme_deletekeys_request(hapd, sta);
+       ap_sta_clear_disconnect_timeouts(hapd, sta);
  }
  
  
diff --combined libeap/src/ap/authsrv.c
@@@ -173,6 -173,8 +173,8 @@@ int authsrv_init(struct hostapd_data *h
                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");
        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 "
diff --combined libeap/src/ap/beacon.c
@@@ -29,6 -29,7 +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 +301,65 @@@ static u8 * hostapd_eid_wpa(struct host
  
  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)
-               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
+       if (!hapd->cs_freq_params.channel || !hapd->iface->cs_oper_class)
                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 +368,7 @@@ static u8 * hostapd_gen_probe_resp(stru
                                   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
                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;
        /* 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);
  
  
        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 */
        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),
  
  #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);
        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 +563,8 @@@ static enum ssid_match_result ssid_matc
  
        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 +600,7 @@@ void sta_track_expire(struct hostapd_if
                           MAC2STR(info->addr));
                dl_list_del(&info->list);
                iface->num_sta_seen--;
-               os_free(info);
+               sta_track_del(info);
        }
  }
  
@@@ -607,6 -633,8 +633,8 @@@ void sta_track_add(struct hostapd_ifac
  
        /* 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 +676,23 @@@ sta_track_seen_on(struct hostapd_iface 
  }
  
  
+ #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)
        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,
        }
  
  #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)) {
                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)) {
        }
  #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) {
                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) {
        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 +985,16 @@@ static u8 * hostapd_probe_resp_offloads
  #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)
  {
        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
        }
  #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");
        /* 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);
  
        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 */
        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) {
  
  #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);
        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));
                params->osen = 1;
        }
  #endif /* CONFIG_HS20 */
+       params->pbss = hapd->conf->pbss;
        return 0;
  }
  
diff --combined libeap/src/ap/beacon.h
@@@ -22,9 -22,12 +22,12 @@@ int ieee802_11_build_ap_params(struct h
                               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 */
@@@ -22,6 -22,8 +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 +37,9 @@@
                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 +163,19 @@@ static int hostapd_ctrl_iface_sta_mib(s
                        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 +259,7 @@@ static int p2p_manager_disconnect(struc
        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);
        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 +326,7 @@@ int hostapd_ctrl_iface_deauthenticate(s
        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);
        }
  #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 +389,7 @@@ int hostapd_ctrl_iface_disassociate(str
        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);
        }
  #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);
  }
  
  
+ #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)
  {
                          "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 +626,16 @@@ int hostapd_ctrl_iface_stop_ap(struct h
  {
        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);
+ }
@@@ -19,10 -19,18 +19,18 @@@ int hostapd_ctrl_iface_deauthenticate(s
                                      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 */
diff --combined libeap/src/ap/dfs.c
@@@ -450,7 -450,7 +450,7 @@@ dfs_get_valid_channel(struct hostapd_if
                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 +704,8 @@@ int hostapd_handle_dfs(struct hostapd_i
                                                        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 +794,6 @@@ static int hostapd_dfs_start_channel_sw
  
        if (!channel) {
                wpa_printf(MSG_ERROR, "No valid channel available");
-               hostapd_setup_interface_complete(iface, err);
                return err;
        }
  
  }
  
  
- 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;
                                                &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 +983,11 @@@ int hostapd_dfs_nop_finished(struct hos
        /* 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;
  }
  
@@@ -121,7 -121,8 +121,8 @@@ static void handle_dhcp(void *ctx, cons
  
                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)
@@@ -22,6 -22,7 +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 +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,
        }
        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);
                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
                        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 +480,8 @@@ void hostapd_event_ch_switch(struct hos
                             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,
                        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 +573,11 @@@ void hostapd_event_connect_failed_reaso
  
  
  #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",
                        hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
                                       HOSTAPD_LEVEL_WARNING,
                                       "driver selected to bad hw_mode");
-                       return;
+                       err = 1;
+                       goto out;
                }
        }
  
                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;
                hapd->iconf->secondary_channel = 1;
        else {
                wpa_printf(MSG_ERROR, "Invalid secondary channel!");
-               return;
+               err = 1;
+               goto out;
        }
  
        if (hapd->iface->conf->ieee80211ac) {
                }
        }
  
-       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 +923,24 @@@ static void hostapd_mgmt_tx_cb(struct h
                               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 +987,8 @@@ static void hostapd_event_eapol_rx(stru
        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)
  
        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 +1061,9 @@@ static void hostapd_single_channel_get_
  }
  
  
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;
  
  }
  
  
+ #ifdef HOSTAPD
  #ifdef NEED_AP_MLME
  
  static void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
@@@ -1251,7 -1303,7 +1303,7 @@@ void wpa_supplicant_event(void *ctx, en
                        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:
        }
  }
  
+ 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 */
diff --combined libeap/src/ap/gas_serv.c
@@@ -101,6 -101,7 +101,7 @@@ gas_serv_dialog_find(struct hostapd_dat
                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 +168,107 @@@ static void anqp_add_hs_capab_list(stru
  #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 */
  
  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;
  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 +320,9 @@@ static void anqp_add_roaming_consortium
        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;
  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 +402,7 @@@ static int hs20_add_nai_home_realm_matc
  
        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;
        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);
                }
                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 +484,10 @@@ static void anqp_add_nai_realm(struct h
                               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;
  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,
  
  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 +786,42 @@@ static void anqp_add_icon_binary_file(s
  #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)
                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)
                                   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)
  }
  
  
+ #define ANQP_MAX_EXTRA_REQ 20
  struct anqp_query_info {
        unsigned int request;
        const u8 *home_realm_query;
        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 +922,11 @@@ static void rx_anqp_query_list_id(struc
                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);
                             "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 +1010,7 @@@ static void rx_anqp_query_list(struct h
        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 +1099,7 @@@ static void rx_anqp_vendor_specific(str
        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;
        }
        pos++;
  
-       if (pos + 1 >= end)
+       if (end - pos <= 1)
                return;
  
        subtype = *pos++;
  
  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)
                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;
        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) {
                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;
  
        while (pos < end) {
                u16 info_id, elen;
  
-               if (pos + 4 > end)
+               if (end - pos < 4)
                        return;
  
                info_id = WPA_GET_LE16(pos);
                elen = WPA_GET_LE16(pos);
                pos += 2;
  
-               if (pos + elen > end) {
+               if (elen > end - pos) {
                        wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
                        return;
                }
                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;
  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 +1455,7 @@@ static void gas_serv_rx_public_action(v
        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)
         */
        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;
        }
  }
diff --combined libeap/src/ap/gas_serv.h
@@@ -9,10 -9,13 +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 \
diff --combined libeap/src/ap/hostapd.c
@@@ -12,6 -12,7 +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 +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 +206,12 @@@ int hostapd_reload_config(struct hostap
  
  
  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 +339,8 @@@ static void hostapd_free_hapd_data(stru
        wpabuf_free(hapd->mesh_pending_auth);
        hapd->mesh_pending_auth = NULL;
  #endif /* CONFIG_MESH */
+       hostapd_clean_rrm(hapd);
  }
  
  
@@@ -367,7 -374,7 +374,7 @@@ static void sta_track_deinit(struct hos
                                     list))) {
                dl_list_del(&info->list);
                iface->num_sta_seen--;
-               os_free(info);
+               sta_track_del(info);
        }
  }
  
@@@ -511,6 -518,9 +518,9 @@@ static int hostapd_validate_bssid_confi
        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. */
        /* 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 +682,7 @@@ static struct sta_info * hostapd_das_fi
  
        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;
                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++;
  
        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;
                        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 +914,9 @@@ static int hostapd_setup_bss(struct hos
        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);
  
                                           "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)) {
                        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;
                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 +1532,128 @@@ void fst_hostapd_fill_iface_obj(struct 
  #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;
                        } 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];
        hostapd_tx_queue_params(iface);
  
        ap_list_init(iface);
-       dl_list_init(&iface->sta_seen);
  
        hostapd_set_acl(hapd);
  
@@@ -1701,6 -1836,9 +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:
  
  
  /**
+  * 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 +1999,8 @@@ hostapd_alloc_bss_data(struct hostapd_i
        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;
  }
  
  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 +2044,11 @@@ void hostapd_interface_deinit(struct ho
        }
  #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 +2057,8 @@@ void hostapd_interface_free(struct host
        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]);
  }
  
  
+ 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 +2098,7 @@@ struct hostapd_iface * hostapd_init(str
        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 +2434,7 @@@ hostapd_iface_alloc(struct hapd_interfa
                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 +2801,7 @@@ void hostapd_new_assoc_sta(struct hosta
        }
  
        hostapd_prune_associations(hapd, sta->addr);
+       ap_sta_clear_disconnect_timeouts(hapd, sta);
  
        /* IEEE 802.11F (IAPP) */
        if (hapd->conf->ieee802_11f)
                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 +2873,23 @@@ const char * hostapd_state_text(enum ho
  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 +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,
                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 +3073,43 @@@ static int hostapd_fill_csa_settings(st
        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);
                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 +3153,8 @@@ void hostapd_cleanup_cs_params(struct h
        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 +3242,8 @@@ hostapd_switch_channel_fallback(struct 
        hostapd_enable_iface(iface);
  }
  
+ #endif /* NEED_AP_MLME */
  
  struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
                                        const char *ifname)
        return NULL;
  }
  
- #endif /* NEED_AP_MLME */
  
  void hostapd_periodic_iface(struct hostapd_iface *iface)
  {
diff --combined libeap/src/ap/hostapd.h
@@@ -41,7 -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 +53,7 @@@
  #ifndef CONFIG_NO_VLAN
        struct dynamic_iface *vlan_priv;
  #endif /* CONFIG_NO_VLAN */
+       int eloop_initialized;
  };
  
  enum hostapd_chan_status {
@@@ -99,6 -100,16 +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 +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;
        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;
        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;
  #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
  
        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 +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 +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];
        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 +474,7 @@@ int hostapd_setup_interface(struct host
  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 +491,7 @@@ int hostapd_remove_iface(struct hapd_in
  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 +521,11 @@@ int hostapd_probe_req_rx(struct hostapd
                         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,
@@@ -329,6 -329,7 +329,7 @@@ static void ieee80211n_check_scan(struc
        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 +473,9 @@@ static int ieee80211n_check_40mhz(struc
        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 "
diff --combined libeap/src/ap/iapp.c
  #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 +381,7 @@@ struct iapp_data * iapp_init(struct hos
        struct sockaddr_in *paddr, uaddr;
        struct iapp_data *iapp;
        struct ip_mreqn mreq;
+       int reuseaddr = 1;
  
        iapp = os_zalloc(sizeof(*iapp));
        if (iapp == NULL)
        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",
@@@ -42,6 -42,9 +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 +142,7 @@@ u16 hostapd_own_capab_info(struct hosta
        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);
            (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 +215,17 @@@ static u16 auth_shared_key(struct hosta
                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);
                }
  #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,
                   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 +310,25 @@@ static void handle_auth_ft_finish(void 
  {
        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 +391,19 @@@ static int auth_sae_send_commit(struct 
                                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 +412,19 @@@ static int auth_sae_send_confirm(struc
                                 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 +519,9 @@@ static void auth_sae_retransmit_timer(v
        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 +564,18 @@@ static void sae_set_retransmit_timer(st
  }
  
  
+ 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)
  {
                                 * 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.
                                 */
                        }
  
                        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:
                                   ") 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;
  }
  
  
+ 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;
                        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;
                        }
  
                        /*
                         * 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;
                        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 -
                        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)
                               "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,
                               "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 +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 +986,11 @@@ static void handle_auth(struct hostapd_
        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;
        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);
                                       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
        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) {
        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,
        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;
  
                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 +1496,9 @@@ static u16 check_ext_capab(struct hosta
        }
  #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 +1789,27 @@@ static u16 check_assoc_ies(struct hosta
                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 +1836,66 @@@ static void send_deauth(struct hostapd_
  }
  
  
- 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];
  
  #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 */
  #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) {
                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 +2056,7 @@@ static void handle_assoc(struct hostapd
                         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;
                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) {
                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);
                goto fail;
        }
  
-       sta->capability = capab_info;
        sta->listen_interval = listen_interval;
  
        if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
         * 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 +2341,12 @@@ static void handle_disassoc(struct host
        /* 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 +2568,9 @@@ static int handle_action(struct hostapd
                                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,
                       "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 +2627,6 @@@ int ieee802_11_mgmt(struct hostapd_dat
                    struct hostapd_frame_info *fi)
  {
        struct ieee80211_mgmt *mgmt;
-       int broadcast;
        u16 fc, stype;
        int ret = 0;
  
                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 +2722,28 @@@ static void handle_auth_cb(struct hosta
        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 &&
                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 +2796,6 @@@ static void handle_assoc_cb(struct host
        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) {
                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;
        }
  
        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;
  
        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];
        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 +2923,7 @@@ static void handle_deauth_cb(struct hos
                             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 +2947,7 @@@ static void handle_disassoc_cb(struct h
                               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 +3003,7 @@@ void ieee802_11_mgmt_cb(struct hostapd_
                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");
                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 +3112,8 @@@ void hostapd_client_poll_ok(struct host
        }
        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 +3152,7 @@@ void ieee802_11_rx_from_unknown(struct 
  
        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;
        }
@@@ -49,9 -49,13 +49,13 @@@ u8 * hostapd_eid_supp_rates(struct host
  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 +65,7 @@@ void hostapd_get_ht_capab(struct hostap
  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 +102,7 @@@ int auth_sae_init_committed(struct host
  #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)
  }
  #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 */
@@@ -15,7 -15,6 +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 +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 +76,20 @@@ static void hostapd_acl_cache_free(stru
  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 +155,10 @@@ static int hostapd_radius_acl_query(str
        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,
  
  
  /**
+  * 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
   */
  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)
        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
                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 +432,7 @@@ static void decode_tunnel_passwords(str
                                    struct hostapd_cached_radius_acl *cache)
  {
        int passphraselen;
-       char *passphrase, *strpassphrase;
+       char *passphrase;
        size_t i;
        struct hostapd_sta_wpa_psk_short *psk;
  
                 */
                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 +509,7 @@@ hostapd_acl_recv_radius(struct radius_m
        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;
                        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);
                    !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 +678,12 @@@ void hostapd_acl_deinit(struct hostapd_
  
  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;
@@@ -16,9 -16,12 +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);
@@@ -108,6 -108,29 +108,29 @@@ u8 * hostapd_eid_ht_operation(struct ho
  }
  
  
+ 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
@@@ -172,6 -172,8 +172,8 @@@ static void hostapd_ext_capab_byte(stru
        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)
                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 +243,9 @@@ u8 * hostapd_eid_ext_capab(struct hosta
                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;
        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 +525,62 @@@ u8 * hostapd_eid_bss_max_idle_period(st
  
        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);
+ }
  #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;
        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 +93,26 @@@ u8 * hostapd_eid_vht_operation(struct h
                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 +164,171 @@@ static int check_valid_vht_mcs(struct h
  }
  
  
+ 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 +410,7 @@@ u8 * hostapd_eid_vendor_vht(struct host
        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;
@@@ -34,6 -34,9 +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 +222,7 @@@ static void ieee802_1x_tx_key(struct ho
                   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 +405,16 @@@ static int add_common_radius_sta_attr(s
        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;
                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");
                }
        }
  
+       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 +502,7 @@@ int add_common_radius_attr(struct hosta
  {
        char buf[128];
        struct hostapd_radius_attr *attr;
+       int len;
  
        if (!hostapd_config_get_radius_attr(req_attr,
                                            RADIUS_ATTR_NAS_IP_ADDRESS) &&
                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 +611,10 @@@ static void ieee802_1x_encapsulate_radi
                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 +862,29 @@@ ieee802_1x_alloc_eapol_sm(struct hostap
  }
  
  
+ 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 +915,13 @@@ void ieee802_1x_receive(struct hostapd_
                     !(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 +1108,7 @@@ void ieee802_1x_new_station(struct host
                 * 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;
        }
  
                 * 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;
        }
  
                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 */
                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) {
  }
  
  
- 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;
  
  #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 +1662,16 @@@ ieee802_1x_receive_auth(struct radius_m
        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) {
  
        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,
                }
  #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;
                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 +2273,7 @@@ void ieee802_1x_deinit(struct hostapd_d
  {
        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 +2578,12 @@@ int ieee802_1x_get_mib_sta(struct hosta
                          /* 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,
                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;
  }
  
  
+ #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)
                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 */
  
                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,
@@@ -21,7 -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 --combined libeap/src/ap/mbo_ap.c
index 0000000,43b0bf1..43b0bf1
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,244 +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 --combined libeap/src/ap/mbo_ap.h
index 0000000,9f37f28..9f37f28
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,51 +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 */
@@@ -17,6 -17,7 +17,7 @@@
  #include "ap_drv_ops.h"
  #include "list.h"
  #include "x_snoop.h"
+ #include "ndisc_snoop.h"
  
  struct ip6addr {
        struct in6_addr addr;
index 0000000,a2efff6..a2efff6
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,133 +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);
+       }
+ }
index 0000000,c22e043..c22e043
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,24 +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 */
@@@ -38,6 -38,7 +38,7 @@@ static void pmksa_cache_set_expiration(
  
  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 +92,20 @@@ void pmksa_cache_free_entry(struct rsn_
  }
  
  
+ /**
+  * 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 +141,8 @@@ static void pmksa_cache_set_expiration(
  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;
  
  #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)
        }
  
        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 +260,7 @@@ static void pmksa_cache_link_entry(stru
   * @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
   */
  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)
        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)
                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 +366,13 @@@ pmksa_cache_add_okc(struct rsn_pmksa_ca
        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 +506,11 @@@ static int das_attr_match(struct rsn_pm
        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 +560,48 @@@ int pmksa_cache_auth_radius_das_disconn
  
        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;
+ }
@@@ -17,7 -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_* */
        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 +48,7 @@@ struct rsn_pmksa_cache_entry * pmksa_ca
        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 +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 --combined libeap/src/ap/rrm.c
index 0000000,3569f95..3569f95
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,544 +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 --combined libeap/src/ap/rrm.h
index 0000000,f07fd41..f07fd41
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,28 +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 */
diff --combined libeap/src/ap/sta_info.c
  #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 +171,10 @@@ void ap_free_sta(struct hostapd_data *h
        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);
                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 */
  
  #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)
        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
                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
        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 +376,8 @@@ void ap_handle_timer(void *eloop_ctx, v
        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 +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 +541,8 @@@ static void ap_handle_session_timer(voi
        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 +601,8 @@@ static void ap_handle_session_warning_t
        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 +643,10 @@@ struct sta_info * ap_sta_add(struct hos
                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 "
        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 +684,16 @@@ static int ap_sta_remove(struct hostapd
                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 +717,10 @@@ static void ap_sta_remove_in_other_bss(
                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 +732,8 @@@ static void ap_sta_disassoc_cb_timeout(
        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 +757,7 @@@ void ap_sta_disassociate(struct hostapd
        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 +773,8 @@@ static void ap_sta_deauth_cb_timeout(vo
        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 +798,7 @@@ void ap_sta_deauthenticate(struct hosta
        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 +826,128 @@@ int ap_sta_wps_cancel(struct hostapd_da
  #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
        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;
        }
                               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 +1056,10 @@@ static void ap_sa_query_timer(void *elo
        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 +1198,14 @@@ void ap_sta_set_authorized(struct hosta
  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);
        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 +1262,22 @@@ void ap_sta_disassoc_cb(struct hostapd_
  }
  
  
+ 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;
diff --combined libeap/src/ap/sta_info.h
  #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 */
        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 */
  
        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;
  
        /* 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 */
  
        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;
  
  #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 */
        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 */
  };
  
  
   * 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 +268,8 @@@ int ap_sta_wps_cancel(struct hostapd_da
                      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 +285,8 @@@ static inline int ap_sta_is_authorized(
  
  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 --combined libeap/src/ap/taxonomy.c
index 0000000,cea8b72..cea8b72
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,291 +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 --combined libeap/src/ap/taxonomy.h
index 0000000,80f245c..80f245c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,24 +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 --combined libeap/src/ap/vlan.c
index 0000000,b6f6bb1..b6f6bb1
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,34 +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 --combined libeap/src/ap/vlan.h
index 0000000,af84929..af84929
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,30 +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 */
index 0000000,aa42335..aa42335
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,752 +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);
+ }
index 0000000,ef953a5..ef953a5
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,69 +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);
+ }
   */
  
  #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 +83,14 @@@ static int vlan_dynamic_add(struct host
  {
        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 +109,17 @@@ static void vlan_dynamic_remove(struct 
        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 +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 +172,45 @@@ void vlan_deinit(struct hostapd_data *h
  
  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 +219,7 @@@ int vlan_remove_dynamic(struct hostapd_
  {
        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)",
                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 */
@@@ -15,10 -15,9 +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 +28,9 @@@ static inline void vlan_deinit(struct h
  {
  }
  
- 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 +39,6 @@@ static inline int vlan_remove_dynamic(s
  {
        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 */
index 0000000,987b612..987b612
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,155 +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;
+ }
@@@ -7,18 -7,10 +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 +25,6 @@@ int vlan_add(const char *if_name, int v
  {
        int err, ret = -1;
        struct nl_sock *handle = NULL;
-       struct nl_cache *cache = NULL;
        struct rtnl_link *rlink = NULL;
        int if_idx = 0;
  
                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;
  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 +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);
                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);
  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;
+ }
@@@ -1,5 -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 +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 */
diff --combined libeap/src/ap/wnm_ap.c
@@@ -17,6 -17,7 +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 +95,7 @@@ static int ieee802_11_send_wnmsleep_res
        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 +378,29 @@@ static void ieee802_11_rx_bss_trans_mgm
  }
  
  
+ 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)
  {
        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 +556,8 @@@ int wnm_send_ess_disassoc_imminent(stru
  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;
        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;
                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");
diff --combined libeap/src/ap/wnm_ap.h
@@@ -21,6 -21,7 +21,7 @@@ int wnm_send_ess_disassoc_imminent(stru
  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 */
diff --combined libeap/src/ap/wpa_auth.c
@@@ -44,7 -44,8 +44,8 @@@ static int wpa_gtk_update(struct wpa_au
  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 +828,7 @@@ static int wpa_try_alt_snonce(struct wp
        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)) {
                                               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 +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 +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 +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));
                }
  
  
  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 +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;
                        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,
                 * 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 +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) {
                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 +3284,21 @@@ const u8 * wpa_auth_get_wpa_ie(struct w
  
  
  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 +3316,7 @@@ int wpa_auth_pmksa_add_preauth(struct w
        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,
  
  
  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 +3359,46 @@@ void wpa_auth_pmksa_remove(struct wpa_a
  }
  
  
+ 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 +3477,98 @@@ wpa_auth_add_group(struct wpa_authentic
  }
  
  
+ /*
+  * 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;
diff --combined libeap/src/ap/wpa_auth.h
@@@ -42,10 -42,11 +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 */
        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 */
        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 */
        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 +288,25 @@@ void wpa_auth_sta_local_mic_failure_rep
  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 +344,7 @@@ int wpa_auth_radius_das_disconnect_pmks
                                         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 */
@@@ -720,11 -720,6 +720,6 @@@ u8 * wpa_sm_write_assoc_resp_ies(struc
        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 */
                       _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;
  }
  
@@@ -12,6 -12,7 +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 +247,13 @@@ static const u8 * hostapd_wpa_auth_get_
                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 +421,8 @@@ static int hostapd_wpa_auth_ft_iter(str
                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 +573,9 @@@ static void hostapd_rrb_receive(void *c
        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 +650,7 @@@ int hostapd_setup_wpa(struct hostapd_da
        }
  
  #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 +687,14 @@@ void hostapd_deinit_wpa(struct hostapd_
                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);
@@@ -60,7 -60,8 +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 +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;
  };
  
  
@@@ -251,7 -251,7 +251,7 @@@ int wpa_write_rsn_ie(struct wpa_auth_co
        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);
  #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 +712,14 @@@ int wpa_validate_wpa_ie(struct 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 +794,7 @@@ static int wpa_parse_generic(const u8 *
                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 +890,13 @@@ int wpa_parse_kde_ies(const u8 *buf, si
        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));
@@@ -1,6 -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 +269,6 @@@ static void hostapd_wps_enrollee_seen_c
  }
  
  
- 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 +439,8 @@@ static int hapd_wps_cred_cb(struct host
        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 +868,8 @@@ static void hostapd_wps_clear_ies(struc
        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 +1064,14 @@@ int hostapd_init_wps(struct hostapd_dat
                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) {
                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) {
                /* 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 +1621,8 @@@ const char * hostapd_wps_ap_pin_random(
        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 --combined libeap/src/common/cli.c
index 0000000,b583d1c..b583d1c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,267 +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 --combined libeap/src/common/cli.h
index 0000000,41ef329..41ef329
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,47 +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 */
@@@ -9,6 -9,7 +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"
index 0000000,ebbe6ff..ebbe6ff
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,173 +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;
+ }
index 0000000,0b6e3e7..0b6e3e7
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,38 +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 */
diff --combined libeap/src/common/defs.h
@@@ -312,6 -312,7 +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
  };
  
  #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 {
        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 */
@@@ -25,7 -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
@@@ -115,6 -115,11 +115,11 @@@ static int ieee802_11_parse_vendor_spec
                        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 +371,14 @@@ ParseRes ieee802_11_parse_elems(const u
                        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 +411,8 @@@ int ieee802_11_ie_count(const u8 *ies, 
        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 +432,8 @@@ struct wpabuf * ieee802_11_vendor_ie_co
        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) {
         * 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 +583,8 @@@ enum hostapd_hw_mode ieee80211_freq_to_
  {
        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);
  }
  
  
   * 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 +602,8 @@@ enum hostapd_hw_mode ieee80211_freq_to_
                                                   int sec_channel, int vht,
                                                   u8 *op_class, u8 *channel)
  {
+       u8 vht_opclass;
        /* TODO: more operating classes */
  
        if (sec_channel > 1 || sec_channel < -1)
                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;
  
                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 +1185,135 @@@ struct wpabuf * mb_ies_by_info(struct m
  
        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;
+ }
@@@ -9,6 -9,8 +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 +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;
        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 +127,7 @@@ enum hostapd_hw_mode ieee80211_freq_to_
                                                   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,
  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 */
  #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 +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 +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 +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;
                                        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 +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
  #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 +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 +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 +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 +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 +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 +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 */
@@@ -10,7 -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 {
index 0000000,7b76846..7b76846
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,24 +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 */
index 0000000,8a1dd6e..8a1dd6e
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,52 +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 */
@@@ -89,6 -89,102 +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,
        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,
        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 +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 +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 +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 +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 */
  
  /**
   *
   *    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 */
diff --combined libeap/src/common/sae.c
@@@ -1,6 -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 +275,9 @@@ static int sae_test_pwd_seed_ecc(struc
  
        /* 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 +319,10 @@@ static int sae_test_pwd_seed_ffc(struc
        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 +811,13 @@@ static int sae_derive_keys(struct sae_d
        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 +925,7 @@@ static void sae_parse_commit_token(stru
                                   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 +948,7 @@@ static u16 sae_parse_commit_scalar(stru
  {
        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 +996,7 @@@ static u16 sae_parse_commit_element_ecc
  {
        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 +1042,7 @@@ static u16 sae_parse_commit_element_ffc
        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 +1100,7 @@@ u16 sae_parse_commit(struct sae_data *s
        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)
diff --combined libeap/src/common/sae.h
@@@ -45,6 -45,7 +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;
@@@ -5,6 -5,10 +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 */
@@@ -292,38 -292,47 +292,47 @@@ static int wpa_ft_parse_ftie(const u8 *
        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 +354,18 @@@ int wpa_ft_parse_ies(const u8 *ies, siz
  
        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);
                                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)
        }
  
        /* 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 +600,10 @@@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_
        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;
        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 +1184,8 @@@ const char * wpa_key_mgmt_txt(int key_m
                        "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 +1284,13 @@@ int wpa_compare_rsn_ie(int ft_initial_a
  
  
  #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)
                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;
        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 */
  
@@@ -12,6 -12,8 +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 +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;
@@@ -532,6 -532,8 +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)) {
@@@ -76,6 -76,21 +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 "
  #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 "
  /* 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 "
  
  #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 "
  
  #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 +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
  };
  
@@@ -172,7 -172,8 +172,8 @@@ int get_wpa_status(const char *ifname, 
        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;
        }
@@@ -47,7 -47,9 +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
@@@ -28,6 -28,9 +28,9 @@@ int aes_128_cbc_encrypt(const u8 *key, 
        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 +64,9 @@@ int aes_128_cbc_decrypt(const u8 *key, 
        u8 *pos = data;
        int i, j, blocks;
  
+       if (TEST_FAIL())
+               return -1;
        ctx = aes_decrypt_init(key, 16);
        if (ctx == NULL)
                return -1;
@@@ -48,6 -48,9 +48,9 @@@ int omac1_aes_vector(const u8 *key, siz
        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,0000000..0dc073d
mode 100644,000000..100644
--- /dev/null
@@@ -1,819 -1,0 +1,842 @@@
-       CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256
 +/*
 + * Wrapper functions for crypto libraries
 + * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
 + *
 + * This software may be distributed under the terms of the BSD license.
 + * See README for more details.
 + *
 + * This file defines the cryptographic functions that need to be implemented
 + * for wpa_supplicant and hostapd. When TLS is not used, internal
 + * implementation of MD5, SHA1, and AES is used and no external libraries are
 + * required. When TLS is enabled (e.g., by enabling EAP-TLS or EAP-PEAP), the
 + * crypto library used by the TLS implementation is expected to be used for
 + * non-TLS needs, too, in order to save space by not implementing these
 + * functions twice.
 + *
 + * Wrapper code for using each crypto library is in its own file (crypto*.c)
 + * and one of these files is build and linked in to provide the functions
 + * defined here.
 + */
 +
 +#ifndef CRYPTO_H
 +#define CRYPTO_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +
 +/**
 + * md4_vector - MD4 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 md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
 +
 +/**
 + * md5_vector - MD5 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 md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
 +
 +
 +/**
 + * sha1_vector - SHA-1 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 sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
 +              u8 *mac);
 +
 +/**
 + * fips186_2-prf - NIST FIPS Publication 186-2 change notice 1 PRF
 + * @seed: Seed/key for the PRF
 + * @seed_len: Seed length in bytes
 + * @x: Buffer for PRF output
 + * @xlen: Output length in bytes
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function implements random number generation specified in NIST FIPS
 + * Publication 186-2 for EAP-SIM. This PRF uses a function that is similar to
 + * SHA-1, but has different message padding.
 + */
 +int __must_check fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x,
 +                             size_t xlen);
 +
 +/**
 + * sha256_vector - SHA256 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 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)
 + * @cypher: 8 octets (out)
 + */
 +void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher);
 +
 +/**
 + * aes_encrypt_init - Initialize AES for encryption
 + * @key: Encryption key
 + * @len: Key length in bytes (usually 16, i.e., 128 bits)
 + * Returns: Pointer to context data or %NULL on failure
 + */
 +void * aes_encrypt_init(const u8 *key, size_t len);
 +
 +/**
 + * aes_encrypt - Encrypt one AES block
 + * @ctx: Context pointer from aes_encrypt_init()
 + * @plain: Plaintext data to be encrypted (16 bytes)
 + * @crypt: Buffer for the encrypted data (16 bytes)
 + */
 +void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
 +
 +/**
 + * aes_encrypt_deinit - Deinitialize AES encryption
 + * @ctx: Context pointer from aes_encrypt_init()
 + */
 +void aes_encrypt_deinit(void *ctx);
 +
 +/**
 + * aes_decrypt_init - Initialize AES for decryption
 + * @key: Decryption key
 + * @len: Key length in bytes (usually 16, i.e., 128 bits)
 + * Returns: Pointer to context data or %NULL on failure
 + */
 +void * aes_decrypt_init(const u8 *key, size_t len);
 +
 +/**
 + * aes_decrypt - Decrypt one AES block
 + * @ctx: Context pointer from aes_encrypt_init()
 + * @crypt: Encrypted data (16 bytes)
 + * @plain: Buffer for the decrypted data (16 bytes)
 + */
 +void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
 +
 +/**
 + * aes_decrypt_deinit - Deinitialize AES decryption
 + * @ctx: Context pointer from aes_encrypt_init()
 + */
 +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_SHA384, CRYPTO_HASH_ALG_SHA512
 +};
 +
 +struct crypto_hash;
 +
 +/**
 + * crypto_hash_init - Initialize hash/HMAC function
 + * @alg: Hash algorithm
 + * @key: Key for keyed hash (e.g., HMAC) or %NULL if not needed
 + * @key_len: Length of the key in bytes
 + * Returns: Pointer to hash context to use with other hash functions or %NULL
 + * on failure
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
 +                                    size_t key_len);
 +
 +/**
 + * crypto_hash_update - Add data to hash calculation
 + * @ctx: Context pointer from crypto_hash_init()
 + * @data: Data buffer to add
 + * @len: Length of the buffer
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len);
 +
 +/**
 + * crypto_hash_finish - Complete hash calculation
 + * @ctx: Context pointer from crypto_hash_init()
 + * @hash: Buffer for hash value or %NULL if caller is just freeing the hash
 + * context
 + * @len: Pointer to length of the buffer or %NULL if caller is just freeing the
 + * hash context; on return, this is set to the actual length of the hash value
 + * Returns: 0 on success, -1 if buffer is too small (len set to needed length),
 + * or -2 on other failures (including failed crypto_hash_update() operations)
 + *
 + * This function calculates the hash value and frees the context buffer that
 + * was used for hash calculation.
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +int crypto_hash_finish(struct crypto_hash *ctx, u8 *hash, size_t *len);
 +
 +
 +enum crypto_cipher_alg {
 +      CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES,
 +      CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4
 +};
 +
 +struct crypto_cipher;
 +
 +/**
 + * crypto_cipher_init - Initialize block/stream cipher function
 + * @alg: Cipher algorithm
 + * @iv: Initialization vector for block ciphers or %NULL for stream ciphers
 + * @key: Cipher key
 + * @key_len: Length of key in bytes
 + * Returns: Pointer to cipher context to use with other cipher functions or
 + * %NULL on failure
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
 +                                        const u8 *iv, const u8 *key,
 +                                        size_t key_len);
 +
 +/**
 + * crypto_cipher_encrypt - Cipher encrypt
 + * @ctx: Context pointer from crypto_cipher_init()
 + * @plain: Plaintext to cipher
 + * @crypt: Resulting ciphertext
 + * @len: Length of the plaintext
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +int __must_check crypto_cipher_encrypt(struct crypto_cipher *ctx,
 +                                     const u8 *plain, u8 *crypt, size_t len);
 +
 +/**
 + * crypto_cipher_decrypt - Cipher decrypt
 + * @ctx: Context pointer from crypto_cipher_init()
 + * @crypt: Ciphertext to decrypt
 + * @plain: Resulting plaintext
 + * @len: Length of the cipher text
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +int __must_check crypto_cipher_decrypt(struct crypto_cipher *ctx,
 +                                     const u8 *crypt, u8 *plain, size_t len);
 +
 +/**
 + * crypto_cipher_decrypt - Free cipher context
 + * @ctx: Context pointer from crypto_cipher_init()
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +void crypto_cipher_deinit(struct crypto_cipher *ctx);
 +
 +
 +struct crypto_public_key;
 +struct crypto_private_key;
 +
 +/**
 + * crypto_public_key_import - Import an RSA public key
 + * @key: Key buffer (DER encoded RSA public key)
 + * @len: Key buffer length in bytes
 + * Returns: Pointer to the public key or %NULL on failure
 + *
 + * This function can just return %NULL if the crypto library supports X.509
 + * parsing. In that case, crypto_public_key_from_cert() is used to import the
 + * public key from a certificate.
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len);
 +
 +struct crypto_public_key *
 +crypto_public_key_import_parts(const u8 *n, size_t n_len,
 +                             const u8 *e, size_t e_len);
 +
 +/**
 + * crypto_private_key_import - Import an RSA private key
 + * @key: Key buffer (DER encoded RSA private key)
 + * @len: Key buffer length in bytes
 + * @passwd: Key encryption password or %NULL if key is not encrypted
 + * Returns: Pointer to the private key or %NULL on failure
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +struct crypto_private_key * crypto_private_key_import(const u8 *key,
 +                                                    size_t len,
 +                                                    const char *passwd);
 +
 +/**
 + * crypto_public_key_from_cert - Import an RSA public key from a certificate
 + * @buf: DER encoded X.509 certificate
 + * @len: Certificate buffer length in bytes
 + * Returns: Pointer to public key or %NULL on failure
 + *
 + * This function can just return %NULL if the crypto library does not support
 + * X.509 parsing. In that case, internal code will be used to parse the
 + * certificate and public key is imported using crypto_public_key_import().
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
 +                                                     size_t len);
 +
 +/**
 + * crypto_public_key_encrypt_pkcs1_v15 - Public key encryption (PKCS #1 v1.5)
 + * @key: Public key
 + * @in: Plaintext buffer
 + * @inlen: Length of plaintext buffer in bytes
 + * @out: Output buffer for encrypted data
 + * @outlen: Length of output buffer in bytes; set to used length on success
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +int __must_check crypto_public_key_encrypt_pkcs1_v15(
 +      struct crypto_public_key *key, const u8 *in, size_t inlen,
 +      u8 *out, size_t *outlen);
 +
 +/**
 + * crypto_private_key_decrypt_pkcs1_v15 - Private key decryption (PKCS #1 v1.5)
 + * @key: Private key
 + * @in: Encrypted buffer
 + * @inlen: Length of encrypted buffer in bytes
 + * @out: Output buffer for encrypted data
 + * @outlen: Length of output buffer in bytes; set to used length on success
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +int __must_check crypto_private_key_decrypt_pkcs1_v15(
 +      struct crypto_private_key *key, const u8 *in, size_t inlen,
 +      u8 *out, size_t *outlen);
 +
 +/**
 + * crypto_private_key_sign_pkcs1 - Sign with private key (PKCS #1)
 + * @key: Private key from crypto_private_key_import()
 + * @in: Plaintext buffer
 + * @inlen: Length of plaintext buffer in bytes
 + * @out: Output buffer for encrypted (signed) data
 + * @outlen: Length of output buffer in bytes; set to used length on success
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +int __must_check crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
 +                                             const u8 *in, size_t inlen,
 +                                             u8 *out, size_t *outlen);
 +
 +/**
 + * crypto_public_key_free - Free public key
 + * @key: Public key
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +void crypto_public_key_free(struct crypto_public_key *key);
 +
 +/**
 + * crypto_private_key_free - Free private key
 + * @key: Private key from crypto_private_key_import()
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +void crypto_private_key_free(struct crypto_private_key *key);
 +
 +/**
 + * crypto_public_key_decrypt_pkcs1 - Decrypt PKCS #1 signature
 + * @key: Public key
 + * @crypt: Encrypted signature data (using the private key)
 + * @crypt_len: Encrypted signature data length
 + * @plain: Buffer for plaintext (at least crypt_len bytes)
 + * @plain_len: Plaintext length (max buffer size on input, real len on output);
 + * Returns: 0 on success, -1 on failure
 + */
 +int __must_check crypto_public_key_decrypt_pkcs1(
 +      struct crypto_public_key *key, const u8 *crypt, size_t crypt_len,
 +      u8 *plain, size_t *plain_len);
 +
 +/**
 + * crypto_global_init - Initialize crypto wrapper
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +int __must_check crypto_global_init(void);
 +
 +/**
 + * crypto_global_deinit - Deinitialize crypto wrapper
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +void crypto_global_deinit(void);
 +
 +/**
 + * crypto_mod_exp - Modular exponentiation of large integers
 + * @base: Base integer (big endian byte array)
 + * @base_len: Length of base integer in bytes
 + * @power: Power integer (big endian byte array)
 + * @power_len: Length of power integer in bytes
 + * @modulus: Modulus integer (big endian byte array)
 + * @modulus_len: Length of modulus integer in bytes
 + * @result: Buffer for the result
 + * @result_len: Result length (max buffer size on input, real len on output)
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function calculates result = base ^ power mod modulus. modules_len is
 + * used as the maximum size of modulus buffer. It is set to the used size on
 + * success.
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +int __must_check crypto_mod_exp(const u8 *base, size_t base_len,
 +                              const u8 *power, size_t power_len,
 +                              const u8 *modulus, size_t modulus_len,
 +                              u8 *result, size_t *result_len);
 +
 +/**
 + * rc4_skip - XOR RC4 stream to given data with skip-stream-start
 + * @key: RC4 key
 + * @keylen: RC4 key length
 + * @skip: number of bytes to skip from the beginning of the RC4 stream
 + * @data: data to be XOR'ed with RC4 stream
 + * @data_len: buf length
 + * Returns: 0 on success, -1 on failure
 + *
 + * Generate RC4 pseudo random stream for the given key, skip beginning of the
 + * stream, and XOR the end result with the data buffer to perform RC4
 + * encryption/decryption.
 + */
 +int rc4_skip(const u8 *key, size_t keylen, size_t skip,
 +           u8 *data, size_t data_len);
 +
 +/**
 + * crypto_get_random - Generate cryptographically strong pseudy-random bytes
 + * @buf: Buffer for data
 + * @len: Number of bytes to generate
 + * Returns: 0 on success, -1 on failure
 + *
 + * If the PRNG does not have enough entropy to ensure unpredictable byte
 + * sequence, this functions must return -1.
 + */
 +int crypto_get_random(void *buf, size_t len);
 +
 +
 +/**
 + * struct crypto_bignum - bignum
 + *
 + * Internal data structure for bignum implementation. The contents is specific
 + * to the used crypto library.
 + */
 +struct crypto_bignum;
 +
 +/**
 + * crypto_bignum_init - Allocate memory for bignum
 + * Returns: Pointer to allocated bignum or %NULL on failure
 + */
 +struct crypto_bignum * crypto_bignum_init(void);
 +
 +/**
 + * crypto_bignum_init_set - Allocate memory for bignum and set the value
 + * @buf: Buffer with unsigned binary value
 + * @len: Length of buf in octets
 + * Returns: Pointer to allocated bignum or %NULL on failure
 + */
 +struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len);
 +
 +/**
 + * crypto_bignum_deinit - Free bignum
 + * @n: Bignum from crypto_bignum_init() or crypto_bignum_init_set()
 + * @clear: Whether to clear the value from memory
 + */
 +void crypto_bignum_deinit(struct crypto_bignum *n, int clear);
 +
 +/**
 + * crypto_bignum_to_bin - Set binary buffer to unsigned bignum
 + * @a: Bignum
 + * @buf: Buffer for the binary number
 + * @len: Length of @buf in octets
 + * @padlen: Length in octets to pad the result to or 0 to indicate no padding
 + * Returns: Number of octets written on success, -1 on failure
 + */
 +int crypto_bignum_to_bin(const struct crypto_bignum *a,
 +                       u8 *buf, size_t buflen, size_t padlen);
 +
 +/**
 + * crypto_bignum_add - c = a + b
 + * @a: Bignum
 + * @b: Bignum
 + * @c: Bignum; used to store the result of a + b
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_bignum_add(const struct crypto_bignum *a,
 +                    const struct crypto_bignum *b,
 +                    struct crypto_bignum *c);
 +
 +/**
 + * crypto_bignum_mod - c = a % b
 + * @a: Bignum
 + * @b: Bignum
 + * @c: Bignum; used to store the result of a % b
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_bignum_mod(const struct crypto_bignum *a,
 +                    const struct crypto_bignum *b,
 +                    struct crypto_bignum *c);
 +
 +/**
 + * crypto_bignum_exptmod - Modular exponentiation: d = a^b (mod c)
 + * @a: Bignum; base
 + * @b: Bignum; exponent
 + * @c: Bignum; modulus
 + * @d: Bignum; used to store the result of a^b (mod c)
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_bignum_exptmod(const struct crypto_bignum *a,
 +                        const struct crypto_bignum *b,
 +                        const struct crypto_bignum *c,
 +                        struct crypto_bignum *d);
 +
 +/**
 + * crypto_bignum_inverse - Inverse a bignum so that a * c = 1 (mod b)
 + * @a: Bignum
 + * @b: Bignum
 + * @c: Bignum; used to store the result
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_bignum_inverse(const struct crypto_bignum *a,
 +                        const struct crypto_bignum *b,
 +                        struct crypto_bignum *c);
 +
 +/**
 + * crypto_bignum_sub - c = a - b
 + * @a: Bignum
 + * @b: Bignum
 + * @c: Bignum; used to store the result of a - b
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_bignum_sub(const struct crypto_bignum *a,
 +                    const struct crypto_bignum *b,
 +                    struct crypto_bignum *c);
 +
 +/**
 + * crypto_bignum_div - c = a / b
 + * @a: Bignum
 + * @b: Bignum
 + * @c: Bignum; used to store the result of a / b
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_bignum_div(const struct crypto_bignum *a,
 +                    const struct crypto_bignum *b,
 +                    struct crypto_bignum *c);
 +
 +/**
 + * crypto_bignum_mulmod - d = a * b (mod c)
 + * @a: Bignum
 + * @b: Bignum
 + * @c: Bignum
 + * @d: Bignum; used to store the result of (a * b) % c
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_bignum_mulmod(const struct crypto_bignum *a,
 +                       const struct crypto_bignum *b,
 +                       const struct crypto_bignum *c,
 +                       struct crypto_bignum *d);
 +
 +/**
 + * crypto_bignum_cmp - Compare two bignums
 + * @a: Bignum
 + * @b: Bignum
 + * Returns: -1 if a < b, 0 if a == b, or 1 if a > b
 + */
 +int crypto_bignum_cmp(const struct crypto_bignum *a,
 +                    const struct crypto_bignum *b);
 +
 +/**
 + * crypto_bignum_bits - Get size of a bignum in bits
 + * @a: Bignum
 + * Returns: Number of bits in the bignum
 + */
 +int crypto_bignum_bits(const struct crypto_bignum *a);
 +
 +/**
 + * crypto_bignum_is_zero - Is the given bignum zero
 + * @a: Bignum
 + * Returns: 1 if @a is zero or 0 if not
 + */
 +int crypto_bignum_is_zero(const struct crypto_bignum *a);
 +
 +/**
 + * crypto_bignum_is_one - Is the given bignum one
 + * @a: Bignum
 + * Returns: 1 if @a is one or 0 if not
 + */
 +int crypto_bignum_is_one(const struct crypto_bignum *a);
 +
 +/**
 + * crypto_bignum_legendre - Compute the Legendre symbol (a/p)
 + * @a: Bignum
 + * @p: Bignum
 + * Returns: Legendre symbol -1,0,1 on success; -2 on calculation failure
 + */
 +int crypto_bignum_legendre(const struct crypto_bignum *a,
 +                         const struct crypto_bignum *p);
 +
 +/**
 + * struct crypto_ec - Elliptic curve context
 + *
 + * Internal data structure for EC implementation. The contents is specific
 + * to the used crypto library.
 + */
 +struct crypto_ec;
 +
 +/**
 + * crypto_ec_init - Initialize elliptic curve context
 + * @group: Identifying number for the ECC group (IANA "Group Description"
 + *    attribute registrty for RFC 2409)
 + * Returns: Pointer to EC context or %NULL on failure
 + */
 +struct crypto_ec * crypto_ec_init(int group);
 +
 +/**
 + * crypto_ec_deinit - Deinitialize elliptic curve context
 + * @e: EC context from crypto_ec_init()
 + */
 +void crypto_ec_deinit(struct crypto_ec *e);
 +
 +/**
 + * crypto_ec_prime_len - Get length of the prime in octets
 + * @e: EC context from crypto_ec_init()
 + * Returns: Length of the prime defining the group
 + */
 +size_t crypto_ec_prime_len(struct crypto_ec *e);
 +
 +/**
 + * crypto_ec_prime_len_bits - Get length of the prime in bits
 + * @e: EC context from crypto_ec_init()
 + * Returns: Length of the prime defining the group in bits
 + */
 +size_t crypto_ec_prime_len_bits(struct crypto_ec *e);
 +
 +/**
 + * crypto_ec_get_prime - Get prime defining an EC group
 + * @e: EC context from crypto_ec_init()
 + * Returns: Prime (bignum) defining the group
 + */
 +const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e);
 +
 +/**
 + * crypto_ec_get_order - Get order of an EC group
 + * @e: EC context from crypto_ec_init()
 + * Returns: Order (bignum) of the group
 + */
 +const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e);
 +
 +/**
 + * struct crypto_ec_point - Elliptic curve point
 + *
 + * Internal data structure for EC implementation to represent a point. The
 + * contents is specific to the used crypto library.
 + */
 +struct crypto_ec_point;
 +
 +/**
 + * crypto_ec_point_init - Initialize data for an EC point
 + * @e: EC context from crypto_ec_init()
 + * Returns: Pointer to EC point data or %NULL on failure
 + */
 +struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e);
 +
 +/**
 + * crypto_ec_point_deinit - Deinitialize EC point data
 + * @p: EC point data from crypto_ec_point_init()
 + * @clear: Whether to clear the EC point value from memory
 + */
 +void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear);
 +
 +/**
 + * crypto_ec_point_to_bin - Write EC point value as binary data
 + * @e: EC context from crypto_ec_init()
 + * @p: EC point data from crypto_ec_point_init()
 + * @x: Buffer for writing the binary data for x coordinate or %NULL if not used
 + * @y: Buffer for writing the binary data for y coordinate or %NULL if not used
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function can be used to write an EC point as binary data in a format
 + * that has the x and y coordinates in big endian byte order fields padded to
 + * the length of the prime defining the group.
 + */
 +int crypto_ec_point_to_bin(struct crypto_ec *e,
 +                         const struct crypto_ec_point *point, u8 *x, u8 *y);
 +
 +/**
 + * crypto_ec_point_from_bin - Create EC point from binary data
 + * @e: EC context from crypto_ec_init()
 + * @val: Binary data to read the EC point from
 + * Returns: Pointer to EC point data or %NULL on failure
 + *
 + * This function readers x and y coordinates of the EC point from the provided
 + * buffer assuming the values are in big endian byte order with fields padded to
 + * the length of the prime defining the group.
 + */
 +struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
 +                                                const u8 *val);
 +
 +/**
 + * crypto_bignum_add - c = a + b
 + * @e: EC context from crypto_ec_init()
 + * @a: Bignum
 + * @b: Bignum
 + * @c: Bignum; used to store the result of a + b
 + * Returns: 0 on success, -1 on failure
 + */
 +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);
 +
 +/**
 + * crypto_bignum_mul - res = b * p
 + * @e: EC context from crypto_ec_init()
 + * @p: EC point
 + * @b: Bignum
 + * @res: EC point; used to store the result of b * p
 + * Returns: 0 on success, -1 on failure
 + */
 +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);
 +
 +/**
 + * crypto_ec_point_invert - Compute inverse of an EC point
 + * @e: EC context from crypto_ec_init()
 + * @p: EC point to invert (and result of the operation)
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p);
 +
 +/**
 + * crypto_ec_point_solve_y_coord - Solve y coordinate for an x coordinate
 + * @e: EC context from crypto_ec_init()
 + * @p: EC point to use for the returning the result
 + * @x: x coordinate
 + * @y_bit: y-bit (0 or 1) for selecting the y value to use
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
 +                                struct crypto_ec_point *p,
 +                                const struct crypto_bignum *x, int y_bit);
 +
 +/**
 + * crypto_ec_point_compute_y_sqr - Compute y^2 = x^3 + ax + b
 + * @e: EC context from crypto_ec_init()
 + * @x: x coordinate
 + * Returns: y^2 on success, %NULL failure
 + */
 +struct crypto_bignum *
 +crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
 +                            const struct crypto_bignum *x);
 +
 +/**
 + * crypto_ec_point_is_at_infinity - Check whether EC point is neutral element
 + * @e: EC context from crypto_ec_init()
 + * @p: EC point
 + * Returns: 1 if the specified EC point is the neutral element of the group or
 + *    0 if not
 + */
 +int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
 +                                 const struct crypto_ec_point *p);
 +
 +/**
 + * crypto_ec_point_is_on_curve - Check whether EC point is on curve
 + * @e: EC context from crypto_ec_init()
 + * @p: EC point
 + * Returns: 1 if the specified EC point is on the curve or 0 if not
 + */
 +int crypto_ec_point_is_on_curve(struct crypto_ec *e,
 +                              const struct crypto_ec_point *p);
 +
 +/**
 + * crypto_ec_point_cmp - Compare two EC points
 + * @e: EC context from crypto_ec_init()
 + * @a: EC point
 + * @b: EC point
 + * Returns: 0 on equal, non-zero otherwise
 + */
 +int crypto_ec_point_cmp(const struct crypto_ec *e,
 +                      const struct crypto_ec_point *a,
 +                      const struct crypto_ec_point *b);
 +
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* CRYPTO_H */
@@@ -11,6 -11,8 +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 +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 +62,16 @@@ struct crypto_hash * crypto_hash_init(e
                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 +160,16 @@@ void crypto_hash_update(struct crypto_h
                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 +219,28 @@@ int crypto_hash_finish(struct crypto_ha
                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;
@@@ -9,6 -9,7 +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 +1267,7 @@@ static int test_sha1(void
  }
  
  
- const struct {
static const struct {
        char *data;
        u8 hash[32];
  } tests[] = {
        }
  };
  
- const struct hmac_test {
static const struct hmac_test {
        u8 key[80];
        size_t key_len;
        u8 data[128];
@@@ -1503,6 -1504,7 +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);
                   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 +1751,7 @@@ int crypto_module_tests(void
            test_md5() ||
            test_sha1() ||
            test_sha256() ||
+           test_fips186_2_prf() ||
            test_ms_funcs())
                ret = -1;
  
  #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,
                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
  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 +186,34 @@@ int rc4_skip(const u8 *key, size_t keyl
  #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 +265,16 @@@ void * aes_encrypt_init(const u8 *key, 
        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 +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 +317,18 @@@ void * aes_decrypt_init(const u8 *key, 
        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 +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 +399,56 @@@ int aes_unwrap(const u8 *kek, size_t ke
  
  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 +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 +553,25 @@@ struct crypto_cipher * crypto_cipher_in
                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 +584,7 @@@ int crypto_cipher_encrypt(struct crypto
                          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 +595,7 @@@ int crypto_cipher_decrypt(struct crypto
  {
        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;
  }
  
  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 +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();
  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 +830,7 @@@ void dh5_free(void *ctx
  
  
  struct crypto_hash {
-       HMAC_CTX ctx;
+       HMAC_CTX *ctx;
  };
  
  
@@@ -707,16 -865,17 +865,17 @@@ struct crypto_hash * crypto_hash_init(e
        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 +885,7 @@@ void crypto_hash_update(struct crypto_h
  {
        if (ctx == NULL)
                return;
-       HMAC_Update(&ctx->ctx, data, len);
+       HMAC_Update(ctx->ctx, data, len);
  }
  
  
@@@ -739,18 -898,14 +898,14 @@@ int crypto_hash_finish(struct crypto_ha
                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 +922,26 @@@ static int openssl_hmac_vector(const EV
                               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 +1045,9 @@@ int omac1_aes_vector(const u8 *key, siz
        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 +1097,20 @@@ int omac1_aes_256(const u8 *key, const 
  
  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 +1129,9 @@@ int crypto_bignum_to_bin(const struct c
  {
        int num_bytes, offset;
  
+       if (TEST_FAIL())
+               return -1;
        if (padlen > buflen)
                return -1;
  
@@@ -1019,6 -1185,9 +1185,9 @@@ int crypto_bignum_exptmod(const struct 
        int res;
        BN_CTX *bnctx;
  
+       if (TEST_FAIL())
+               return -1;
        bnctx = BN_CTX_new();
        if (bnctx == NULL)
                return -1;
@@@ -1037,6 -1206,8 +1206,8 @@@ int crypto_bignum_inverse(const struct 
        BIGNUM *res;
        BN_CTX *bnctx;
  
+       if (TEST_FAIL())
+               return -1;
        bnctx = BN_CTX_new();
        if (bnctx == NULL)
                return -1;
@@@ -1052,6 -1223,8 +1223,8 @@@ int crypto_bignum_sub(const struct cryp
                      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 +1238,9 @@@ int crypto_bignum_div(const struct cryp
  
        BN_CTX *bnctx;
  
+       if (TEST_FAIL())
+               return -1;
        bnctx = BN_CTX_new();
        if (bnctx == NULL)
                return -1;
@@@ -1085,6 -1261,9 +1261,9 @@@ int crypto_bignum_mulmod(const struct c
  
        BN_CTX *bnctx;
  
+       if (TEST_FAIL())
+               return -1;
        bnctx = BN_CTX_new();
        if (bnctx == NULL)
                return -1;
@@@ -1128,6 -1307,9 +1307,9 @@@ int crypto_bignum_legendre(const struc
        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 +1434,8 @@@ void crypto_ec_deinit(struct crypto_ec 
  
  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 +1482,9 @@@ int crypto_ec_point_to_bin(struct crypt
        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 +1515,9 @@@ struct crypto_ec_point * crypto_ec_poin
        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 +1545,8 @@@ int crypto_ec_point_add(struct crypto_e
                        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 +1556,8 @@@ int crypto_ec_point_mul(struct crypto_e
                        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;
  
  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 +1576,8 @@@ int crypto_ec_point_solve_y_coord(struc
                                  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 +1593,9 @@@ crypto_ec_point_compute_y_sqr(struct cr
  {
        BIGNUM *tmp, *tmp2, *y_sqr = NULL;
  
+       if (TEST_FAIL())
+               return NULL;
        tmp = BN_new();
        tmp2 = BN_new();
  
@@@ -15,6 -15,7 +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;
@@@ -1218,14 -1218,19 +1218,19 @@@ struct wpabuf * dh_init(const struct dh
  
        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);
@@@ -17,6 -17,19 +17,19 @@@ static void sha1_transform(u32 *state, 
  {
        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 +41,7 @@@
        state[2] = context.h2;
        state[3] = context.h3;
        state[4] = context.h4;
+ #endif
  }
  
  
@@@ -62,12 -76,11 +76,11 @@@ int fips186_2_prf(const u8 *seed, size_
                        /* 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;
@@@ -31,6 -31,9 +31,9 @@@ int md4_vector(size_t num_elem, const u
        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]);
@@@ -33,6 -33,9 +33,9 @@@ int md5_vector(size_t num_elem, const u
        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]);
@@@ -48,7 -48,7 +48,7 @@@ static int utf8_to_ucs2(const u8 *utf8_
                                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;
@@@ -33,6 -33,9 +33,9 @@@ int sha1_vector(size_t num_elem, const 
        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 +297,6 @@@ void SHA1Final(unsigned char digest[20]
                         255);
        }
        /* Wipe variables */
-       i = 0;
        os_memset(context->buffer, 0, 64);
        os_memset(context->state, 0, 20);
        os_memset(context->count, 0, 8);
@@@ -28,6 -28,9 +28,9 @@@ int sha256_vector(size_t num_elem, cons
        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]))
@@@ -1,6 -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);
  }
  
  
   * @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;
                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;
        }
  
        os_memset(hash, 0, sizeof(hash));
+       return 0;
  }
@@@ -1,6 -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 +15,11 @@@ int hmac_sha256_vector(const u8 *key, s
                       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);
index 0000000,646f729..646f729
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,92 +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 ===== */
index 0000000,a00253f..a00253f
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,23 +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 */
index 0000000,76c4fe7..76c4fe7
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,264 +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 ===== */
index 0000000,1089589..1089589
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,25 +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 */
diff --combined libeap/src/crypto/tls.h
index d02158e,0000000..33262da
mode 100644,000000..100644
--- /dev/null
@@@ -1,602 -1,0 +1,612 @@@
-     /**
-      * If non-null, specifies a callback method that can be used to
-      * confirm the validity of a peer certificate.
-      */
 +/*
 + * SSL/TLS interface definition
 + * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
 + *
 + * This software may be distributed under the terms of the BSD license.
 + * See README for more details.
 + */
 +
 +#ifndef TLS_H
 +#define TLS_H
 +
 +#include <openssl/x509.h>
 +
 +struct tls_connection;
 +
 +struct tls_random {
 +      const u8 *client_random;
 +      size_t client_random_len;
 +      const u8 *server_random;
 +      size_t server_random_len;
 +};
 +
 +enum tls_event {
 +      TLS_CERT_CHAIN_SUCCESS,
 +      TLS_CERT_CHAIN_FAILURE,
 +      TLS_PEER_CERTIFICATE,
 +      TLS_ALERT
 +};
 +
 +/*
 + * Note: These are used as identifier with external programs and as such, the
 + * values must not be changed.
 + */
 +enum tls_fail_reason {
 +      TLS_FAIL_UNSPECIFIED = 0,
 +      TLS_FAIL_UNTRUSTED = 1,
 +      TLS_FAIL_REVOKED = 2,
 +      TLS_FAIL_NOT_YET_VALID = 3,
 +      TLS_FAIL_EXPIRED = 4,
 +      TLS_FAIL_SUBJECT_MISMATCH = 5,
 +      TLS_FAIL_ALTSUBJECT_MISMATCH = 6,
 +      TLS_FAIL_BAD_CERTIFICATE = 7,
 +      TLS_FAIL_SERVER_CHAIN_PROBE = 8,
 +      TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9,
 +      TLS_FAIL_DOMAIN_MISMATCH = 10,
 +};
 +
 +
 +#define TLS_MAX_ALT_SUBJECT 10
 +
 +union tls_event_data {
 +      struct {
 +              int depth;
 +              const char *subject;
 +              enum tls_fail_reason reason;
 +              const char *reason_txt;
 +              const struct wpabuf *cert;
 +      } cert_fail;
 +
 +      struct {
 +              int depth;
 +              const char *subject;
 +              const struct wpabuf *cert;
 +              const u8 *hash;
 +              size_t hash_len;
 +              const char *altsubject[TLS_MAX_ALT_SUBJECT];
 +              int num_altsubject;
 +      } peer_cert;
 +
 +      struct {
 +              int is_local;
 +              const char *type;
 +              const char *description;
 +      } alert;
 +};
 +
 +struct tls_config {
 +      const char *opensc_engine_path;
 +      const char *pkcs11_engine_path;
 +      const char *pkcs11_module_path;
 +      int fips_mode;
 +      int cert_in_cb;
 +      const char *openssl_ciphers;
 +      unsigned int tls_session_lifetime;
 +
 +      void (*event_cb)(void *ctx, enum tls_event ev,
 +                       union tls_event_data *data);
 +      void *cb_ctx;
 +};
 +
 +#define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0)
 +#define TLS_CONN_DISABLE_TIME_CHECKS BIT(1)
 +#define TLS_CONN_DISABLE_SESSION_TICKET BIT(2)
 +#define TLS_CONN_REQUEST_OCSP BIT(3)
 +#define TLS_CONN_REQUIRE_OCSP BIT(4)
 +#define TLS_CONN_DISABLE_TLSv1_1 BIT(5)
 +#define TLS_CONN_DISABLE_TLSv1_2 BIT(6)
 +#define TLS_CONN_EAP_FAST BIT(7)
 +#define TLS_CONN_DISABLE_TLSv1_0 BIT(8)
++#define TLS_CONN_EXT_CERT_CHECK BIT(9)
++#define TLS_CONN_REQUIRE_OCSP_ALL BIT(10)
 +
 +struct X509; /* from OpenSSL */
 +
 +/**
 + * struct tls_connection_params - Parameters for TLS connection
 + * @ca_cert: File or reference name for CA X.509 certificate in PEM or DER
 + * format
 + * @ca_cert_blob: ca_cert as inlined data or %NULL if not used
 + * @ca_cert_blob_len: ca_cert_blob length
 + * @ca_path: Path to CA certificates (OpenSSL specific)
 + * @subject_match: String to match in the subject of the peer certificate or
 + * %NULL to allow all subjects
 + * @altsubject_match: String to match in the alternative subject of the peer
 + * certificate or %NULL to allow all alternative subjects
 + * @suffix_match: String to suffix match in the dNSName or CN of the peer
 + * certificate or %NULL to allow all domain names. This may allow subdomains an
 + * wildcard certificates. Each domain name label must have a full match.
 + * @domain_match: String to match in the dNSName or CN of the peer
 + * certificate or %NULL to allow all domain names. This requires a full,
 + * case-insensitive match.
 + * @client_cert: File or reference name for client X.509 certificate in PEM or
 + * DER format
 + * @client_cert_blob: client_cert as inlined data or %NULL if not used
 + * @client_cert_blob_len: client_cert_blob length
 + * @private_key: File or reference name for client private key in PEM or DER
 + * format (traditional format (RSA PRIVATE KEY) or PKCS#8 (PRIVATE KEY)
 + * @private_key_blob: private_key as inlined data or %NULL if not used
 + * @private_key_blob_len: private_key_blob length
 + * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
 + * passphrase is used.
 + * @dh_file: File name for DH/DSA data in PEM format, or %NULL if not used
 + * @dh_blob: dh_file as inlined data or %NULL if not used
 + * @dh_blob_len: dh_blob length
 + * @engine: 1 = use engine (e.g., a smartcard) for private key operations
 + * (this is OpenSSL specific for now)
 + * @engine_id: engine id string (this is OpenSSL specific for now)
 + * @ppin: pointer to the pin variable in the configuration
 + * (this is OpenSSL specific for now)
 + * @key_id: the private key's id when using engine (this is OpenSSL
 + * specific for now)
 + * @cert_id: the certificate's id when using engine
 + * @ca_cert_id: the CA certificate's id when using engine
 + * @openssl_ciphers: OpenSSL cipher configuration
 + * @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.
 + *
 + * TLS connection parameters to be configured with tls_connection_set_params()
 + * and tls_global_set_params().
 + *
 + * Certificates and private key can be configured either as a reference name
 + * (file path or reference to certificate store) or by providing the same data
 + * as a pointer to the data in memory. Only one option will be used for each
 + * field.
 + */
 +struct tls_connection_params {
 +      const char *ca_cert;
 +      const u8 *ca_cert_blob;
 +      size_t ca_cert_blob_len;
 +      const char *ca_path;
 +      const char *subject_match;
 +      const char *altsubject_match;
 +      const char *suffix_match;
 +      const char *domain_match;
 +      const char *client_cert;
 +      const u8 *client_cert_blob;
 +      size_t client_cert_blob_len;
 +      const char *private_key;
 +      const u8 *private_key_blob;
 +      size_t private_key_blob_len;
 +      const char *private_key_passwd;
 +      const char *dh_file;
 +      const u8 *dh_blob;
 +      size_t dh_blob_len;
 +
 +      /* OpenSSL specific variables */
 +      int engine;
 +      const char *engine_id;
 +      const char *pin;
 +      const char *key_id;
 +      const char *cert_id;
 +      const char *ca_cert_id;
 +      const char *openssl_ciphers;
 +
 +      unsigned int flags;
 +      const char *ocsp_stapling_response;
-  * tls_connection_prf - Use TLS-PRF to derive keying material
++      const char *ocsp_stapling_response_multi;
 +    int (*server_cert_cb)(int ok_so_far, X509* cert, void *ca_ctx);
 +    void *server_cert_ctx;
 +};
 +
 +
 +/**
 + * tls_init - Initialize TLS library
 + * @conf: Configuration data for TLS library
 + * Returns: Context data to be used as tls_ctx in calls to other functions,
 + * or %NULL on failure.
 + *
 + * Called once during program startup and once for each RSN pre-authentication
 + * session. In other words, there can be two concurrent TLS contexts. If global
 + * library initialization is needed (i.e., one that is shared between both
 + * authentication types), the TLS library wrapper should maintain a reference
 + * counter and do global initialization only when moving from 0 to 1 reference.
 + */
 +void * tls_init(const struct tls_config *conf);
 +
 +/**
 + * tls_deinit - Deinitialize TLS library
 + * @tls_ctx: TLS context data from tls_init()
 + *
 + * Called once during program shutdown and once for each RSN pre-authentication
 + * session. If global library deinitialization is needed (i.e., one that is
 + * shared between both authentication types), the TLS library wrapper should
 + * maintain a reference counter and do global deinitialization only when moving
 + * from 1 to 0 references.
 + */
 +void tls_deinit(void *tls_ctx);
 +
 +/**
 + * tls_get_errors - Process pending errors
 + * @tls_ctx: TLS context data from tls_init()
 + * Returns: Number of found error, 0 if no errors detected.
 + *
 + * Process all pending TLS errors.
 + */
 +int tls_get_errors(void *tls_ctx);
 +
 +/**
 + * tls_connection_init - Initialize a new TLS connection
 + * @tls_ctx: TLS context data from tls_init()
 + * Returns: Connection context data, conn for other function calls
 + */
 +struct tls_connection * tls_connection_init(void *tls_ctx);
 +
 +/**
 + * tls_connection_deinit - Free TLS connection data
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + *
 + * Release all resources allocated for TLS connection.
 + */
 +void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn);
 +
 +/**
 + * tls_connection_established - Has the TLS connection been completed?
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * Returns: 1 if TLS connection has been completed, 0 if not.
 + */
 +int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
 +
 +/**
 + * tls_connection_shutdown - Shutdown TLS connection
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * Returns: 0 on success, -1 on failure
 + *
 + * Shutdown current TLS connection without releasing all resources. New
 + * connection can be started by using the same conn without having to call
 + * tls_connection_init() or setting certificates etc. again. The new
 + * connection should try to use session resumption.
 + */
 +int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn);
 +
 +enum {
 +      TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN = -4,
 +      TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3,
 +      TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2
 +};
 +
 +/**
 + * tls_connection_set_params - Set TLS connection parameters
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @params: Connection parameters
 + * Returns: 0 on success, -1 on failure,
 + * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on error causing PKCS#11 engine
 + * failure, or
 + * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
 + * PKCS#11 engine private key, or
 + * TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN (-4) on PIN error causing PKCS#11 engine
 + * failure.
 + */
 +int __must_check
 +tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
 +                        const struct tls_connection_params *params);
 +
 +/**
 + * tls_global_set_params - Set TLS parameters for all TLS connection
 + * @tls_ctx: TLS context data from tls_init()
 + * @params: Global TLS parameters
 + * Returns: 0 on success, -1 on failure,
 + * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on error causing PKCS#11 engine
 + * failure, or
 + * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
 + * PKCS#11 engine private key, or
 + * TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN (-4) on PIN error causing PKCS#11 engine
 + * failure.
 + */
 +int __must_check tls_global_set_params(
 +      void *tls_ctx, const struct tls_connection_params *params);
 +
 +/**
 + * tls_global_set_verify - Set global certificate verification options
 + * @tls_ctx: TLS context data from tls_init()
 + * @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate,
 + * 2 = verify CRL for all certificates
 + * Returns: 0 on success, -1 on failure
 + */
 +int __must_check tls_global_set_verify(void *tls_ctx, int check_crl);
 +
 +/**
 + * tls_connection_set_verify - Set certificate verification options
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @verify_peer: 1 = verify peer certificate
 + * @flags: Connection flags (TLS_CONN_*)
 + * @session_ctx: Session caching context or %NULL to use default
 + * @session_ctx_len: Length of @session_ctx in bytes.
 + * Returns: 0 on success, -1 on failure
 + */
 +int __must_check tls_connection_set_verify(void *tls_ctx,
 +                                         struct tls_connection *conn,
 +                                         int verify_peer,
 +                                         unsigned int flags,
 +                                         const u8 *session_ctx,
 +                                         size_t session_ctx_len);
 +
 +/**
 + * tls_connection_get_random - Get random data from TLS connection
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @data: Structure of client/server random data (filled on success)
 + * Returns: 0 on success, -1 on failure
 + */
 +int __must_check tls_connection_get_random(void *tls_ctx,
 +                                       struct tls_connection *conn,
 +                                       struct tls_random *data);
 +
 +/**
-  * @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
++ * 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
-  * 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.
 + * @out: Buffer for output data from TLS-PRF
 + * @out_len: Length of the output buffer
 + * Returns: 0 on success, -1 on failure
 + *
- 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);
++ * 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.
 + */
-       TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */
++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)
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @in_data: Input data from TLS server
 + * @appl_data: Pointer to application data pointer, or %NULL if dropped
 + * Returns: Output data, %NULL on failure
 + *
 + * The caller is responsible for freeing the returned output data. If the final
 + * handshake message includes application data, this is decrypted and
 + * appl_data (if not %NULL) is set to point this data. The caller is
 + * responsible for freeing appl_data.
 + *
 + * This function is used during TLS handshake. The first call is done with
 + * in_data == %NULL and the library is expected to return ClientHello packet.
 + * This packet is then send to the server and a response from server is given
 + * to TLS library by calling this function again with in_data pointing to the
 + * TLS message from the server.
 + *
 + * If the TLS handshake fails, this function may return %NULL. However, if the
 + * TLS library has a TLS alert to send out, that should be returned as the
 + * output data. In this case, tls_connection_get_failed() must return failure
 + * (> 0).
 + *
 + * tls_connection_established() should return 1 once the TLS handshake has been
 + * completed successfully.
 + */
 +struct wpabuf * tls_connection_handshake(void *tls_ctx,
 +                                       struct tls_connection *conn,
 +                                       const struct wpabuf *in_data,
 +                                       struct wpabuf **appl_data);
 +
 +struct wpabuf * tls_connection_handshake2(void *tls_ctx,
 +                                        struct tls_connection *conn,
 +                                        const struct wpabuf *in_data,
 +                                        struct wpabuf **appl_data,
 +                                        int *more_data_needed);
 +
 +/**
 + * tls_connection_server_handshake - Process TLS handshake (server side)
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @in_data: Input data from TLS peer
 + * @appl_data: Pointer to application data pointer, or %NULL if dropped
 + * Returns: Output data, %NULL on failure
 + *
 + * The caller is responsible for freeing the returned output data.
 + */
 +struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
 +                                              struct tls_connection *conn,
 +                                              const struct wpabuf *in_data,
 +                                              struct wpabuf **appl_data);
 +
 +/**
 + * tls_connection_encrypt - Encrypt data into TLS tunnel
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @in_data: Plaintext data to be encrypted
 + * Returns: Encrypted TLS data or %NULL on failure
 + *
 + * This function is used after TLS handshake has been completed successfully to
 + * send data in the encrypted tunnel. The caller is responsible for freeing the
 + * returned output data.
 + */
 +struct wpabuf * tls_connection_encrypt(void *tls_ctx,
 +                                     struct tls_connection *conn,
 +                                     const struct wpabuf *in_data);
 +
 +/**
 + * tls_connection_decrypt - Decrypt data from TLS tunnel
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @in_data: Encrypted TLS data
 + * Returns: Decrypted TLS data or %NULL on failure
 + *
 + * This function is used after TLS handshake has been completed successfully to
 + * receive data from the encrypted tunnel. The caller is responsible for
 + * freeing the returned output data.
 + */
 +struct wpabuf * tls_connection_decrypt(void *tls_ctx,
 +                                     struct tls_connection *conn,
 +                                     const struct wpabuf *in_data);
 +
 +struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
 +                                      struct tls_connection *conn,
 +                                      const struct wpabuf *in_data,
 +                                      int *more_data_needed);
 +
 +/**
 + * tls_connection_resumed - Was session resumption used
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * Returns: 1 if current session used session resumption, 0 if not
 + */
 +int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn);
 +
 +enum {
 +      TLS_CIPHER_NONE,
 +      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_RSA_DHE_AES256_SHA /* 0x0039 */,
++      TLS_CIPHER_AES256_SHA /* 0x0035 */,
 +};
 +
 +/**
 + * tls_connection_set_cipher_list - Configure acceptable cipher suites
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
 + * (TLS_CIPHER_*).
 + * Returns: 0 on success, -1 on failure
 + */
 +int __must_check tls_connection_set_cipher_list(void *tls_ctx,
 +                                              struct tls_connection *conn,
 +                                              u8 *ciphers);
 +
 +/**
 + * tls_get_version - Get the current TLS version number
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @buf: Buffer for returning the TLS version number
 + * @buflen: buf size
 + * Returns: 0 on success, -1 on failure
 + *
 + * Get the currently used TLS version number.
 + */
 +int __must_check tls_get_version(void *tls_ctx, struct tls_connection *conn,
 +                               char *buf, size_t buflen);
 +
 +/**
 + * tls_get_cipher - Get current cipher name
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @buf: Buffer for the cipher name
 + * @buflen: buf size
 + * Returns: 0 on success, -1 on failure
 + *
 + * Get the name of the currently used cipher.
 + */
 +int __must_check tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
 +                              char *buf, size_t buflen);
 +
 +/**
 + * tls_connection_enable_workaround - Enable TLS workaround options
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function is used to enable connection-specific workaround options for
 + * buffer SSL/TLS implementations.
 + */
 +int __must_check tls_connection_enable_workaround(void *tls_ctx,
 +                                                struct tls_connection *conn);
 +
 +/**
 + * tls_connection_client_hello_ext - Set TLS extension for ClientHello
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @ext_type: Extension type
 + * @data: Extension payload (%NULL to remove extension)
 + * @data_len: Extension payload length
 + * Returns: 0 on success, -1 on failure
 + */
 +int __must_check tls_connection_client_hello_ext(void *tls_ctx,
 +                                               struct tls_connection *conn,
 +                                               int ext_type, const u8 *data,
 +                                               size_t data_len);
 +
 +/**
 + * tls_connection_get_failed - Get connection failure status
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + *
 + * Returns >0 if connection has failed, 0 if not.
 + */
 +int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn);
 +
 +/**
 + * tls_connection_get_read_alerts - Get connection read alert status
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * Returns: Number of times a fatal read (remote end reported error) has
 + * happened during this connection.
 + */
 +int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn);
 +
 +/**
 + * tls_connection_get_write_alerts - Get connection write alert status
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * Returns: Number of times a fatal write (locally detected error) has happened
 + * during this connection.
 + */
 +int tls_connection_get_write_alerts(void *tls_ctx,
 +                                  struct tls_connection *conn);
 +
 +typedef int (*tls_session_ticket_cb)
 +(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
 + const u8 *server_random, u8 *master_secret);
 +
 +int __must_check  tls_connection_set_session_ticket_cb(
 +      void *tls_ctx, struct tls_connection *conn,
 +      tls_session_ticket_cb cb, void *ctx);
 +
 +void tls_connection_set_log_cb(struct tls_connection *conn,
 +                             void (*log_cb)(void *ctx, const char *msg),
 +                             void *ctx);
 +
 +#define TLS_BREAK_VERIFY_DATA BIT(0)
 +#define TLS_BREAK_SRV_KEY_X_HASH BIT(1)
 +#define TLS_BREAK_SRV_KEY_X_SIGNATURE BIT(2)
 +#define TLS_DHE_PRIME_511B BIT(3)
 +#define TLS_DHE_PRIME_767B BIT(4)
 +#define TLS_DHE_PRIME_15 BIT(5)
 +#define TLS_DHE_PRIME_58B BIT(6)
 +#define TLS_DHE_NON_PRIME BIT(7)
 +
 +void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags);
 +
 +int tls_get_library_version(char *buf, size_t buf_len);
 +
 +void tls_connection_set_success_data(struct tls_connection *conn,
 +                                   struct wpabuf *data);
 +
 +void tls_connection_set_success_data_resumed(struct tls_connection *conn);
 +
 +const struct wpabuf *
 +tls_connection_get_success_data(struct tls_connection *conn);
 +
 +void tls_connection_remove_session(struct tls_connection *conn);
 +
 +#endif /* TLS_H */
@@@ -37,6 -37,8 +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 +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 +350,18 @@@ int tls_connection_set_params(void *tls
        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;
  }
  
  
+ #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)
  {
                }
        }
  
+ #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 +810,22 @@@ int tls_connection_get_random(void *ssl
  }
  
  
- 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;
  }
  
  
@@@ -23,6 -23,11 +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 +56,11 @@@ void * tls_init(const struct tls_confi
        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 +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 +107,8 @@@ struct tls_connection * tls_connection_
                        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 +200,12 @@@ int tls_connection_set_params(void *tls
        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;
                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 +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 +394,9 @@@ static int tls_get_keyblock_size(struc
  }
  
  
- 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;
        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)
  }
  
  
+ 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 +662,12 @@@ int tls_connection_set_cipher_list(voi
  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;
  }
  
@@@ -86,9 -86,15 +86,15 @@@ int tls_connection_get_random(void *tls
  }
  
  
- 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,0000000..9db8095
mode 100644,000000..100644
--- /dev/null
@@@ -1,4178 -1,0 +1,4366 @@@
- #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)
 +/*
 + * 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.
 + */
 +
 +#include "includes.h"
 +
 +#ifndef CONFIG_SMARTCARD
 +#ifndef OPENSSL_NO_ENGINE
 +#ifndef ANDROID
 +#define OPENSSL_NO_ENGINE
 +#endif
 +#endif
 +#endif
 +
 +#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 <openssl/engine.h>
 +#endif /* OPENSSL_NO_ENGINE */
 +#ifndef OPENSSL_NO_DSA
 +#include <openssl/dsa.h>
 +#endif
 +#ifndef OPENSSL_NO_DH
 +#include <openssl/dh.h>
 +#endif
 +
 +#include "common.h"
 +#include "crypto.h"
 +#include "sha1.h"
 +#include "sha256.h"
 +#include "tls.h"
++#include "tls_openssl.h"
 +
- #ifndef OPENSSL_NO_ENGINE
++#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)
 +/* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */
 +typedef size_t stack_index_t;
 +#else
 +typedef int stack_index_t;
 +#endif
 +
 +#ifdef SSL_set_tlsext_status_type
 +#ifndef OPENSSL_NO_TLSEXT
 +#define HAVE_OCSP
 +#include <openssl/ocsp.h>
 +#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>
 +
 +static BIO * BIO_from_keystore(const char *key)
 +{
 +      BIO *bio = NULL;
 +      uint8_t *value = NULL;
 +      int length = keystore_get(key, strlen(key), &value);
 +      if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL)
 +              BIO_write(bio, value, length);
 +      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;
 +static int tls_ex_idx_session = -1;
 +
 +struct tls_context {
 +      void (*event_cb)(void *ctx, enum tls_event ev,
 +                       union tls_event_data *data);
 +      void *cb_ctx;
 +      int cert_in_cb;
 +      char *ocsp_stapling_response;
 +};
 +
 +static struct tls_context *tls_global = NULL;
 +
 +
 +struct tls_data {
 +      SSL_CTX *ssl;
 +      unsigned int tls_session_lifetime;
 +};
 +
 +struct tls_connection {
 +      struct tls_context *context;
 +      SSL_CTX *ssl_ctx;
 +      SSL *ssl;
 +      BIO *ssl_in, *ssl_out;
- #if OPENSSL_VERSION_NUMBER >= 0x10100000L
++#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 */
 +      char *subject_match, *altsubject_match, *suffix_match, *domain_match;
 +      int read_alerts, write_alerts, failed;
 +
 +      tls_session_ticket_cb session_ticket_cb;
 +      void *session_ticket_cb_ctx;
 +
 +      /* SessionTicket received from OpenSSL hello_extension_cb (server) */
 +      u8 *session_ticket;
 +      size_t session_ticket_len;
 +
 +      unsigned int ca_cert_verify:1;
 +      unsigned int cert_probe:1;
 +      unsigned int server_cert_only:1;
 +      unsigned int invalid_hb_used:1;
 +      unsigned int success_data:1;
 +
 +      u8 srv_cert_hash[32];
 +
 +      unsigned int flags;
 +
 +      X509 *peer_cert;
 +      X509 *peer_issuer;
 +      X509 *peer_issuer_issuer;
 +
- #endif
 +      unsigned char client_random[SSL3_RANDOM_SIZE];
 +      unsigned char server_random[SSL3_RANDOM_SIZE];
-               if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
 +
 +    int (*server_cert_cb)(int ok_so_far, X509* cert, void *ca_ctx);
 +    void *server_cert_ctx;
 +};
 +
 +
 +static struct tls_context * tls_context_new(const struct tls_config *conf)
 +{
 +      struct tls_context *context = os_zalloc(sizeof(*context));
 +      if (context == NULL)
 +              return NULL;
 +      if (conf) {
 +              context->event_cb = conf->event_cb;
 +              context->cb_ctx = conf->cb_ctx;
 +              context->cert_in_cb = conf->cert_in_cb;
 +      }
 +      return context;
 +}
 +
 +#ifdef CONFIG_NO_STDOUT_DEBUG
 +
 +static void _tls_show_errors(void)
 +{
 +      unsigned long err;
 +
 +      while ((err = ERR_get_error())) {
 +              /* Just ignore the errors, since stdout is disabled */
 +      }
 +}
 +#define tls_show_errors(l, f, t) _tls_show_errors()
 +
 +#else /* CONFIG_NO_STDOUT_DEBUG */
 +
 +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));
 +      }
 +}
 +
 +#endif /* CONFIG_NO_STDOUT_DEBUG */
 +
 +
 +#ifdef CONFIG_NATIVE_WINDOWS
 +
 +/* Windows CryptoAPI and access to certificate stores */
 +#include <wincrypt.h>
 +
 +#ifdef __MINGW32_VERSION
 +/*
 + * MinGW does not yet include all the needed definitions for CryptoAPI, so
 + * define here whatever extra is needed.
 + */
 +#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16)
 +#define CERT_STORE_READONLY_FLAG 0x00008000
 +#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
 +
 +#endif /* __MINGW32_VERSION */
 +
 +
 +struct cryptoapi_rsa_data {
 +      const CERT_CONTEXT *cert;
 +      HCRYPTPROV crypt_prov;
 +      DWORD key_spec;
 +      BOOL free_crypt_prov;
 +};
 +
 +
 +static void cryptoapi_error(const char *msg)
 +{
 +      wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u",
 +                 msg, (unsigned int) GetLastError());
 +}
 +
 +
 +static int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from,
 +                               unsigned char *to, RSA *rsa, int padding)
 +{
 +      wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
 +      return 0;
 +}
 +
 +
 +static int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from,
 +                               unsigned char *to, RSA *rsa, int padding)
 +{
 +      wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
 +      return 0;
 +}
 +
 +
 +static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from,
 +                                unsigned char *to, RSA *rsa, int padding)
 +{
 +      struct cryptoapi_rsa_data *priv =
 +              (struct cryptoapi_rsa_data *) rsa->meth->app_data;
 +      HCRYPTHASH hash;
 +      DWORD hash_size, len, i;
 +      unsigned char *buf = NULL;
 +      int ret = 0;
 +
 +      if (priv == NULL) {
 +              RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
 +                     ERR_R_PASSED_NULL_PARAMETER);
 +              return 0;
 +      }
 +
 +      if (padding != RSA_PKCS1_PADDING) {
 +              RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
 +                     RSA_R_UNKNOWN_PADDING_TYPE);
 +              return 0;
 +      }
 +
 +      if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) {
 +              wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported",
 +                         __func__);
 +              RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
 +                     RSA_R_INVALID_MESSAGE_LENGTH);
 +              return 0;
 +      }
 +
 +      if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash))
 +      {
 +              cryptoapi_error("CryptCreateHash failed");
 +              return 0;
 +      }
 +
 +      len = sizeof(hash_size);
 +      if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len,
 +                             0)) {
 +              cryptoapi_error("CryptGetHashParam failed");
 +              goto err;
 +      }
 +
 +      if ((int) hash_size != flen) {
 +              wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)",
 +                         (unsigned) hash_size, flen);
 +              RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
 +                     RSA_R_INVALID_MESSAGE_LENGTH);
 +              goto err;
 +      }
 +      if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) {
 +              cryptoapi_error("CryptSetHashParam failed");
 +              goto err;
 +      }
 +
 +      len = RSA_size(rsa);
 +      buf = os_malloc(len);
 +      if (buf == NULL) {
 +              RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
 +              goto err;
 +      }
 +
 +      if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) {
 +              cryptoapi_error("CryptSignHash failed");
 +              goto err;
 +      }
 +
 +      for (i = 0; i < len; i++)
 +              to[i] = buf[len - i - 1];
 +      ret = len;
 +
 +err:
 +      os_free(buf);
 +      CryptDestroyHash(hash);
 +
 +      return ret;
 +}
 +
 +
 +static int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from,
 +                                unsigned char *to, RSA *rsa, int padding)
 +{
 +      wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
 +      return 0;
 +}
 +
 +
 +static void cryptoapi_free_data(struct cryptoapi_rsa_data *priv)
 +{
 +      if (priv == NULL)
 +              return;
 +      if (priv->crypt_prov && priv->free_crypt_prov)
 +              CryptReleaseContext(priv->crypt_prov, 0);
 +      if (priv->cert)
 +              CertFreeCertificateContext(priv->cert);
 +      os_free(priv);
 +}
 +
 +
 +static int cryptoapi_finish(RSA *rsa)
 +{
 +      cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data);
 +      os_free((void *) rsa->meth);
 +      rsa->meth = NULL;
 +      return 1;
 +}
 +
 +
 +static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store)
 +{
 +      HCERTSTORE cs;
 +      const CERT_CONTEXT *ret = NULL;
 +
 +      cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0,
 +                         store | CERT_STORE_OPEN_EXISTING_FLAG |
 +                         CERT_STORE_READONLY_FLAG, L"MY");
 +      if (cs == NULL) {
 +              cryptoapi_error("Failed to open 'My system store'");
 +              return NULL;
 +      }
 +
 +      if (strncmp(name, "cert://", 7) == 0) {
 +              unsigned short wbuf[255];
 +              MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255);
 +              ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING |
 +                                               PKCS_7_ASN_ENCODING,
 +                                               0, CERT_FIND_SUBJECT_STR,
 +                                               wbuf, NULL);
 +      } else if (strncmp(name, "hash://", 7) == 0) {
 +              CRYPT_HASH_BLOB blob;
 +              int len;
 +              const char *hash = name + 7;
 +              unsigned char *buf;
 +
 +              len = os_strlen(hash) / 2;
 +              buf = os_malloc(len);
 +              if (buf && hexstr2bin(hash, buf, len) == 0) {
 +                      blob.cbData = len;
 +                      blob.pbData = buf;
 +                      ret = CertFindCertificateInStore(cs,
 +                                                       X509_ASN_ENCODING |
 +                                                       PKCS_7_ASN_ENCODING,
 +                                                       0, CERT_FIND_HASH,
 +                                                       &blob, NULL);
 +              }
 +              os_free(buf);
 +      }
 +
 +      CertCloseStore(cs, 0);
 +
 +      return ret;
 +}
 +
 +
 +static int tls_cryptoapi_cert(SSL *ssl, const char *name)
 +{
 +      X509 *cert = NULL;
 +      RSA *rsa = NULL, *pub_rsa;
 +      struct cryptoapi_rsa_data *priv;
 +      RSA_METHOD *rsa_meth;
 +
 +      if (name == NULL ||
 +          (strncmp(name, "cert://", 7) != 0 &&
 +           strncmp(name, "hash://", 7) != 0))
 +              return -1;
 +
 +      priv = os_zalloc(sizeof(*priv));
 +      rsa_meth = os_zalloc(sizeof(*rsa_meth));
 +      if (priv == NULL || rsa_meth == NULL) {
 +              wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory "
 +                         "for CryptoAPI RSA method");
 +              os_free(priv);
 +              os_free(rsa_meth);
 +              return -1;
 +      }
 +
 +      priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER);
 +      if (priv->cert == NULL) {
 +              priv->cert = cryptoapi_find_cert(
 +                      name, CERT_SYSTEM_STORE_LOCAL_MACHINE);
 +      }
 +      if (priv->cert == NULL) {
 +              wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate "
 +                         "'%s'", name);
 +              goto err;
 +      }
 +
 +      cert = d2i_X509(NULL,
 +                      (const unsigned char **) &priv->cert->pbCertEncoded,
 +                      priv->cert->cbCertEncoded);
 +      if (cert == NULL) {
 +              wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER "
 +                         "encoding");
 +              goto err;
 +      }
 +
 +      if (!CryptAcquireCertificatePrivateKey(priv->cert,
 +                                             CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
 +                                             NULL, &priv->crypt_prov,
 +                                             &priv->key_spec,
 +                                             &priv->free_crypt_prov)) {
 +              cryptoapi_error("Failed to acquire a private key for the "
 +                              "certificate");
 +              goto err;
 +      }
 +
 +      rsa_meth->name = "Microsoft CryptoAPI RSA Method";
 +      rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc;
 +      rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec;
 +      rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc;
 +      rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec;
 +      rsa_meth->finish = cryptoapi_finish;
 +      rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
 +      rsa_meth->app_data = (char *) priv;
 +
 +      rsa = RSA_new();
 +      if (rsa == NULL) {
 +              SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,
 +                     ERR_R_MALLOC_FAILURE);
 +              goto err;
 +      }
 +
 +      if (!SSL_use_certificate(ssl, cert)) {
 +              RSA_free(rsa);
 +              rsa = NULL;
 +              goto err;
 +      }
 +      pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
 +      X509_free(cert);
 +      cert = NULL;
 +
 +      rsa->n = BN_dup(pub_rsa->n);
 +      rsa->e = BN_dup(pub_rsa->e);
 +      if (!RSA_set_method(rsa, rsa_meth))
 +              goto err;
 +
 +      if (!SSL_use_RSAPrivateKey(ssl, rsa))
 +              goto err;
 +      RSA_free(rsa);
 +
 +      return 0;
 +
 +err:
 +      if (cert)
 +              X509_free(cert);
 +      if (rsa)
 +              RSA_free(rsa);
 +      else {
 +              os_free(rsa_meth);
 +              cryptoapi_free_data(priv);
 +      }
 +      return -1;
 +}
 +
 +
 +static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
 +{
 +      HCERTSTORE cs;
 +      PCCERT_CONTEXT ctx = NULL;
 +      X509 *cert;
 +      char buf[128];
 +      const char *store;
 +#ifdef UNICODE
 +      WCHAR *wstore;
 +#endif /* UNICODE */
 +
 +      if (name == NULL || strncmp(name, "cert_store://", 13) != 0)
 +              return -1;
 +
 +      store = name + 13;
 +#ifdef UNICODE
 +      wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR));
 +      if (wstore == NULL)
 +              return -1;
 +      wsprintf(wstore, L"%S", store);
 +      cs = CertOpenSystemStore(0, wstore);
 +      os_free(wstore);
 +#else /* UNICODE */
 +      cs = CertOpenSystemStore(0, store);
 +#endif /* UNICODE */
 +      if (cs == NULL) {
 +              wpa_printf(MSG_DEBUG, "%s: failed to open system cert store "
 +                         "'%s': error=%d", __func__, store,
 +                         (int) GetLastError());
 +              return -1;
 +      }
 +
 +      while ((ctx = CertEnumCertificatesInStore(cs, ctx))) {
 +              cert = d2i_X509(NULL,
 +                              (const unsigned char **) &ctx->pbCertEncoded,
 +                              ctx->cbCertEncoded);
 +              if (cert == NULL) {
 +                      wpa_printf(MSG_INFO, "CryptoAPI: Could not process "
 +                                 "X509 DER encoding for CA cert");
 +                      continue;
 +              }
 +
 +              X509_NAME_oneline(X509_get_subject_name(cert), buf,
 +                                sizeof(buf));
 +              wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for "
 +                         "system certificate store: subject='%s'", buf);
 +
-               ENGINE_free(engine);
++              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");
 +              }
 +
 +              X509_free(cert);
 +      }
 +
 +      if (!CertCloseStore(cs, 0)) {
 +              wpa_printf(MSG_DEBUG, "%s: failed to close system cert store "
 +                         "'%s': error=%d", __func__, name + 13,
 +                         (int) GetLastError());
 +      }
 +
 +      return 0;
 +}
 +
 +
 +#else /* CONFIG_NATIVE_WINDOWS */
 +
 +static int tls_cryptoapi_cert(SSL *ssl, const char *name)
 +{
 +      return -1;
 +}
 +
 +#endif /* CONFIG_NATIVE_WINDOWS */
 +
 +
 +static void ssl_info_cb(const SSL *ssl, int where, int ret)
 +{
 +      const char *str;
 +      int w;
 +
 +      wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret);
 +      w = where & ~SSL_ST_MASK;
 +      if (w & SSL_ST_CONNECT)
 +              str = "SSL_connect";
 +      else if (w & SSL_ST_ACCEPT)
 +              str = "SSL_accept";
 +      else
 +              str = "undefined";
 +
 +      if (where & SSL_CB_LOOP) {
 +              wpa_printf(MSG_DEBUG, "SSL: %s:%s",
 +                         str, SSL_state_string_long(ssl));
 +      } else if (where & SSL_CB_ALERT) {
 +              struct tls_connection *conn = SSL_get_app_data((SSL *) ssl);
 +              wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s",
 +                         where & SSL_CB_READ ?
 +                         "read (remote end reported an error)" :
 +                         "write (local SSL3 detected an error)",
 +                         SSL_alert_type_string_long(ret),
 +                         SSL_alert_desc_string_long(ret));
 +              if ((ret >> 8) == SSL3_AL_FATAL) {
 +                      if (where & SSL_CB_READ)
 +                              conn->read_alerts++;
 +                      else
 +                              conn->write_alerts++;
 +              }
 +              if (conn->context->event_cb != NULL) {
 +                      union tls_event_data ev;
 +                      struct tls_context *context = conn->context;
 +                      os_memset(&ev, 0, sizeof(ev));
 +                      ev.alert.is_local = !(where & SSL_CB_READ);
 +                      ev.alert.type = SSL_alert_type_string_long(ret);
 +                      ev.alert.description = SSL_alert_desc_string_long(ret);
 +                      context->event_cb(context->cb_ctx, TLS_ALERT, &ev);
 +              }
 +      } else if (where & SSL_CB_EXIT && ret <= 0) {
 +              wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s",
 +                         str, ret == 0 ? "failed" : "error",
 +                         SSL_state_string_long(ssl));
 +      }
 +}
 +
 +
 +#ifndef OPENSSL_NO_ENGINE
 +/**
 + * tls_engine_load_dynamic_generic - load any openssl engine
 + * @pre: an array of commands and values that load an engine initialized
 + *       in the engine specific function
 + * @post: an array of commands and values that initialize an already loaded
 + *        engine (or %NULL if not required)
 + * @id: the engine id of the engine to load (only required if post is not %NULL
 + *
 + * This function is a generic function that loads any openssl engine.
 + *
 + * Returns: 0 on success, -1 on failure
 + */
 +static int tls_engine_load_dynamic_generic(const char *pre[],
 +                                         const char *post[], const char *id)
 +{
 +      ENGINE *engine;
 +      const char *dynamic_id = "dynamic";
 +
 +      engine = ENGINE_by_id(id);
 +      if (engine) {
-               return 0;
 +              wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
 +                         "available", id);
++              /*
++               * 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();
 +
 +      engine = ENGINE_by_id(dynamic_id);
 +      if (engine == NULL) {
 +              wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
 +                         dynamic_id,
 +                         ERR_error_string(ERR_get_error(), NULL));
 +              return -1;
 +      }
 +
 +      /* Perform the pre commands. This will load the engine. */
 +      while (pre && pre[0]) {
 +              wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]);
 +              if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) {
 +                      wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: "
 +                                 "%s %s [%s]", pre[0], pre[1],
 +                                 ERR_error_string(ERR_get_error(), NULL));
 +                      ENGINE_free(engine);
 +                      return -1;
 +              }
 +              pre += 2;
 +      }
 +
 +      /*
 +       * Free the reference to the "dynamic" engine. The loaded engine can
 +       * now be looked up using ENGINE_by_id().
 +       */
 +      ENGINE_free(engine);
 +
 +      engine = ENGINE_by_id(id);
 +      if (engine == NULL) {
 +              wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
 +                         id, ERR_error_string(ERR_get_error(), NULL));
 +              return -1;
 +      }
- #ifndef OPENSSL_NO_ENGINE
++ 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) {
 +                      wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:"
 +                              " %s %s [%s]", post[0], post[1],
 +                                 ERR_error_string(ERR_get_error(), NULL));
 +                      ENGINE_remove(engine);
 +                      ENGINE_free(engine);
 +                      return -1;
 +              }
 +              post += 2;
 +      }
 +      ENGINE_free(engine);
 +
 +      return 0;
 +}
 +
 +
 +/**
 + * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc
 + * @pkcs11_so_path: pksc11_so_path from the configuration
 + * @pcks11_module_path: pkcs11_module_path from the configuration
 + */
 +static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path,
 +                                        const char *pkcs11_module_path)
 +{
 +      char *engine_id = "pkcs11";
 +      const char *pre_cmd[] = {
 +              "SO_PATH", NULL /* pkcs11_so_path */,
 +              "ID", NULL /* engine_id */,
 +              "LIST_ADD", "1",
 +              /* "NO_VCHECK", "1", */
 +              "LOAD", NULL,
 +              NULL, NULL
 +      };
 +      const char *post_cmd[] = {
 +              "MODULE_PATH", NULL /* pkcs11_module_path */,
 +              NULL, NULL
 +      };
 +
 +      if (!pkcs11_so_path)
 +              return 0;
 +
 +      pre_cmd[1] = pkcs11_so_path;
 +      pre_cmd[3] = engine_id;
 +      if (pkcs11_module_path)
 +              post_cmd[1] = pkcs11_module_path;
 +      else
 +              post_cmd[0] = NULL;
 +
 +      wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s",
 +                 pkcs11_so_path);
 +
 +      return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id);
 +}
 +
 +
 +/**
 + * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc
 + * @opensc_so_path: opensc_so_path from the configuration
 + */
 +static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
 +{
 +      char *engine_id = "opensc";
 +      const char *pre_cmd[] = {
 +              "SO_PATH", NULL /* opensc_so_path */,
 +              "ID", NULL /* engine_id */,
 +              "LIST_ADD", "1",
 +              "LOAD", NULL,
 +              NULL, NULL
 +      };
 +
 +      if (!opensc_so_path)
 +              return 0;
 +
 +      pre_cmd[1] = opensc_so_path;
 +      pre_cmd[3] = engine_id;
 +
 +      wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s",
 +                 opensc_so_path);
 +
 +      return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id);
 +}
 +#endif /* OPENSSL_NO_ENGINE */
 +
 +
 +static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess)
 +{
 +      struct wpabuf *buf;
 +
 +      if (tls_ex_idx_session < 0)
 +              return;
 +      buf = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
 +      if (!buf)
 +              return;
 +      wpa_printf(MSG_DEBUG,
 +                 "OpenSSL: Free application session data %p (sess %p)",
 +                 buf, sess);
 +      wpabuf_free(buf);
 +
 +      SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
 +}
 +
 +
 +void * tls_init(const struct tls_config *conf)
 +{
 +      struct tls_data *data;
 +      SSL_CTX *ssl;
 +      struct tls_context *context;
 +      const char *ciphers;
 +
 +      if (tls_openssl_ref_count == 0) {
 +              tls_global = context = tls_context_new(conf);
 +              if (context == NULL)
 +                      return NULL;
 +#ifdef CONFIG_FIPS
 +#ifdef OPENSSL_FIPS
 +              if (conf && conf->fips_mode) {
 +                      static int fips_enabled = 0;
 +
 +                      if (!fips_enabled && !FIPS_mode_set(1)) {
 +                              wpa_printf(MSG_ERROR, "Failed to enable FIPS "
 +                                         "mode");
 +                              ERR_load_crypto_strings();
 +                              ERR_print_errors_fp(stderr);
 +                              os_free(tls_global);
 +                              tls_global = NULL;
 +                              return NULL;
 +                      } else {
 +                              wpa_printf(MSG_INFO, "Running in FIPS mode");
 +                              fips_enabled = 1;
 +                      }
 +              }
 +#else /* OPENSSL_FIPS */
 +              if (conf && conf->fips_mode) {
 +                      wpa_printf(MSG_ERROR, "FIPS mode requested, but not "
 +                                 "supported");
 +                      os_free(tls_global);
 +                      tls_global = NULL;
 +                      return NULL;
 +              }
 +#endif /* OPENSSL_FIPS */
 +#endif /* CONFIG_FIPS */
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
 +              SSL_load_error_strings();
 +              SSL_library_init();
 +#ifndef OPENSSL_NO_SHA256
 +              EVP_add_digest(EVP_sha256());
 +#endif /* OPENSSL_NO_SHA256 */
 +              /* TODO: if /dev/urandom is available, PRNG is seeded
 +               * automatically. If this is not the case, random data should
 +               * be added here. */
 +
 +#ifdef PKCS12_FUNCS
 +#ifndef OPENSSL_NO_RC2
 +              /*
 +               * 40-bit RC2 is commonly used in PKCS#12 files, so enable it.
 +               * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8
 +               * versions, but it looks like OpenSSL 1.0.0 does not do that
 +               * anymore.
 +               */
 +              EVP_add_cipher(EVP_rc2_40_cbc());
 +#endif /* OPENSSL_NO_RC2 */
 +              PKCS12_PBE_add();
 +#endif  /* PKCS12_FUNCS */
++#endif /* < 1.1.0 */
 +      } else {
 +              context = tls_context_new(conf);
 +              if (context == NULL)
 +                      return NULL;
 +      }
 +      tls_openssl_ref_count++;
 +
 +      data = os_zalloc(sizeof(*data));
 +      if (data)
 +              ssl = SSL_CTX_new(SSLv23_method());
 +      else
 +              ssl = NULL;
 +      if (ssl == NULL) {
 +              tls_openssl_ref_count--;
 +              if (context != tls_global)
 +                      os_free(context);
 +              if (tls_openssl_ref_count == 0) {
 +                      os_free(tls_global);
 +                      tls_global = NULL;
 +              }
++              os_free(data);
 +              return NULL;
 +      }
 +      data->ssl = ssl;
 +      if (conf)
 +              data->tls_session_lifetime = conf->tls_session_lifetime;
 +
 +      SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
 +      SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
 +
 +      SSL_CTX_set_info_callback(ssl, ssl_info_cb);
 +      SSL_CTX_set_app_data(ssl, context);
 +      if (data->tls_session_lifetime > 0) {
 +              SSL_CTX_set_quiet_shutdown(ssl, 1);
 +              /*
 +               * Set default context here. In practice, this will be replaced
 +               * by the per-EAP method context in tls_connection_set_verify().
 +               */
 +              SSL_CTX_set_session_id_context(ssl, (u8 *) "hostapd", 7);
 +              SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_SERVER);
 +              SSL_CTX_set_timeout(ssl, data->tls_session_lifetime);
 +              SSL_CTX_sess_set_remove_cb(ssl, remove_session_cb);
 +      } else {
 +              SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF);
 +      }
 +
 +      if (tls_ex_idx_session < 0) {
 +              tls_ex_idx_session = SSL_SESSION_get_ex_new_index(
 +                      0, NULL, NULL, NULL, NULL);
 +              if (tls_ex_idx_session < 0) {
 +                      tls_deinit(data);
 +                      return NULL;
 +              }
 +      }
 +
 +#ifndef OPENSSL_NO_ENGINE
 +      wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
 +      ERR_load_ENGINE_strings();
 +      ENGINE_load_dynamic();
 +
 +      if (conf &&
 +          (conf->opensc_engine_path || conf->pkcs11_engine_path ||
 +           conf->pkcs11_module_path)) {
 +              if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
 +                  tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
 +                                                 conf->pkcs11_module_path)) {
 +                      tls_deinit(data);
 +                      return NULL;
 +              }
 +      }
 +#endif /* OPENSSL_NO_ENGINE */
 +
 +      if (conf && conf->openssl_ciphers)
 +              ciphers = conf->openssl_ciphers;
 +      else
 +              ciphers = "DEFAULT:!EXP:!LOW";
 +      if (SSL_CTX_set_cipher_list(ssl, ciphers) != 1) {
 +              wpa_printf(MSG_ERROR,
 +                         "OpenSSL: Failed to set cipher string '%s'",
 +                         ciphers);
 +              tls_deinit(data);
 +              return NULL;
 +      }
 +
 +      return data;
 +}
 +
 +
 +void tls_deinit(void *ssl_ctx)
 +{
 +      struct tls_data *data = ssl_ctx;
 +      SSL_CTX *ssl = data->ssl;
 +      struct tls_context *context = SSL_CTX_get_app_data(ssl);
 +      if (context != tls_global)
 +              os_free(context);
 +      if (data->tls_session_lifetime > 0)
 +              SSL_CTX_flush_sessions(ssl, 0);
 +      SSL_CTX_free(ssl);
 +
 +      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.)
 +//// #ifndef OPENSSL_NO_ENGINE
 +////          ENGINE_cleanup();
 +//// #endif /* OPENSSL_NO_ENGINE */
 +////          CRYPTO_cleanup_all_ex_data();
 +              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);
 +              tls_global = NULL;
 +      }
 +
 +      os_free(data);
 +}
 +
 +
 +#ifndef OPENSSL_NO_ENGINE
 +
 +/* Cryptoki return values */
 +#define CKR_PIN_INCORRECT 0x000000a0
 +#define CKR_PIN_INVALID 0x000000a1
 +#define CKR_PIN_LEN_RANGE 0x000000a2
 +
 +/* libp11 */
 +#define ERR_LIB_PKCS11        ERR_LIB_USER
 +
 +static int tls_is_pin_error(unsigned int err)
 +{
 +      return ERR_GET_LIB(err) == ERR_LIB_PKCS11 &&
 +              (ERR_GET_REASON(err) == CKR_PIN_INCORRECT ||
 +               ERR_GET_REASON(err) == CKR_PIN_INVALID ||
 +               ERR_GET_REASON(err) == CKR_PIN_LEN_RANGE);
 +}
 +
 +#endif /* OPENSSL_NO_ENGINE */
 +
 +
++#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) {
 +              wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
 +              return -1;
 +      }
 +
 +      ERR_clear_error();
 +#ifdef ANDROID
 +      ENGINE_load_dynamic();
 +#endif
 +      conn->engine = ENGINE_by_id(engine_id);
 +      if (!conn->engine) {
 +              wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]",
 +                         engine_id, ERR_error_string(ERR_get_error(), NULL));
 +              goto err;
 +      }
 +      if (ENGINE_init(conn->engine) != 1) {
 +              wpa_printf(MSG_ERROR, "ENGINE: engine init failed "
 +                         "(engine: %s) [%s]", engine_id,
 +                         ERR_error_string(ERR_get_error(), NULL));
 +              goto err;
 +      }
 +      wpa_printf(MSG_DEBUG, "ENGINE: engine initialized");
 +
 +#ifndef ANDROID
 +      if (pin && ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
 +              wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]",
 +                         ERR_error_string(ERR_get_error(), NULL));
 +              goto err;
 +      }
 +#endif
 +      if (key_id) {
 +              /*
 +               * Ensure that the ENGINE does not attempt to use the OpenSSL
 +               * UI system to obtain a PIN, if we didn't provide one.
 +               */
 +              struct {
 +                      const void *password;
 +                      const char *prompt_info;
 +              } key_cb = { "", NULL };
 +
 +              /* load private key first in-case PIN is required for cert */
 +              conn->private_key = ENGINE_load_private_key(conn->engine,
 +                                                          key_id, NULL,
 +                                                          &key_cb);
 +              if (!conn->private_key) {
 +                      unsigned long err = ERR_get_error();
 +
 +                      wpa_printf(MSG_ERROR,
 +                                 "ENGINE: cannot load private key with id '%s' [%s]",
 +                                 key_id,
 +                                 ERR_error_string(err, NULL));
 +                      if (tls_is_pin_error(err))
 +                              ret = TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN;
 +                      else
 +                              ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
 +                      goto err;
 +              }
 +      }
 +
 +      /* handle a certificate and/or CA certificate */
 +      if (cert_id || ca_cert_id) {
 +              const char *cmd_name = "LOAD_CERT_CTRL";
 +
 +              /* test if the engine supports a LOAD_CERT_CTRL */
 +              if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
 +                               0, (void *)cmd_name, NULL)) {
 +                      wpa_printf(MSG_ERROR, "ENGINE: engine does not support"
 +                                 " loading certificates");
 +                      ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
 +                      goto err;
 +              }
 +      }
 +
 +      return 0;
 +
 +err:
 +      if (conn->engine) {
 +              ENGINE_free(conn->engine);
 +              conn->engine = NULL;
 +      }
 +
 +      if (conn->private_key) {
 +              EVP_PKEY_free(conn->private_key);
 +              conn->private_key = NULL;
 +      }
 +
 +      return ret;
 +#else /* OPENSSL_NO_ENGINE */
 +      return 0;
 +#endif /* OPENSSL_NO_ENGINE */
 +}
 +
 +
 +static void tls_engine_deinit(struct tls_connection *conn)
 +{
- #endif /* 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;
 +      }
-       wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d",
-                  write_p ? "TX" : "RX", version, content_type);
++#endif /* ANDROID || !OPENSSL_NO_ENGINE */
 +}
 +
 +
 +int tls_get_errors(void *ssl_ctx)
 +{
 +      int count = 0;
 +      unsigned long err;
 +
 +      while ((err = ERR_get_error())) {
 +              wpa_printf(MSG_INFO, "TLS - SSL error: %s",
 +                         ERR_error_string(err, NULL));
 +              count++;
 +      }
 +
 +      return count;
 +}
 +
 +
++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;
 +
-       if (conn->cert_probe || context->cert_in_cb) {
++      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);
 +              if (payload_len + 3 > len) {
 +                      wpa_printf(MSG_ERROR, "OpenSSL: Heartbeat attack detected");
 +                      conn->invalid_hb_used = 1;
 +              }
 +      }
 +}
 +
 +
 +struct tls_connection * tls_connection_init(void *ssl_ctx)
 +{
 +      struct tls_data *data = ssl_ctx;
 +      SSL_CTX *ssl = data->ssl;
 +      struct tls_connection *conn;
 +      long options;
 +      struct tls_context *context = SSL_CTX_get_app_data(ssl);
 +
 +      conn = os_zalloc(sizeof(*conn));
 +      if (conn == NULL)
 +              return NULL;
 +      conn->ssl_ctx = ssl;
 +      conn->ssl = SSL_new(ssl);
 +      if (conn->ssl == NULL) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Failed to initialize new SSL connection");
 +              os_free(conn);
 +              return NULL;
 +      }
 +
 +      conn->context = context;
 +      SSL_set_app_data(conn->ssl, conn);
 +      SSL_set_msg_callback(conn->ssl, tls_msg_cb);
 +      SSL_set_msg_callback_arg(conn->ssl, conn);
 +      options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
 +              SSL_OP_SINGLE_DH_USE;
 +#ifdef SSL_OP_NO_COMPRESSION
 +      options |= SSL_OP_NO_COMPRESSION;
 +#endif /* SSL_OP_NO_COMPRESSION */
 +      SSL_set_options(conn->ssl, options);
 +
 +      conn->ssl_in = BIO_new(BIO_s_mem());
 +      if (!conn->ssl_in) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Failed to create a new BIO for ssl_in");
 +              SSL_free(conn->ssl);
 +              os_free(conn);
 +              return NULL;
 +      }
 +
 +      conn->ssl_out = BIO_new(BIO_s_mem());
 +      if (!conn->ssl_out) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Failed to create a new BIO for ssl_out");
 +              SSL_free(conn->ssl);
 +              BIO_free(conn->ssl_in);
 +              os_free(conn);
 +              return NULL;
 +      }
 +
 +      SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out);
 +
 +      return conn;
 +}
 +
 +
 +void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
 +{
 +      if (conn == NULL)
 +              return;
 +      if (conn->success_data) {
 +              /*
 +               * Make sure ssl_clear_bad_session() does not remove this
 +               * session.
 +               */
 +              SSL_set_quiet_shutdown(conn->ssl, 1);
 +              SSL_shutdown(conn->ssl);
 +      }
 +      SSL_free(conn->ssl);
 +      tls_engine_deinit(conn);
 +      os_free(conn->subject_match);
 +      os_free(conn->altsubject_match);
 +      os_free(conn->suffix_match);
 +      os_free(conn->domain_match);
 +      os_free(conn->session_ticket);
 +      os_free(conn);
 +}
 +
 +
 +int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
 +{
 +      return conn ? SSL_is_init_finished(conn->ssl) : 0;
 +}
 +
 +
 +int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
 +{
 +      if (conn == NULL)
 +              return -1;
 +
 +      /* Shutdown previous TLS connection without notifying the peer
 +       * because the connection was already terminated in practice
 +       * and "close notify" shutdown alert would confuse AS. */
 +      SSL_set_quiet_shutdown(conn->ssl, 1);
 +      SSL_shutdown(conn->ssl);
 +      return SSL_clear(conn->ssl) == 1 ? 0 : -1;
 +}
 +
 +
 +static int tls_match_altsubject_component(X509 *cert, int type,
 +                                        const char *value, size_t len)
 +{
 +      GENERAL_NAME *gen;
 +      void *ext;
 +      int found = 0;
 +      stack_index_t i;
 +
 +      ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
 +
 +      for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
 +              gen = sk_GENERAL_NAME_value(ext, i);
 +              if (gen->type != type)
 +                      continue;
 +              if (os_strlen((char *) gen->d.ia5->data) == len &&
 +                  os_memcmp(value, gen->d.ia5->data, len) == 0)
 +                      found++;
 +      }
 +
++      sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
++
 +      return found;
 +}
 +
 +
 +static int tls_match_altsubject(X509 *cert, const char *match)
 +{
 +      int type;
 +      const char *pos, *end;
 +      size_t len;
 +
 +      pos = match;
 +      do {
 +              if (os_strncmp(pos, "EMAIL:", 6) == 0) {
 +                      type = GEN_EMAIL;
 +                      pos += 6;
 +              } else if (os_strncmp(pos, "DNS:", 4) == 0) {
 +                      type = GEN_DNS;
 +                      pos += 4;
 +              } else if (os_strncmp(pos, "URI:", 4) == 0) {
 +                      type = GEN_URI;
 +                      pos += 4;
 +              } else {
 +                      wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName "
 +                                 "match '%s'", pos);
 +                      return 0;
 +              }
 +              end = os_strchr(pos, ';');
 +              while (end) {
 +                      if (os_strncmp(end + 1, "EMAIL:", 6) == 0 ||
 +                          os_strncmp(end + 1, "DNS:", 4) == 0 ||
 +                          os_strncmp(end + 1, "URI:", 4) == 0)
 +                              break;
 +                      end = os_strchr(end + 1, ';');
 +              }
 +              if (end)
 +                      len = end - pos;
 +              else
 +                      len = os_strlen(pos);
 +              if (tls_match_altsubject_component(cert, type, pos, len) > 0)
 +                      return 1;
 +              pos = end + 1;
 +      } while (end);
 +
 +      return 0;
 +}
 +
 +
 +#ifndef CONFIG_NATIVE_WINDOWS
 +static int domain_suffix_match(const u8 *val, size_t len, const char *match,
 +                             int full)
 +{
 +      size_t i, match_len;
 +
 +      /* Check for embedded nuls that could mess up suffix matching */
 +      for (i = 0; i < len; i++) {
 +              if (val[i] == '\0') {
 +                      wpa_printf(MSG_DEBUG, "TLS: Embedded null in a string - reject");
 +                      return 0;
 +              }
 +      }
 +
 +      match_len = os_strlen(match);
 +      if (match_len > len || (full && match_len != len))
 +              return 0;
 +
 +      if (os_strncasecmp((const char *) val + len - match_len, match,
 +                         match_len) != 0)
 +              return 0; /* no match */
 +
 +      if (match_len == len)
 +              return 1; /* exact match */
 +
 +      if (val[len - match_len - 1] == '.')
 +              return 1; /* full label match completes suffix match */
 +
 +      wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match");
 +      return 0;
 +}
 +#endif /* CONFIG_NATIVE_WINDOWS */
 +
 +
 +static int tls_match_suffix(X509 *cert, const char *match, int full)
 +{
 +#ifdef CONFIG_NATIVE_WINDOWS
 +      /* wincrypt.h has conflicting X509_NAME definition */
 +      return -1;
 +#else /* CONFIG_NATIVE_WINDOWS */
 +      GENERAL_NAME *gen;
 +      void *ext;
 +      int i;
 +      stack_index_t j;
 +      int dns_name = 0;
 +      X509_NAME *name;
 +
 +      wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s",
 +                 full ? "": "suffix ", match);
 +
 +      ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
 +
 +      for (j = 0; ext && j < sk_GENERAL_NAME_num(ext); j++) {
 +              gen = sk_GENERAL_NAME_value(ext, j);
 +              if (gen->type != GEN_DNS)
 +                      continue;
 +              dns_name++;
 +              wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
 +                                gen->d.dNSName->data,
 +                                gen->d.dNSName->length);
 +              if (domain_suffix_match(gen->d.dNSName->data,
 +                                      gen->d.dNSName->length, match, 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");
 +              return 0;
 +      }
 +
 +      name = X509_get_subject_name(cert);
 +      i = -1;
 +      for (;;) {
 +              X509_NAME_ENTRY *e;
 +              ASN1_STRING *cn;
 +
 +              i = X509_NAME_get_index_by_NID(name, NID_commonName, i);
 +              if (i == -1)
 +                      break;
 +              e = X509_NAME_get_entry(name, i);
 +              if (e == NULL)
 +                      continue;
 +              cn = X509_NAME_ENTRY_get_data(e);
 +              if (cn == NULL)
 +                      continue;
 +              wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
 +                                cn->data, cn->length);
 +              if (domain_suffix_match(cn->data, cn->length, match, full) == 1)
 +              {
 +                      wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
 +                                 full ? "Match" : "Suffix match");
 +                      return 1;
 +              }
 +      }
 +
 +      wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
 +                 full ? "": "suffix ");
 +      return 0;
 +#endif /* CONFIG_NATIVE_WINDOWS */
 +}
 +
 +
 +static enum tls_fail_reason openssl_tls_fail_reason(int err)
 +{
 +      switch (err) {
 +      case X509_V_ERR_CERT_REVOKED:
 +              return TLS_FAIL_REVOKED;
 +      case X509_V_ERR_CERT_NOT_YET_VALID:
 +      case X509_V_ERR_CRL_NOT_YET_VALID:
 +              return TLS_FAIL_NOT_YET_VALID;
 +      case X509_V_ERR_CERT_HAS_EXPIRED:
 +      case X509_V_ERR_CRL_HAS_EXPIRED:
 +              return TLS_FAIL_EXPIRED;
 +      case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
 +      case X509_V_ERR_UNABLE_TO_GET_CRL:
 +      case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
 +      case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
 +      case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
 +      case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
 +      case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
 +      case X509_V_ERR_CERT_CHAIN_TOO_LONG:
 +      case X509_V_ERR_PATH_LENGTH_EXCEEDED:
 +      case X509_V_ERR_INVALID_CA:
 +              return TLS_FAIL_UNTRUSTED;
 +      case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
 +      case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
 +      case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
 +      case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
 +      case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
 +      case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
 +      case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
 +      case X509_V_ERR_CERT_UNTRUSTED:
 +      case X509_V_ERR_CERT_REJECTED:
 +              return TLS_FAIL_BAD_CERTIFICATE;
 +      default:
 +              return TLS_FAIL_UNSPECIFIED;
 +      }
 +}
 +
 +
 +static struct wpabuf * get_x509_cert(X509 *cert)
 +{
 +      struct wpabuf *buf;
 +      u8 *tmp;
 +
 +      int cert_len = i2d_X509(cert, NULL);
 +      if (cert_len <= 0)
 +              return NULL;
 +
 +      buf = wpabuf_alloc(cert_len);
 +      if (buf == NULL)
 +              return NULL;
 +
 +      tmp = wpabuf_put(buf, cert_len);
 +      i2d_X509(cert, &tmp);
 +      return buf;
 +}
 +
 +
 +static void openssl_tls_fail_event(struct tls_connection *conn,
 +                                 X509 *err_cert, int err, int depth,
 +                                 const char *subject, const char *err_str,
 +                                 enum tls_fail_reason reason)
 +{
 +      union tls_event_data ev;
 +      struct wpabuf *cert = NULL;
 +      struct tls_context *context = conn->context;
 +
 +      if (context->event_cb == NULL)
 +              return;
 +
 +      cert = get_x509_cert(err_cert);
 +      os_memset(&ev, 0, sizeof(ev));
 +      ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
 +              reason : openssl_tls_fail_reason(err);
 +      ev.cert_fail.depth = depth;
 +      ev.cert_fail.subject = subject;
 +      ev.cert_fail.reason_txt = err_str;
 +      ev.cert_fail.cert = cert;
 +      context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
 +      wpabuf_free(cert);
 +}
 +
 +
 +static void openssl_tls_cert_event(struct tls_connection *conn,
 +                                 X509 *err_cert, int depth,
 +                                 const char *subject)
 +{
 +      struct wpabuf *cert = NULL;
 +      union tls_event_data ev;
 +      struct tls_context *context = conn->context;
 +      char *altsubject[TLS_MAX_ALT_SUBJECT];
 +      int alt, num_altsubject = 0;
 +      GENERAL_NAME *gen;
 +      void *ext;
 +      stack_index_t i;
 +#ifdef CONFIG_SHA256
 +      u8 hash[32];
 +#endif /* CONFIG_SHA256 */
 +
 +      if (context->event_cb == NULL)
 +              return;
 +
 +      os_memset(&ev, 0, sizeof(ev));
-       if (preverify_ok && context->event_cb != NULL)
++      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;
 +      }
 +#ifdef CONFIG_SHA256
 +      if (cert) {
 +              const u8 *addr[1];
 +              size_t len[1];
 +              addr[0] = wpabuf_head(cert);
 +              len[0] = wpabuf_len(cert);
 +              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;
 +      ev.peer_cert.subject = subject;
 +
 +      ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL);
 +      for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
 +              char *pos;
 +
 +              if (num_altsubject == TLS_MAX_ALT_SUBJECT)
 +                      break;
 +              gen = sk_GENERAL_NAME_value(ext, i);
 +              if (gen->type != GEN_EMAIL &&
 +                  gen->type != GEN_DNS &&
 +                  gen->type != GEN_URI)
 +                      continue;
 +
 +              pos = os_malloc(10 + gen->d.ia5->length + 1);
 +              if (pos == NULL)
 +                      break;
 +              altsubject[num_altsubject++] = pos;
 +
 +              switch (gen->type) {
 +              case GEN_EMAIL:
 +                      os_memcpy(pos, "EMAIL:", 6);
 +                      pos += 6;
 +                      break;
 +              case GEN_DNS:
 +                      os_memcpy(pos, "DNS:", 4);
 +                      pos += 4;
 +                      break;
 +              case GEN_URI:
 +                      os_memcpy(pos, "URI:", 4);
 +                      pos += 4;
 +                      break;
 +              }
 +
 +              os_memcpy(pos, gen->d.ia5->data, gen->d.ia5->length);
 +              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];
 +      ev.peer_cert.num_altsubject = num_altsubject;
 +
 +      context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
 +      wpabuf_free(cert);
 +      for (alt = 0; alt < num_altsubject; alt++)
 +              os_free(altsubject[alt]);
 +}
 +
 +
 +static void debug_print_cert(X509 *cert, const char *title);
 +
 +static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
 +{
 +      char buf[256];
 +      X509 *err_cert;
 +      int err, depth;
 +      SSL *ssl;
 +      struct tls_connection *conn;
 +      struct tls_context *context;
 +      char *match, *altmatch, *suffix_match, *domain_match;
 +      const char *err_str;
 +
 +      err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
 +      if (!err_cert)
 +              return 0;
 +
 +    // debug_print_cert(err_cert, "\n\n***** tls_verify_cb:\n");
 +
 +      err = X509_STORE_CTX_get_error(x509_ctx);
 +      depth = X509_STORE_CTX_get_error_depth(x509_ctx);
 +      ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
 +                                       SSL_get_ex_data_X509_STORE_CTX_idx());
 +      X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
 +
 +      conn = SSL_get_app_data(ssl);
 +      if (conn == NULL)
 +              return 0;
 +
 +      if (depth == 0)
 +              conn->peer_cert = err_cert;
 +      else if (depth == 1)
 +              conn->peer_issuer = err_cert;
 +      else if (depth == 2)
 +              conn->peer_issuer_issuer = err_cert;
 +
 +      wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb(enter) - preverify_ok=%d "
 +                 "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s' server_cert_cb=%p server_cert_only=%d",
 +                 preverify_ok, err, X509_verify_cert_error_string(err),
 +               conn->ca_cert_verify, depth, buf, conn->server_cert_cb, conn->server_cert_only);
 +
 +
 +      context = conn->context;
 +      match = conn->subject_match;
 +      altmatch = conn->altsubject_match;
 +      suffix_match = conn->suffix_match;
 +      domain_match = conn->domain_match;
 +
 +      if (!preverify_ok && !conn->ca_cert_verify)
 +              preverify_ok = 1;
 +
 +      if (!preverify_ok && depth > 0 && conn->server_cert_only) {
 +        wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb: allowing cert because depth > 0 && conn->server_cert_only\n");
 +              preverify_ok = 1;
 +    }
 +      if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) &&
 +          (err == X509_V_ERR_CERT_HAS_EXPIRED ||
 +           err == X509_V_ERR_CERT_NOT_YET_VALID)) {
 +              wpa_printf(MSG_DEBUG, "tls_verify_cb: OpenSSL: Ignore certificate validity "
 +                         "time mismatch");
 +              preverify_ok = 1;
 +      }
 +
 +      err_str = X509_verify_cert_error_string(err);
 +
 +#ifdef CONFIG_SHA256
 +      if (depth == 0) {
 +        if (conn->server_cert_cb) {
 +            preverify_ok = conn->server_cert_cb(preverify_ok, err_cert, conn->server_cert_ctx);
 +            wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb: server_cert_cb returned %d", preverify_ok);
 +        }
 +        if (conn->server_cert_only) {
 +            /*
 +             * Do not require preverify_ok so we can explicity allow otherwise
 +             * invalid pinned server certificates.
 +             */
 +            struct wpabuf *cert;
 +            cert = get_x509_cert(err_cert);
 +            if (!cert) {
 +                wpa_printf(MSG_DEBUG, "tls_verify_cb: OpenSSL: Could not fetch "
 +                           "server certificate data");
 +                preverify_ok = 0;
 +            } else {
 +                u8 hash[32];
 +                const u8 *addr[1];
 +                size_t len[1];
 +                addr[0] = wpabuf_head(cert);
 +                len[0] = wpabuf_len(cert);
 +                if (sha256_vector(1, addr, len, hash) < 0 ||
 +                    os_memcmp(conn->srv_cert_hash, hash, 32) != 0) {
 +                    err_str = "Server certificate mismatch";
 +                    err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
 +                    preverify_ok = 0;
 +                } else if (!preverify_ok) {
 +                    /*
 +                     * Certificate matches pinned certificate, allow
 +                     * regardless of other problems.
 +                     */
 +                    wpa_printf(MSG_DEBUG,
 +                               "tls_verify_cb: OpenSSL: Ignore validation issues for a pinned server certificate");
 +                    preverify_ok = 1;
 +                }
 +                wpabuf_free(cert);
 +            }
 +        }
 +    }
 +#endif /* CONFIG_SHA256 */
 +
 +      if (!preverify_ok) {
 +              wpa_printf(MSG_WARNING, "tls_verify_cb: TLS: Certificate verification failed,"
 +                         " error %d (%s) depth %d for '%s'", err, err_str,
 +                         depth, buf);
 +              openssl_tls_fail_event(conn, err_cert, err, depth, buf,
 +                                     err_str, TLS_FAIL_UNSPECIFIED);
 +              return preverify_ok;
 +      }
 +
 +      wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb(exit) - preverify_ok=%d "
 +                 "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
 +                 preverify_ok, err, err_str,
 +                 conn->ca_cert_verify, depth, buf);
 +      if (depth == 0 && match && os_strstr(buf, match) == NULL) {
 +              wpa_printf(MSG_WARNING, "tls_verify_cb: TLS: Subject '%s' did not "
 +                         "match with '%s'", buf, match);
 +              preverify_ok = 0;
 +              openssl_tls_fail_event(conn, err_cert, err, depth, buf,
 +                                     "Subject mismatch",
 +                                     TLS_FAIL_SUBJECT_MISMATCH);
 +      } else if (depth == 0 && altmatch &&
 +                 !tls_match_altsubject(err_cert, altmatch)) {
 +              wpa_printf(MSG_WARNING, "tls_verify_cb: TLS: altSubjectName match "
 +                         "'%s' not found", altmatch);
 +              preverify_ok = 0;
 +              openssl_tls_fail_event(conn, err_cert, err, depth, buf,
 +                                     "AltSubject mismatch",
 +                                     TLS_FAIL_ALTSUBJECT_MISMATCH);
 +      } else if (depth == 0 && suffix_match &&
 +                 !tls_match_suffix(err_cert, suffix_match, 0)) {
 +              wpa_printf(MSG_WARNING, "tls_verify_cb: TLS: Domain suffix match '%s' not found",
 +                         suffix_match);
 +              preverify_ok = 0;
 +              openssl_tls_fail_event(conn, err_cert, err, depth, buf,
 +                                     "Domain suffix mismatch",
 +                                     TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
 +      } else if (depth == 0 && domain_match &&
 +                 !tls_match_suffix(err_cert, domain_match, 1)) {
 +              wpa_printf(MSG_WARNING, "tls_verify_cb: TLS: Domain match '%s' not found",
 +                         domain_match);
 +              preverify_ok = 0;
 +              openssl_tls_fail_event(conn, err_cert, err, depth, buf,
 +                                     "Domain mismatch",
 +                                     TLS_FAIL_DOMAIN_MISMATCH);
 +      } else
 +              openssl_tls_cert_event(conn, err_cert, depth, buf);
 +
 +      if (conn->cert_probe && preverify_ok && depth == 0) {
 +              wpa_printf(MSG_DEBUG, "tls_verify_cb: OpenSSL: Reject server certificate "
 +                         "on probe-only run");
 +              preverify_ok = 0;
 +              openssl_tls_fail_event(conn, err_cert, err, depth, buf,
 +                                     "Server certificate chain probe",
 +                                     TLS_FAIL_SERVER_CHAIN_PROBE);
 +      }
 +
-               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)
++#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);
 +
 +      return preverify_ok;
 +}
 +
 +
 +#ifndef OPENSSL_NO_STDIO
 +static int tls_load_ca_der(struct tls_data *data, const char *ca_cert)
 +{
 +      SSL_CTX *ssl_ctx = data->ssl;
 +      X509_LOOKUP *lookup;
 +      int ret = 0;
 +
 +      lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(ssl_ctx),
 +                                     X509_LOOKUP_file());
 +      if (lookup == NULL) {
 +              tls_show_errors(MSG_WARNING, __func__,
 +                              "Failed add lookup for X509 store");
 +              return -1;
 +      }
 +
 +      if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) {
 +              unsigned long err = ERR_peek_error();
 +              tls_show_errors(MSG_WARNING, __func__,
 +                              "Failed load CA in DER format");
 +              if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
 +                  ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
 +                                 "cert already in hash table error",
 +                                 __func__);
 +              } else
 +                      ret = -1;
 +      }
 +
 +      return ret;
 +}
 +#endif /* OPENSSL_NO_STDIO */
 +
 +
 +static int tls_connection_ca_cert(struct tls_data *data,
 +                                  struct tls_connection *conn,
 +                                  const char *ca_cert, const u8 *ca_cert_blob,
 +                                  size_t ca_cert_blob_len, const char *ca_path,
 +                                  int (*server_cert_cb)(int ok_so_far, X509* cert, void *ca_ctx),
 +                                  void *server_cert_ctx)
 +{
 +      SSL_CTX *ssl_ctx = data->ssl;
 +      X509_STORE *store;
 +
 +      /*
 +       * Remove previously configured trusted CA certificates before adding
 +       * new ones.
 +       */
 +      store = X509_STORE_new();
 +      if (store == NULL) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
 +                         "certificate store", __func__);
 +              return -1;
 +      }
 +      SSL_CTX_set_cert_store(ssl_ctx, store);
 +
 +      SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
 +      conn->ca_cert_verify = 1;
 +    conn->server_cert_cb = server_cert_cb;
 +    conn->server_cert_ctx = server_cert_ctx;
 +
 +      if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate "
 +                         "chain; setting conn->ca_cert_verify=0");
 +              conn->cert_probe = 1;
 +              conn->ca_cert_verify = 0;
 +              return 0;
 +      }
 +
 +      if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) {
 +#ifdef CONFIG_SHA256
 +              const char *pos = ca_cert + 7;
 +              if (os_strncmp(pos, "server/sha256/", 14) != 0) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert "
 +                                 "hash value '%s'", ca_cert);
 +                      return -1;
 +              }
 +              pos += 14;
 +              if (os_strlen(pos) != 32 * 2) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 "
 +                                 "hash length in ca_cert '%s'", ca_cert);
 +                      return -1;
 +              }
 +              if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash "
 +                                 "value in ca_cert '%s'", ca_cert);
 +                      return -1;
 +              }
 +              conn->server_cert_only = 1;
 +              wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server "
 +                         "certificate match");
 +              return 0;
 +#else /* CONFIG_SHA256 */
 +              wpa_printf(MSG_INFO, "No SHA256 included in the build - "
 +                         "cannot validate server certificate hash");
 +              return -1;
 +#endif /* CONFIG_SHA256 */
 +      }
 +
 +      if (ca_cert_blob) {
 +              X509 *cert = d2i_X509(NULL,
 +                                    (const unsigned char **) &ca_cert_blob,
 +                                    ca_cert_blob_len);
 +              if (cert == NULL) {
 +                      tls_show_errors(MSG_WARNING, __func__,
 +                                      "Failed to parse ca_cert_blob");
 +                      return -1;
 +              }
 +
 +              if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
 +                                       cert)) {
 +                      unsigned long err = ERR_peek_error();
 +                      tls_show_errors(MSG_WARNING, __func__,
 +                                      "Failed to add ca_cert_blob to "
 +                                      "certificate store");
 +                      if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
 +                          ERR_GET_REASON(err) ==
 +                          X509_R_CERT_ALREADY_IN_HASH_TABLE) {
 +                              wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
 +                                         "cert already in hash table error",
 +                                         __func__);
 +                      } else {
 +                              X509_free(cert);
 +                              return -1;
 +                      }
 +              }
 +              X509_free(cert);
 +              wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob "
 +                         "to certificate store", __func__);
 +              return 0;
 +      }
 +
 +#ifdef ANDROID
++      /* Single alias */
 +      if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 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);
++              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;
++      }
 +
-               sk_X509_INFO_pop_free(stack, X509_INFO_free);
++      /* 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;
 +                      }
 +              }
- #if OPENSSL_VERSION_NUMBER >= 0x10002000L
-               SSL_clear_chain_certs(ssl);
++              os_free(aliases);
++              if (rc)
++                      return rc;
++
 +              SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
 +              return 0;
 +      }
 +#endif /* ANDROID */
 +
 +#ifdef CONFIG_NATIVE_WINDOWS
 +      if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) ==
 +          0) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from "
 +                         "system certificate store");
 +              return 0;
 +      }
 +#endif /* CONFIG_NATIVE_WINDOWS */
 +
 +      if (ca_cert || ca_path) {
 +#ifndef OPENSSL_NO_STDIO
 +              if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) !=
 +                  1) {
 +                      tls_show_errors(MSG_WARNING, __func__,
 +                                      "Failed to load root certificates");
 +                      if (ca_cert &&
 +                          tls_load_ca_der(data, ca_cert) == 0) {
 +                              wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded "
 +                                         "DER format CA certificate",
 +                                         __func__);
 +                      } else
 +                              return -1;
 +              } else {
 +                      wpa_printf(MSG_DEBUG, "TLS: Trusted root "
 +                                 "certificate(s) loaded");
 +                      tls_get_errors(data);
 +              }
 +#else /* OPENSSL_NO_STDIO */
 +              wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
 +                         __func__);
 +              return -1;
 +#endif /* OPENSSL_NO_STDIO */
 +      } else {
 +              /* No ca_cert configured - do not try to verify server
 +               * certificate */
 +              wpa_printf(MSG_DEBUG, "OpenSSL: tls_connection_ca_cert: No ca_cert; setting conn->ca_cert_verify=0");
 +              conn->ca_cert_verify = 0;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +static int tls_global_ca_cert(struct tls_data *data, const char *ca_cert)
 +{
 +      SSL_CTX *ssl_ctx = data->ssl;
 +
 +      if (ca_cert) {
 +              if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
 +              {
 +                      tls_show_errors(MSG_WARNING, __func__,
 +                                      "Failed to load root certificates");
 +                      return -1;
 +              }
 +
 +              wpa_printf(MSG_DEBUG, "TLS: Trusted root "
 +                         "certificate(s) loaded");
 +
 +#ifndef OPENSSL_NO_STDIO
 +              /* Add the same CAs to the client certificate requests */
 +              SSL_CTX_set_client_CA_list(ssl_ctx,
 +                                         SSL_load_client_CA_file(ca_cert));
 +#endif /* OPENSSL_NO_STDIO */
 +      }
 +
 +      return 0;
 +}
 +
 +
 +int tls_global_set_verify(void *ssl_ctx, int check_crl)
 +{
 +      int flags;
 +
 +      if (check_crl) {
 +              struct tls_data *data = ssl_ctx;
 +              X509_STORE *cs = SSL_CTX_get_cert_store(data->ssl);
 +              if (cs == NULL) {
 +                      tls_show_errors(MSG_INFO, __func__, "Failed to get "
 +                                      "certificate store when enabling "
 +                                      "check_crl");
 +                      return -1;
 +              }
 +              flags = X509_V_FLAG_CRL_CHECK;
 +              if (check_crl == 2)
 +                      flags |= X509_V_FLAG_CRL_CHECK_ALL;
 +              X509_STORE_set_flags(cs, flags);
 +      }
 +      return 0;
 +}
 +
 +
 +static int tls_connection_set_subject_match(struct tls_connection *conn,
 +                                          const char *subject_match,
 +                                          const char *altsubject_match,
 +                                          const char *suffix_match,
 +                                          const char *domain_match)
 +{
 +      os_free(conn->subject_match);
 +      conn->subject_match = NULL;
 +      if (subject_match) {
 +              conn->subject_match = os_strdup(subject_match);
 +              if (conn->subject_match == NULL)
 +                      return -1;
 +      }
 +
 +      os_free(conn->altsubject_match);
 +      conn->altsubject_match = NULL;
 +      if (altsubject_match) {
 +              conn->altsubject_match = os_strdup(altsubject_match);
 +              if (conn->altsubject_match == NULL)
 +                      return -1;
 +      }
 +
 +      os_free(conn->suffix_match);
 +      conn->suffix_match = NULL;
 +      if (suffix_match) {
 +              conn->suffix_match = os_strdup(suffix_match);
 +              if (conn->suffix_match == NULL)
 +                      return -1;
 +      }
 +
 +      os_free(conn->domain_match);
 +      conn->domain_match = NULL;
 +      if (domain_match) {
 +              conn->domain_match = os_strdup(domain_match);
 +              if (conn->domain_match == NULL)
 +                      return -1;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +static void tls_set_conn_flags(SSL *ssl, unsigned int flags)
 +{
 +#ifdef SSL_OP_NO_TICKET
 +      if (flags & TLS_CONN_DISABLE_SESSION_TICKET)
 +              SSL_set_options(ssl, SSL_OP_NO_TICKET);
 +#ifdef SSL_clear_options
 +      else
 +              SSL_clear_options(ssl, SSL_OP_NO_TICKET);
 +#endif /* SSL_clear_options */
 +#endif /* SSL_OP_NO_TICKET */
 +
 +#ifdef SSL_OP_NO_TLSv1
 +      if (flags & TLS_CONN_DISABLE_TLSv1_0)
 +              SSL_set_options(ssl, SSL_OP_NO_TLSv1);
 +      else
 +              SSL_clear_options(ssl, SSL_OP_NO_TLSv1);
 +#endif /* SSL_OP_NO_TLSv1 */
 +#ifdef SSL_OP_NO_TLSv1_1
 +      if (flags & TLS_CONN_DISABLE_TLSv1_1)
 +              SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
 +      else
 +              SSL_clear_options(ssl, SSL_OP_NO_TLSv1_1);
 +#endif /* SSL_OP_NO_TLSv1_1 */
 +#ifdef SSL_OP_NO_TLSv1_2
 +      if (flags & TLS_CONN_DISABLE_TLSv1_2)
 +              SSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
 +      else
 +              SSL_clear_options(ssl, SSL_OP_NO_TLSv1_2);
 +#endif /* SSL_OP_NO_TLSv1_2 */
 +}
 +
 +
 +int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
 +                            int verify_peer, unsigned int flags,
 +                            const u8 *session_ctx, size_t session_ctx_len)
 +{
 +      static int counter = 0;
 +      struct tls_data *data = ssl_ctx;
 +
 +      if (conn == NULL)
 +              return -1;
 +
 +      if (verify_peer) {
 +              conn->ca_cert_verify = 1;
 +              SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
 +                             SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
 +                             SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
 +      } else {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: tls_connection_set_verify: !verify_peer; setting conn->ca_cert_verify=0");
 +              conn->ca_cert_verify = 0;
 +              SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
 +      }
 +
 +      tls_set_conn_flags(conn->ssl, flags);
 +      conn->flags = flags;
 +
 +      SSL_set_accept_state(conn->ssl);
 +
 +      if (data->tls_session_lifetime == 0) {
 +              /*
 +               * Set session id context to a unique value to make sure
 +               * session resumption cannot be used either through session
 +               * caching or TLS ticket extension.
 +               */
 +              counter++;
 +              SSL_set_session_id_context(conn->ssl,
 +                                         (const unsigned char *) &counter,
 +                                         sizeof(counter));
 +      } else if (session_ctx) {
 +              SSL_set_session_id_context(conn->ssl, session_ctx,
 +                                         session_ctx_len);
 +      }
 +
 +      return 0;
 +}
 +
 +
 +static int tls_connection_client_cert(struct tls_connection *conn,
 +                                    const char *client_cert,
 +                                    const u8 *client_cert_blob,
 +                                    size_t client_cert_blob_len)
 +{
 +      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) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> "
 +                         "OK");
 +              return 0;
 +      } else if (client_cert_blob) {
 +              tls_show_errors(MSG_DEBUG, __func__,
 +                              "SSL_use_certificate_ASN1 failed");
 +      }
 +
 +      if (client_cert == NULL)
 +              return -1;
 +
 +#ifdef ANDROID
 +      if (os_strncmp("keystore://", client_cert, 11) == 0) {
 +              BIO *bio = BIO_from_keystore(&client_cert[11]);
 +              X509 *x509 = NULL;
 +              int ret = -1;
 +              if (bio) {
 +                      x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
 +                      BIO_free(bio);
 +              }
 +              if (x509) {
 +                      if (SSL_use_certificate(conn->ssl, x509) == 1)
 +                              ret = 0;
 +                      X509_free(x509);
 +              }
 +              return ret;
 +      }
 +#endif /* ANDROID */
 +
 +#ifndef OPENSSL_NO_STDIO
 +      if (SSL_use_certificate_file(conn->ssl, client_cert,
 +                                   SSL_FILETYPE_ASN1) == 1) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)"
 +                         " --> OK");
 +              return 0;
 +      }
 +
 +      if (SSL_use_certificate_file(conn->ssl, client_cert,
 +                                   SSL_FILETYPE_PEM) == 1) {
 +              ERR_clear_error();
 +              wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)"
 +                         " --> OK");
 +              return 0;
 +      }
 +
 +      tls_show_errors(MSG_DEBUG, __func__,
 +                      "SSL_use_certificate_file failed");
 +#else /* OPENSSL_NO_STDIO */
 +      wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
 +#endif /* OPENSSL_NO_STDIO */
 +
 +      return -1;
 +}
 +
 +
 +static int tls_global_client_cert(struct tls_data *data,
 +                                const char *client_cert)
 +{
 +#ifndef OPENSSL_NO_STDIO
 +      SSL_CTX *ssl_ctx = data->ssl;
 +
 +      if (client_cert == NULL)
 +              return 0;
 +
 +      if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
 +                                       SSL_FILETYPE_ASN1) != 1 &&
 +          SSL_CTX_use_certificate_chain_file(ssl_ctx, client_cert) != 1 &&
 +          SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
 +                                       SSL_FILETYPE_PEM) != 1) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Failed to load client certificate");
 +              return -1;
 +      }
 +      return 0;
 +#else /* OPENSSL_NO_STDIO */
 +      if (client_cert == NULL)
 +              return 0;
 +      wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
 +      return -1;
 +#endif /* OPENSSL_NO_STDIO */
 +}
 +
 +
 +static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
 +{
 +      if (password == NULL) {
 +              return 0;
 +      }
 +      os_strlcpy(buf, (char *) password, size);
 +      return os_strlen(buf);
 +}
 +
 +
 +#ifdef PKCS12_FUNCS
 +static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
 +                          const char *passwd)
 +{
 +      EVP_PKEY *pkey;
 +      X509 *cert;
 +      STACK_OF(X509) *certs;
 +      int res = 0;
 +      char buf[256];
 +
 +      pkey = NULL;
 +      cert = NULL;
 +      certs = NULL;
 +      if (!passwd)
 +              passwd = "";
 +      if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) {
 +              tls_show_errors(MSG_DEBUG, __func__,
 +                              "Failed to parse PKCS12 file");
 +              PKCS12_free(p12);
 +              return -1;
 +      }
 +      wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data");
 +
 +      if (cert) {
 +              X509_NAME_oneline(X509_get_subject_name(cert), buf,
 +                                sizeof(buf));
 +              wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: "
 +                         "subject='%s'", buf);
 +              if (ssl) {
 +                      if (SSL_use_certificate(ssl, cert) != 1)
 +                              res = -1;
 +              } else {
 +                      if (SSL_CTX_use_certificate(data->ssl, cert) != 1)
 +                              res = -1;
 +              }
 +              X509_free(cert);
 +      }
 +
 +      if (pkey) {
 +              wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12");
 +              if (ssl) {
 +                      if (SSL_use_PrivateKey(ssl, pkey) != 1)
 +                              res = -1;
 +              } else {
 +                      if (SSL_CTX_use_PrivateKey(data->ssl, pkey) != 1)
 +                              res = -1;
 +              }
 +              EVP_PKEY_free(pkey);
 +      }
 +
 +      if (certs) {
-                       if (SSL_add1_chain_cert(ssl, cert) != 1) {
++#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);
-               sk_X509_free(certs);
++                      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 */
 +              }
-               res = SSL_build_cert_chain(ssl,
-                                          SSL_BUILD_CHAIN_FLAG_CHECK |
-                                          SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
++              sk_X509_pop_free(certs, X509_free);
 +#ifndef OPENSSL_IS_BORINGSSL
- #if OPENSSL_VERSION_NUMBER >= 0x10001000L
++              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");
 +              } else if (res == 2) {
 +                      wpa_printf(MSG_DEBUG,
 +                                 "TLS: Ignore certificate chain verification error when building chain with PKCS#12 extra certificates");
 +              }
 +#endif /* OPENSSL_IS_BORINGSSL */
 +              /*
 +               * Try to continue regardless of result since it is possible for
 +               * the extra certificates not to be required.
 +               */
 +              res = 0;
 +#else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
- #endif /* OPENSSL_VERSION_NUMBER >= 0x10001000L */
 +              SSL_CTX_clear_extra_chain_certs(data->ssl);
-               sk_X509_free(certs);
 +              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);
 +                      /*
 +                       * There is no SSL equivalent for the chain cert - so
 +                       * always add it to the context...
 +                       */
 +                      if (SSL_CTX_add_extra_chain_cert(data->ssl, cert) != 1)
 +                      {
++                              X509_free(cert);
 +                              res = -1;
 +                              break;
 +                      }
 +              }
- #ifndef OPENSSL_NO_ENGINE
++              sk_X509_pop_free(certs, X509_free);
 +#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
 +      }
 +
 +      PKCS12_free(p12);
 +
 +      if (res < 0)
 +              tls_get_errors(data);
 +
 +      return res;
 +}
 +#endif  /* PKCS12_FUNCS */
 +
 +
 +static int tls_read_pkcs12(struct tls_data *data, SSL *ssl,
 +                         const char *private_key, const char *passwd)
 +{
 +#ifdef PKCS12_FUNCS
 +      FILE *f;
 +      PKCS12 *p12;
 +
 +      f = fopen(private_key, "rb");
 +      if (f == NULL)
 +              return -1;
 +
 +      p12 = d2i_PKCS12_fp(f, NULL);
 +      fclose(f);
 +
 +      if (p12 == NULL) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Failed to use PKCS#12 file");
 +              return -1;
 +      }
 +
 +      return tls_parse_pkcs12(data, ssl, p12, passwd);
 +
 +#else /* PKCS12_FUNCS */
 +      wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read "
 +                 "p12/pfx files");
 +      return -1;
 +#endif  /* PKCS12_FUNCS */
 +}
 +
 +
 +static int tls_read_pkcs12_blob(struct tls_data *data, SSL *ssl,
 +                              const u8 *blob, size_t len, const char *passwd)
 +{
 +#ifdef PKCS12_FUNCS
 +      PKCS12 *p12;
 +
 +      p12 = d2i_PKCS12(NULL, (const unsigned char **) &blob, len);
 +      if (p12 == NULL) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Failed to use PKCS#12 blob");
 +              return -1;
 +      }
 +
 +      return tls_parse_pkcs12(data, ssl, p12, passwd);
 +
 +#else /* PKCS12_FUNCS */
 +      wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse "
 +                 "p12/pfx blobs");
 +      return -1;
 +#endif  /* PKCS12_FUNCS */
 +}
 +
 +
 +#ifndef OPENSSL_NO_ENGINE
 +static int tls_engine_get_cert(struct tls_connection *conn,
 +                             const char *cert_id,
 +                             X509 **cert)
 +{
 +      /* this runs after the private key is loaded so no PIN is required */
 +      struct {
 +              const char *cert_id;
 +              X509 *cert;
 +      } params;
 +      params.cert_id = cert_id;
 +      params.cert = NULL;
 +
 +      if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL",
 +                           0, &params, NULL, 1)) {
 +              unsigned long err = ERR_get_error();
 +
 +              wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id"
 +                         " '%s' [%s]", cert_id,
 +                         ERR_error_string(err, NULL));
 +              if (tls_is_pin_error(err))
 +                      return TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN;
 +              return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
 +      }
 +      if (!params.cert) {
 +              wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id"
 +                         " '%s'", cert_id);
 +              return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
 +      }
 +      *cert = params.cert;
 +      return 0;
 +}
 +#endif /* OPENSSL_NO_ENGINE */
 +
 +
 +static int tls_connection_engine_client_cert(struct tls_connection *conn,
 +                                           const char *cert_id)
 +{
 +#ifndef OPENSSL_NO_ENGINE
 +      X509 *cert;
 +
 +      if (tls_engine_get_cert(conn, cert_id, &cert))
 +              return -1;
 +
 +      if (!SSL_use_certificate(conn->ssl, cert)) {
 +              tls_show_errors(MSG_ERROR, __func__,
 +                              "SSL_use_certificate failed");
 +                X509_free(cert);
 +              return -1;
 +      }
 +      X509_free(cert);
 +      wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> "
 +                 "OK");
 +      return 0;
 +
 +#else /* OPENSSL_NO_ENGINE */
 +      return -1;
 +#endif /* OPENSSL_NO_ENGINE */
 +}
 +
 +
 +static int tls_connection_engine_ca_cert(struct tls_data *data,
 +                                       struct tls_connection *conn,
 +                                       const char *ca_cert_id)
 +{
 +#ifndef OPENSSL_NO_ENGINE
 +      X509 *cert;
 +      SSL_CTX *ssl_ctx = data->ssl;
 +      X509_STORE *store;
 +
 +      if (tls_engine_get_cert(conn, ca_cert_id, &cert))
 +              return -1;
 +
 +      /* start off the same as tls_connection_ca_cert */
 +      store = X509_STORE_new();
 +      if (store == NULL) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
 +                         "certificate store", __func__);
 +              X509_free(cert);
 +              return -1;
 +      }
 +      SSL_CTX_set_cert_store(ssl_ctx, store);
 +      if (!X509_STORE_add_cert(store, cert)) {
 +              unsigned long err = ERR_peek_error();
 +              tls_show_errors(MSG_WARNING, __func__,
 +                              "Failed to add CA certificate from engine "
 +                              "to certificate store");
 +              if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
 +                  ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert"
 +                                 " already in hash table error",
 +                                 __func__);
 +              } else {
 +                      X509_free(cert);
 +                      return -1;
 +              }
 +      }
 +      X509_free(cert);
 +      wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine "
 +                 "to certificate store", __func__);
 +      SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
 +      conn->ca_cert_verify = 1;
 +
 +      return 0;
 +
 +#else /* OPENSSL_NO_ENGINE */
 +      return -1;
 +#endif /* OPENSSL_NO_ENGINE */
 +}
 +
 +
 +static int tls_connection_engine_private_key(struct tls_connection *conn)
 +{
- #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 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");
 +              return -1;
 +      }
 +      if (!SSL_check_private_key(conn->ssl)) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Private key failed verification");
 +              return -1;
 +      }
 +      return 0;
 +#else /* OPENSSL_NO_ENGINE */
 +      wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but "
 +                 "engine support was not compiled in");
 +      return -1;
 +#endif /* OPENSSL_NO_ENGINE */
 +}
 +
 +
 +static int tls_connection_private_key(struct tls_data *data,
 +                                    struct tls_connection *conn,
 +                                    const char *private_key,
 +                                    const char *private_key_passwd,
 +                                    const u8 *private_key_blob,
 +                                    size_t private_key_blob_len)
 +{
 +      SSL_CTX *ssl_ctx = data->ssl;
 +      char *passwd;
 +      int ok;
 +
 +      if (private_key == NULL && private_key_blob == NULL)
 +              return 0;
 +
 +      if (private_key_passwd) {
 +              passwd = os_strdup(private_key_passwd);
 +              if (passwd == NULL)
 +                      return -1;
 +      } else
 +              passwd = NULL;
 +
 +      SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
 +      SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
 +
 +      ok = 0;
 +      while (private_key_blob) {
 +              if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl,
 +                                          (u8 *) private_key_blob,
 +                                          private_key_blob_len) == 1) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
 +                                 "ASN1(EVP_PKEY_RSA) --> OK");
 +                      ok = 1;
 +                      break;
 +              }
 +
 +              if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl,
 +                                          (u8 *) private_key_blob,
 +                                          private_key_blob_len) == 1) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
 +                                 "ASN1(EVP_PKEY_DSA) --> OK");
 +                      ok = 1;
 +                      break;
 +              }
 +
 +              if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
 +                                             (u8 *) private_key_blob,
 +                                             private_key_blob_len) == 1) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: "
 +                                 "SSL_use_RSAPrivateKey_ASN1 --> OK");
 +                      ok = 1;
 +                      break;
 +              }
 +
 +              if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob,
 +                                       private_key_blob_len, passwd) == 0) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
 +                                 "OK");
 +                      ok = 1;
 +                      break;
 +              }
 +
 +              break;
 +      }
 +
 +      while (!ok && private_key) {
 +#ifndef OPENSSL_NO_STDIO
 +              if (SSL_use_PrivateKey_file(conn->ssl, private_key,
 +                                          SSL_FILETYPE_ASN1) == 1) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: "
 +                                 "SSL_use_PrivateKey_File (DER) --> OK");
 +                      ok = 1;
 +                      break;
 +              }
 +
 +              if (SSL_use_PrivateKey_file(conn->ssl, private_key,
 +                                          SSL_FILETYPE_PEM) == 1) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: "
 +                                 "SSL_use_PrivateKey_File (PEM) --> OK");
 +                      ok = 1;
 +                      break;
 +              }
 +#else /* OPENSSL_NO_STDIO */
 +              wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
 +                         __func__);
 +#endif /* OPENSSL_NO_STDIO */
 +
 +              if (tls_read_pkcs12(data, conn->ssl, private_key, passwd)
 +                  == 0) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
 +                                 "--> OK");
 +                      ok = 1;
 +                      break;
 +              }
 +
 +              if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to "
 +                                 "access certificate store --> OK");
 +                      ok = 1;
 +                      break;
 +              }
 +
 +              break;
 +      }
 +
 +      if (!ok) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Failed to load private key");
 +              os_free(passwd);
 +              return -1;
 +      }
 +      ERR_clear_error();
 +      SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
 +      os_free(passwd);
 +
 +      if (!SSL_check_private_key(conn->ssl)) {
 +              tls_show_errors(MSG_INFO, __func__, "Private key failed "
 +                              "verification");
 +              return -1;
 +      }
 +
 +      wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully");
 +      return 0;
 +}
 +
 +
 +static int tls_global_private_key(struct tls_data *data,
 +                                const char *private_key,
 +                                const char *private_key_passwd)
 +{
 +      SSL_CTX *ssl_ctx = data->ssl;
 +      char *passwd;
 +
 +      if (private_key == NULL)
 +              return 0;
 +
 +      if (private_key_passwd) {
 +              passwd = os_strdup(private_key_passwd);
 +              if (passwd == NULL)
 +                      return -1;
 +      } else
 +              passwd = NULL;
 +
 +      SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
 +      SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
 +      if (
 +#ifndef OPENSSL_NO_STDIO
 +          SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
 +                                      SSL_FILETYPE_ASN1) != 1 &&
 +          SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
 +                                      SSL_FILETYPE_PEM) != 1 &&
 +#endif /* OPENSSL_NO_STDIO */
 +          tls_read_pkcs12(data, NULL, private_key, passwd)) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Failed to load private key");
 +              os_free(passwd);
 +              ERR_clear_error();
 +              return -1;
 +      }
 +      os_free(passwd);
 +      ERR_clear_error();
 +      SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
 +
 +      if (!SSL_CTX_check_private_key(ssl_ctx)) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Private key failed verification");
 +              return -1;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +static int tls_connection_dh(struct tls_connection *conn, const char *dh_file)
 +{
 +#ifdef OPENSSL_NO_DH
 +      if (dh_file == NULL)
 +              return 0;
 +      wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
 +                 "dh_file specified");
 +      return -1;
 +#else /* OPENSSL_NO_DH */
 +      DH *dh;
 +      BIO *bio;
 +
 +      /* TODO: add support for dh_blob */
 +      if (dh_file == NULL)
 +              return 0;
 +      if (conn == NULL)
 +              return -1;
 +
 +      bio = BIO_new_file(dh_file, "r");
 +      if (bio == NULL) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
 +                         dh_file, ERR_error_string(ERR_get_error(), NULL));
 +              return -1;
 +      }
 +      dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
 +      BIO_free(bio);
 +#ifndef OPENSSL_NO_DSA
 +      while (dh == NULL) {
 +              DSA *dsa;
 +              wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
 +                         " trying to parse as DSA params", dh_file,
 +                         ERR_error_string(ERR_get_error(), NULL));
 +              bio = BIO_new_file(dh_file, "r");
 +              if (bio == NULL)
 +                      break;
 +              dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
 +              BIO_free(bio);
 +              if (!dsa) {
 +                      wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
 +                                 "'%s': %s", dh_file,
 +                                 ERR_error_string(ERR_get_error(), NULL));
 +                      break;
 +              }
 +
 +              wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
 +              dh = DSA_dup_DH(dsa);
 +              DSA_free(dsa);
 +              if (dh == NULL) {
 +                      wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
 +                                 "params into DH params");
 +                      break;
 +              }
 +              break;
 +      }
 +#endif /* !OPENSSL_NO_DSA */
 +      if (dh == NULL) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
 +                         "'%s'", dh_file);
 +              return -1;
 +      }
 +
 +      if (SSL_set_tmp_dh(conn->ssl, dh) != 1) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
 +                         "%s", dh_file,
 +                         ERR_error_string(ERR_get_error(), NULL));
 +              DH_free(dh);
 +              return -1;
 +      }
 +      DH_free(dh);
 +      return 0;
 +#endif /* OPENSSL_NO_DH */
 +}
 +
 +
 +static int tls_global_dh(struct tls_data *data, const char *dh_file)
 +{
 +#ifdef OPENSSL_NO_DH
 +      if (dh_file == NULL)
 +              return 0;
 +      wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
 +                 "dh_file specified");
 +      return -1;
 +#else /* OPENSSL_NO_DH */
 +      SSL_CTX *ssl_ctx = data->ssl;
 +      DH *dh;
 +      BIO *bio;
 +
 +      /* TODO: add support for dh_blob */
 +      if (dh_file == NULL)
 +              return 0;
 +      if (ssl_ctx == NULL)
 +              return -1;
 +
 +      bio = BIO_new_file(dh_file, "r");
 +      if (bio == NULL) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
 +                         dh_file, ERR_error_string(ERR_get_error(), NULL));
 +              return -1;
 +      }
 +      dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
 +      BIO_free(bio);
 +#ifndef OPENSSL_NO_DSA
 +      while (dh == NULL) {
 +              DSA *dsa;
 +              wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
 +                         " trying to parse as DSA params", dh_file,
 +                         ERR_error_string(ERR_get_error(), NULL));
 +              bio = BIO_new_file(dh_file, "r");
 +              if (bio == NULL)
 +                      break;
 +              dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
 +              BIO_free(bio);
 +              if (!dsa) {
 +                      wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
 +                                 "'%s': %s", dh_file,
 +                                 ERR_error_string(ERR_get_error(), NULL));
 +                      break;
 +              }
 +
 +              wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
 +              dh = DSA_dup_DH(dsa);
 +              DSA_free(dsa);
 +              if (dh == NULL) {
 +                      wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
 +                                 "params into DH params");
 +                      break;
 +              }
 +              break;
 +      }
 +#endif /* !OPENSSL_NO_DSA */
 +      if (dh == NULL) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
 +                         "'%s'", dh_file);
 +              return -1;
 +      }
 +
 +      if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
 +                         "%s", dh_file,
 +                         ERR_error_string(ERR_get_error(), NULL));
 +              DH_free(dh);
 +              return -1;
 +      }
 +      DH_free(dh);
 +      return 0;
 +#endif /* OPENSSL_NO_DH */
 +}
 +
 +
 +int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
 +                            struct tls_random *keys)
 +{
 +      SSL *ssl;
 +
 +      if (conn == NULL || keys == NULL)
 +              return -1;
 +      ssl = conn->ssl;
- #endif
 +      if (ssl == NULL)
 +              return -1;
 +
 +      os_memset(keys, 0, sizeof(*keys));
 +      keys->client_random = conn->client_random;
 +      keys->client_random_len = SSL_get_client_random(
 +              ssl, conn->client_random, sizeof(conn->client_random));
 +      keys->server_random = conn->server_random;
 +      keys->server_random_len = SSL_get_server_random(
 +              ssl, conn->server_random, sizeof(conn->server_random));
- #ifndef CONFIG_FIPS
 +
 +      return 0;
 +}
 +
 +
- #if OPENSSL_VERSION_NUMBER < 0x10100000L
++#ifdef OPENSSL_NEED_EAP_FAST_PRF
 +static int openssl_get_keyblock_size(SSL *ssl)
 +{
- #if OPENSSL_VERSION_NUMBER >= 0x00909000L
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
 +      const EVP_CIPHER *c;
 +      const EVP_MD *h;
 +      int md_size;
 +
 +      if (ssl->enc_read_ctx == NULL || ssl->enc_read_ctx->cipher == NULL ||
 +          ssl->read_hash == NULL)
 +              return -1;
 +
 +      c = ssl->enc_read_ctx->cipher;
- #else
-       h = ssl->read_hash;
- #endif
 +      h = EVP_MD_CTX_md(ssl->read_hash);
- #if OPENSSL_VERSION_NUMBER >= 0x10000000L
 +      if (h)
 +              md_size = EVP_MD_size(h);
- #endif
 +      else if (ssl->s3)
 +              md_size = ssl->s3->tmp.new_mac_secret_size;
- #endif /* CONFIG_FIPS */
 +      else
 +              return -1;
 +
 +      wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d "
 +                 "IV_len=%d", EVP_CIPHER_key_length(c), md_size,
 +                 EVP_CIPHER_iv_length(c));
 +      return 2 * (EVP_CIPHER_key_length(c) +
 +                  md_size +
 +                  EVP_CIPHER_iv_length(c));
 +#else
 +      const SSL_CIPHER *ssl_cipher;
 +      int cipher, digest;
 +      const EVP_CIPHER *c;
 +      const EVP_MD *h;
 +
 +      ssl_cipher = SSL_get_current_cipher(ssl);
 +      if (!ssl_cipher)
 +              return -1;
 +      cipher = SSL_CIPHER_get_cipher_nid(ssl_cipher);
 +      digest = SSL_CIPHER_get_digest_nid(ssl_cipher);
 +      wpa_printf(MSG_DEBUG, "OpenSSL: cipher nid %d digest nid %d",
 +                 cipher, digest);
 +      if (cipher < 0 || digest < 0)
 +              return -1;
 +      c = EVP_get_cipherbynid(cipher);
 +      h = EVP_get_digestbynid(digest);
 +      if (!c || !h)
 +              return -1;
 +
 +      wpa_printf(MSG_DEBUG,
 +                 "OpenSSL: keyblock size: key_len=%d MD_size=%d IV_len=%d",
 +                 EVP_CIPHER_key_length(c), EVP_MD_size(h),
 +                 EVP_CIPHER_iv_length(c));
 +      return 2 * (EVP_CIPHER_key_length(c) + EVP_MD_size(h) +
 +                  EVP_CIPHER_iv_length(c));
 +#endif
 +}
- 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)
++#endif /* OPENSSL_NEED_EAP_FAST_PRF */
 +
 +
- #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);
++int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
++                            const char *label, u8 *out, size_t out_len)
 +{
-       }
++      if (!conn ||
++          SSL_export_keying_material(conn->ssl, out, out_len, label,
++                                     os_strlen(label), NULL, 0, 0) != 1)
 +              return -1;
-       if (server_random_first) {
-               os_memcpy(rnd, ssl->s3->server_random, SSL3_RANDOM_SIZE);
-               os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->client_random,
-                       SSL3_RANDOM_SIZE);
-       } else {
-               os_memcpy(rnd, ssl->s3->client_random, SSL3_RANDOM_SIZE);
-               os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->server_random,
-                       SSL3_RANDOM_SIZE);
-       }
++      return 0;
++}
 +
-       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
 +
-        * 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.
++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;
 +      int ret = -1;
 +      int skip = 0;
 +      u8 *tmp_out = NULL;
 +      u8 *_out = out;
 +      unsigned char client_random[SSL3_RANDOM_SIZE];
 +      unsigned char server_random[SSL3_RANDOM_SIZE];
 +      unsigned char master_key[64];
 +      size_t master_key_len;
 +      const char *ver;
 +
 +      /*
-       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;
-       }
++       * 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)
 +              return -1;
 +      ssl = conn->ssl;
 +      if (ssl == NULL)
 +              return -1;
 +      ver = SSL_get_version(ssl);
 +      sess = SSL_get_session(ssl);
 +      if (!ver || !sess)
 +              return -1;
 +
-       if (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);
-       }
++      skip = openssl_get_keyblock_size(ssl);
++      if (skip < 0)
++              return -1;
++      tmp_out = os_malloc(skip + out_len);
++      if (!tmp_out)
++              return -1;
++      _out = tmp_out;
 +
 +      rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
 +      if (!rnd) {
 +              os_free(tmp_out);
 +              return -1;
 +      }
 +
 +      SSL_get_client_random(ssl, client_random, sizeof(client_random));
 +      SSL_get_server_random(ssl, server_random, sizeof(server_random));
 +      master_key_len = SSL_SESSION_get_master_key(sess, master_key,
 +                                                  sizeof(master_key));
 +
-                              label, rnd, 2 * 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,
-       if (ret == 0 && skip_keyblock)
++                                  "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);
- #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);
++      if (ret == 0)
 +              os_memcpy(out, _out + skip, out_len);
 +      bin_clear_free(tmp_out, skip);
 +
 +      return ret;
- #if OPENSSL_VERSION_NUMBER >= 0x10001000L
++#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 */
 +}
 +
 +
 +static struct wpabuf *
 +openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data,
 +                int server)
 +{
 +      int res;
 +      struct wpabuf *out_data;
 +
 +      /*
 +       * Give TLS handshake data from the server (if available) to OpenSSL
 +       * for processing.
 +       */
 +      if (in_data && wpabuf_len(in_data) > 0 &&
 +          BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data))
 +          < 0) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Handshake failed - BIO_write");
 +              return NULL;
 +      }
 +
 +      /* Initiate TLS handshake or continue the existing handshake */
 +      if (server)
 +              res = SSL_accept(conn->ssl);
 +      else
 +              res = SSL_connect(conn->ssl);
 +      if (res != 1) {
 +              int err = SSL_get_error(conn->ssl, res);
 +              if (err == SSL_ERROR_WANT_READ)
 +                      wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want "
 +                                 "more data");
 +              else if (err == SSL_ERROR_WANT_WRITE)
 +                      wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to "
 +                                 "write");
 +              else {
 +                      tls_show_errors(MSG_INFO, __func__, "SSL_connect");
 +                      conn->failed++;
 +              }
 +      }
 +
 +      /* Get the TLS handshake data to be sent to the server */
 +      res = BIO_ctrl_pending(conn->ssl_out);
 +      wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
 +      out_data = wpabuf_alloc(res);
 +      if (out_data == NULL) {
 +              wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for "
 +                         "handshake output (%d bytes)", res);
 +              if (BIO_reset(conn->ssl_out) < 0) {
 +                      tls_show_errors(MSG_INFO, __func__,
 +                                      "BIO_reset failed");
 +              }
 +              return NULL;
 +      }
 +      res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data),
 +                                    res);
 +      if (res < 0) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Handshake failed - BIO_read");
 +              if (BIO_reset(conn->ssl_out) < 0) {
 +                      tls_show_errors(MSG_INFO, __func__,
 +                                      "BIO_reset failed");
 +              }
 +              wpabuf_free(out_data);
 +              return NULL;
 +      }
 +      wpabuf_put(out_data, res);
 +
 +      return out_data;
 +}
 +
 +
 +static struct wpabuf *
 +openssl_get_appl_data(struct tls_connection *conn, size_t max_len)
 +{
 +      struct wpabuf *appl_data;
 +      int res;
 +
 +      appl_data = wpabuf_alloc(max_len + 100);
 +      if (appl_data == NULL)
 +              return NULL;
 +
 +      res = SSL_read(conn->ssl, wpabuf_mhead(appl_data),
 +                     wpabuf_size(appl_data));
 +      if (res < 0) {
 +              int err = SSL_get_error(conn->ssl, res);
 +              if (err == SSL_ERROR_WANT_READ ||
 +                  err == SSL_ERROR_WANT_WRITE) {
 +                      wpa_printf(MSG_DEBUG, "SSL: No Application Data "
 +                                 "included");
 +              } else {
 +                      tls_show_errors(MSG_INFO, __func__,
 +                                      "Failed to read possible "
 +                                      "Application Data");
 +              }
 +              wpabuf_free(appl_data);
 +              return NULL;
 +      }
 +
 +      wpabuf_put(appl_data, res);
 +      wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished "
 +                          "message", appl_data);
 +
 +      return appl_data;
 +}
 +
 +
 +static struct wpabuf *
 +openssl_connection_handshake(struct tls_connection *conn,
 +                           const struct wpabuf *in_data,
 +                           struct wpabuf **appl_data, int server)
 +{
 +      struct wpabuf *out_data;
 +
 +      if (appl_data)
 +              *appl_data = NULL;
 +
 +      out_data = openssl_handshake(conn, in_data, server);
 +      if (out_data == NULL)
 +              return NULL;
 +      if (conn->invalid_hb_used) {
 +              wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
 +              wpabuf_free(out_data);
 +              return NULL;
 +      }
 +
 +      if (SSL_is_init_finished(conn->ssl)) {
 +              wpa_printf(MSG_DEBUG,
 +                         "OpenSSL: Handshake finished - resumed=%d",
 +                         tls_connection_resumed(conn->ssl_ctx, conn));
 +              if (appl_data && in_data)
 +                      *appl_data = openssl_get_appl_data(conn,
 +                                                         wpabuf_len(in_data));
 +      }
 +
 +      if (conn->invalid_hb_used) {
 +              wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
 +              if (appl_data) {
 +                      wpabuf_free(*appl_data);
 +                      *appl_data = NULL;
 +              }
 +              wpabuf_free(out_data);
 +              return NULL;
 +      }
 +
 +      return out_data;
 +}
 +
 +
 +struct wpabuf *
 +tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
 +                       const struct wpabuf *in_data,
 +                       struct wpabuf **appl_data)
 +{
 +      return openssl_connection_handshake(conn, in_data, appl_data, 0);
 +}
 +
 +
 +struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
 +                                              struct tls_connection *conn,
 +                                              const struct wpabuf *in_data,
 +                                              struct wpabuf **appl_data)
 +{
 +      return openssl_connection_handshake(conn, in_data, appl_data, 1);
 +}
 +
 +
 +struct wpabuf * tls_connection_encrypt(void *tls_ctx,
 +                                     struct tls_connection *conn,
 +                                     const struct wpabuf *in_data)
 +{
 +      int res;
 +      struct wpabuf *buf;
 +
 +      if (conn == NULL)
 +              return NULL;
 +
 +      /* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */
 +      if ((res = BIO_reset(conn->ssl_in)) < 0 ||
 +          (res = BIO_reset(conn->ssl_out)) < 0) {
 +              tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
 +              return NULL;
 +      }
 +      res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data));
 +      if (res < 0) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Encryption failed - SSL_write");
 +              return NULL;
 +      }
 +
 +      /* Read encrypted data to be sent to the server */
 +      buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
 +      if (buf == NULL)
 +              return NULL;
 +      res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf));
 +      if (res < 0) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Encryption failed - BIO_read");
 +              wpabuf_free(buf);
 +              return NULL;
 +      }
 +      wpabuf_put(buf, res);
 +
 +      return buf;
 +}
 +
 +
 +struct wpabuf * tls_connection_decrypt(void *tls_ctx,
 +                                     struct tls_connection *conn,
 +                                     const struct wpabuf *in_data)
 +{
 +      int res;
 +      struct wpabuf *buf;
 +
 +      /* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */
 +      res = BIO_write(conn->ssl_in, wpabuf_head(in_data),
 +                      wpabuf_len(in_data));
 +      if (res < 0) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Decryption failed - BIO_write");
 +              return NULL;
 +      }
 +      if (BIO_reset(conn->ssl_out) < 0) {
 +              tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
 +              return NULL;
 +      }
 +
 +      /* Read decrypted data for further processing */
 +      /*
 +       * Even though we try to disable TLS compression, it is possible that
 +       * this cannot be done with all TLS libraries. Add extra buffer space
 +       * to handle the possibility of the decrypted data being longer than
 +       * input data.
 +       */
 +      buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
 +      if (buf == NULL)
 +              return NULL;
 +      res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
 +      if (res < 0) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Decryption failed - SSL_read");
 +              wpabuf_free(buf);
 +              return NULL;
 +      }
 +      wpabuf_put(buf, res);
 +
 +      if (conn->invalid_hb_used) {
 +              wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
 +              wpabuf_free(buf);
 +              return NULL;
 +      }
 +
 +      return buf;
 +}
 +
 +
 +int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
 +{
- #else
-       return conn ? conn->ssl->hit : 0;
- #endif
 +      return conn ? SSL_cache_hit(conn->ssl) : 0;
-       char buf[100], *pos, *end;
 +}
 +
 +
 +int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
 +                                 u8 *ciphers)
 +{
- #if OPENSSL_VERSION_NUMBER >= 0x10100000L
++      char buf[500], *pos, *end;
 +      u8 *c;
 +      int ret;
 +
 +      if (conn == NULL || conn->ssl == NULL || ciphers == NULL)
 +              return -1;
 +
 +      buf[0] = '\0';
 +      pos = buf;
 +      end = pos + sizeof(buf);
 +
 +      c = ciphers;
 +      while (*c != TLS_CIPHER_NONE) {
 +              const char *suite;
 +
 +              switch (*c) {
 +              case TLS_CIPHER_RC4_SHA:
 +                      suite = "RC4-SHA";
 +                      break;
 +              case TLS_CIPHER_AES128_SHA:
 +                      suite = "AES128-SHA";
 +                      break;
 +              case TLS_CIPHER_RSA_DHE_AES128_SHA:
 +                      suite = "DHE-RSA-AES128-SHA";
 +                      break;
 +              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);
 +                      return -1;
 +              }
 +              ret = os_snprintf(pos, end - pos, ":%s", suite);
 +              if (os_snprintf_error(end - pos, ret))
 +                      break;
 +              pos += ret;
 +
 +              c++;
 +      }
 +
 +      wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
 +
- #ifdef OPENSSL_IS_BORINGSSL
++#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-")) {
 +              /*
 +               * Need to drop to security level 0 to allow anonymous
 +               * cipher suites for EAP-FAST.
 +               */
 +              SSL_set_security_level(conn->ssl, 0);
 +      } else if (SSL_get_security_level(conn->ssl) == 0) {
 +              /* Force at least security level 1 */
 +              SSL_set_security_level(conn->ssl, 1);
 +      }
 +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
 +#endif
 +
 +      if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Cipher suite configuration failed");
 +              return -1;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
 +                  char *buf, size_t buflen)
 +{
 +      const char *name;
 +      if (conn == NULL || conn->ssl == NULL)
 +              return -1;
 +
 +      name = SSL_get_version(conn->ssl);
 +      if (name == NULL)
 +              return -1;
 +
 +      os_strlcpy(buf, name, buflen);
 +      return 0;
 +}
 +
 +
 +int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
 +                 char *buf, size_t buflen)
 +{
 +      const char *name;
 +      if (conn == NULL || conn->ssl == NULL)
 +              return -1;
 +
 +      name = SSL_get_cipher(conn->ssl);
 +      if (name == NULL)
 +              return -1;
 +
 +      os_strlcpy(buf, name, buflen);
 +      return 0;
 +}
 +
 +
 +int tls_connection_enable_workaround(void *ssl_ctx,
 +                                   struct tls_connection *conn)
 +{
 +      SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
 +
 +      return 0;
 +}
 +
 +
 +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
 +/* ClientHello TLS extensions require a patch to openssl, so this function is
 + * commented out unless explicitly needed for EAP-FAST in order to be able to
 + * build this file with unmodified openssl. */
 +int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
 +                                  int ext_type, const u8 *data,
 +                                  size_t data_len)
 +{
 +      if (conn == NULL || conn->ssl == NULL || ext_type != 35)
 +              return -1;
 +
 +      if (SSL_set_session_ticket_ext(conn->ssl, (void *) data,
 +                                     data_len) != 1)
 +              return -1;
 +
 +      return 0;
 +}
 +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
 +
 +
 +int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
 +{
 +      if (conn == NULL)
 +              return -1;
 +      return conn->failed;
 +}
 +
 +
 +int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
 +{
 +      if (conn == NULL)
 +              return -1;
 +      return conn->read_alerts;
 +}
 +
 +
 +int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
 +{
 +      if (conn == NULL)
 +              return -1;
 +      return conn->write_alerts;
 +}
 +
 +
 +#ifdef HAVE_OCSP
 +
 +static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp)
 +{
 +#ifndef CONFIG_NO_STDOUT_DEBUG
 +      BIO *out;
 +      size_t rlen;
 +      char *txt;
 +      int res;
 +
 +      if (wpa_debug_level > MSG_DEBUG)
 +              return;
 +
 +      out = BIO_new(BIO_s_mem());
 +      if (!out)
 +              return;
 +
 +      OCSP_RESPONSE_print(out, rsp, 0);
 +      rlen = BIO_ctrl_pending(out);
 +      txt = os_malloc(rlen + 1);
 +      if (!txt) {
 +              BIO_free(out);
 +              return;
 +      }
 +
 +      res = BIO_read(out, txt, rlen);
 +      if (res > 0) {
 +              txt[res] = '\0';
 +              wpa_printf(MSG_DEBUG, "OpenSSL: OCSP Response\n%s", txt);
 +      }
 +      os_free(txt);
 +      BIO_free(out);
 +#endif /* CONFIG_NO_STDOUT_DEBUG */
 +}
 +
 +
 +static void debug_print_cert(X509 *cert, const char *title)
 +{
 +#ifndef CONFIG_NO_STDOUT_DEBUG
 +      BIO *out;
 +      size_t rlen;
 +      char *txt;
 +      int res;
 +
 +      if (wpa_debug_level > MSG_DEBUG)
 +              return;
 +
 +      out = BIO_new(BIO_s_mem());
 +      if (!out)
 +              return;
 +
 +      X509_print(out, cert);
 +      rlen = BIO_ctrl_pending(out);
 +      txt = os_malloc(rlen + 1);
 +      if (!txt) {
 +              BIO_free(out);
 +              return;
 +      }
 +
 +      res = BIO_read(out, txt, rlen);
 +      if (res > 0) {
 +              txt[res] = '\0';
 +              wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt);
 +      }
 +      os_free(txt);
 +
 +      BIO_free(out);
 +#endif /* CONFIG_NO_STDOUT_DEBUG */
 +}
 +
 +
 +static int ocsp_resp_cb(SSL *s, void *arg)
 +{
 +      struct tls_connection *conn = arg;
 +      const unsigned char *p;
 +      int len, status, reason;
 +      OCSP_RESPONSE *rsp;
 +      OCSP_BASICRESP *basic;
 +      OCSP_CERTID *id;
 +      ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update;
 +      X509_STORE *store;
 +      STACK_OF(X509) *certs = NULL;
 +
 +      len = SSL_get_tlsext_status_ocsp_resp(s, &p);
 +      if (!p) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
 +              return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
 +      }
 +
 +      wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len);
 +
 +      rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
 +      if (!rsp) {
 +              wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response");
 +              return 0;
 +      }
 +
 +      ocsp_debug_print_resp(rsp);
 +
 +      status = OCSP_response_status(rsp);
 +      if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
 +              wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)",
 +                         status, OCSP_response_status_str(status));
 +              return 0;
 +      }
 +
 +      basic = OCSP_response_get1_basic(rsp);
 +      if (!basic) {
 +              wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse");
 +              return 0;
 +      }
 +
 +      store = SSL_CTX_get_cert_store(conn->ssl_ctx);
 +      if (conn->peer_issuer) {
 +              debug_print_cert(conn->peer_issuer, "Add OCSP issuer");
 +
 +              if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) {
 +                      tls_show_errors(MSG_INFO, __func__,
 +                                      "OpenSSL: Could not add issuer to certificate store");
 +              }
 +              certs = sk_X509_new_null();
 +              if (certs) {
 +                      X509 *cert;
 +                      cert = X509_dup(conn->peer_issuer);
 +                      if (cert && !sk_X509_push(certs, cert)) {
 +                              tls_show_errors(
 +                                      MSG_INFO, __func__,
 +                                      "OpenSSL: Could not add issuer to OCSP responder trust store");
 +                              X509_free(cert);
 +                              sk_X509_free(certs);
 +                              certs = NULL;
 +                      }
 +                      if (certs && conn->peer_issuer_issuer) {
 +                              cert = X509_dup(conn->peer_issuer_issuer);
 +                              if (cert && !sk_X509_push(certs, cert)) {
 +                                      tls_show_errors(
 +                                              MSG_INFO, __func__,
 +                                              "OpenSSL: Could not add issuer's issuer to OCSP responder trust store");
 +                                      X509_free(cert);
 +                              }
 +                      }
 +              }
 +      }
 +
 +      status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER);
 +      sk_X509_pop_free(certs, X509_free);
 +      if (status <= 0) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "OpenSSL: OCSP response failed verification");
 +              OCSP_BASICRESP_free(basic);
 +              OCSP_RESPONSE_free(rsp);
 +              return 0;
 +      }
 +
 +      wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded");
 +
 +      if (!conn->peer_cert) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check");
 +              OCSP_BASICRESP_free(basic);
 +              OCSP_RESPONSE_free(rsp);
 +              return 0;
 +      }
 +
 +      if (!conn->peer_issuer) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check");
 +              OCSP_BASICRESP_free(basic);
 +              OCSP_RESPONSE_free(rsp);
 +              return 0;
 +      }
 +
 +      id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
 +      if (!id) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: Could not create OCSP certificate identifier");
 +              OCSP_BASICRESP_free(basic);
 +              OCSP_RESPONSE_free(rsp);
 +              return 0;
 +      }
 +
 +      if (!OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
 +                                 &this_update, &next_update)) {
 +              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__,
 +                              "OpenSSL: OCSP status times invalid");
 +              OCSP_BASICRESP_free(basic);
 +              OCSP_RESPONSE_free(rsp);
 +              return 0;
 +      }
 +
 +      OCSP_BASICRESP_free(basic);
 +      OCSP_RESPONSE_free(rsp);
 +
 +      wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s",
 +                 OCSP_cert_status_str(status));
 +
 +      if (status == V_OCSP_CERTSTATUS_GOOD)
 +              return 1;
 +      if (status == V_OCSP_CERTSTATUS_REVOKED)
 +              return 0;
 +      if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required");
 +              return 0;
 +      }
 +      wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue");
 +      return 1;
 +}
 +
 +
 +static int ocsp_status_cb(SSL *s, void *arg)
 +{
 +      char *tmp;
 +      char *resp;
 +      size_t len;
 +
 +      if (tls_global->ocsp_stapling_response == NULL) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - no response configured");
 +              return SSL_TLSEXT_ERR_OK;
 +      }
 +
 +      resp = os_readfile(tls_global->ocsp_stapling_response, &len);
 +      if (resp == NULL) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - could not read response file");
 +              /* TODO: Build OCSPResponse with responseStatus = internalError
 +               */
 +              return SSL_TLSEXT_ERR_OK;
 +      }
 +      wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - send cached response");
 +      tmp = OPENSSL_malloc(len);
 +      if (tmp == NULL) {
 +              os_free(resp);
 +              return SSL_TLSEXT_ERR_ALERT_FATAL;
 +      }
 +
 +      os_memcpy(tmp, resp, len);
 +      os_free(resp);
 +      SSL_set_tlsext_status_ocsp_resp(s, tmp, len);
 +
 +      return SSL_TLSEXT_ERR_OK;
 +}
 +
 +#endif /* HAVE_OCSP */
 +
 +
 +int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
 +                            const struct tls_connection_params *params)
 +{
 +      struct tls_data *data = tls_ctx;
 +      int ret;
 +      unsigned long err;
 +      int can_pkcs11 = 0;
 +      const char *key_id = params->key_id;
 +      const char *cert_id = params->cert_id;
 +      const char *ca_cert_id = params->ca_cert_id;
 +      const char *engine_id = params->engine ? params->engine_id : NULL;
 +
 +      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
 +       * use the PKCS#11 ENGINE.
 +       */
 +      if (!engine_id || os_strcmp(engine_id, "pkcs11") == 0)
 +              can_pkcs11 = 1;
 +
 +      if (!key_id && params->private_key && can_pkcs11 &&
 +          os_strncmp(params->private_key, "pkcs11:", 7) == 0) {
 +              can_pkcs11 = 2;
 +              key_id = params->private_key;
 +      }
 +
 +      if (!cert_id && params->client_cert && can_pkcs11 &&
 +          os_strncmp(params->client_cert, "pkcs11:", 7) == 0) {
 +              can_pkcs11 = 2;
 +              cert_id = params->client_cert;
 +      }
 +
 +      if (!ca_cert_id && params->ca_cert && can_pkcs11 &&
 +          os_strncmp(params->ca_cert, "pkcs11:", 7) == 0) {
 +              can_pkcs11 = 2;
 +              ca_cert_id = params->ca_cert;
 +      }
 +
 +      /* If we need to automatically enable the PKCS#11 ENGINE, do so. */
 +      if (can_pkcs11 == 2 && !engine_id)
 +              engine_id = "pkcs11";
 +
 +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
 +#if OPENSSL_VERSION_NUMBER < 0x10100000L
 +      if (params->flags & TLS_CONN_EAP_FAST) {
 +              wpa_printf(MSG_DEBUG,
 +                         "OpenSSL: Use TLSv1_method() for EAP-FAST");
 +              if (SSL_set_ssl_method(conn->ssl, TLSv1_method()) != 1) {
 +                      tls_show_errors(MSG_INFO, __func__,
 +                                      "Failed to set TLSv1_method() for EAP-FAST");
 +                      return -1;
 +              }
 +      }
 +#endif
 +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
 +
 +      while ((err = ERR_get_error())) {
 +              wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
 +                         __func__, ERR_error_string(err, NULL));
 +      }
 +
 +      if (engine_id) {
 +              wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
 +              ret = tls_engine_init(conn, engine_id, params->pin,
 +                                    key_id, cert_id, ca_cert_id);
 +              if (ret)
 +                      return ret;
 +      }
 +      if (tls_connection_set_subject_match(conn,
 +                                           params->subject_match,
 +                                           params->altsubject_match,
 +                                           params->suffix_match,
 +                                           params->domain_match))
 +              return -1;
 +
 +      if (engine_id && ca_cert_id) {
 +              if (tls_connection_engine_ca_cert(data, conn, ca_cert_id))
 +                      return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
 +      } else {
 +        if (tls_connection_ca_cert(data, conn, params->ca_cert,
 +                                   params->ca_cert_blob,
 +                                   params->ca_cert_blob_len,
 +                                   params->ca_path, params->server_cert_cb, 
 +                                   params->server_cert_ctx))
 +            return -1;
 +    }
 +
 +      if (engine_id && cert_id) {
 +              if (tls_connection_engine_client_cert(conn, cert_id))
 +                      return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
 +      } else if (tls_connection_client_cert(conn, params->client_cert,
 +                                            params->client_cert_blob,
 +                                            params->client_cert_blob_len))
 +              return -1;
 +
 +      if (engine_id && key_id) {
 +              wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
 +              if (tls_connection_engine_private_key(conn))
 +                      return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
 +      } else if (tls_connection_private_key(data, conn,
 +                                            params->private_key,
 +                                            params->private_key_passwd,
 +                                            params->private_key_blob,
 +                                            params->private_key_blob_len)) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'",
 +                         params->private_key);
 +              return -1;
 +      }
 +
 +      if (tls_connection_dh(conn, params->dh_file)) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
 +                         params->dh_file);
 +              return -1;
 +      }
 +
 +      if (params->openssl_ciphers &&
 +          SSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
 +              wpa_printf(MSG_INFO,
 +                         "OpenSSL: Failed to set cipher string '%s'",
 +                         params->openssl_ciphers);
 +              return -1;
 +      }
 +
 +      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;
 +              SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp);
 +              SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb);
 +              SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn);
 +      }
 +#else /* HAVE_OCSP */
 +      if (params->flags & TLS_CONN_REQUIRE_OCSP) {
 +              wpa_printf(MSG_INFO,
 +                         "OpenSSL: No OCSP support included - reject configuration");
 +              return -1;
 +      }
 +      if (params->flags & TLS_CONN_REQUEST_OCSP) {
 +              wpa_printf(MSG_DEBUG,
 +                         "OpenSSL: No OCSP support included - allow optional OCSP case to continue");
 +      }
 +#endif /* HAVE_OCSP */
++#endif /* OPENSSL_IS_BORINGSSL */
 +
 +      conn->flags = params->flags;
 +
 +      tls_get_errors(data);
 +
 +      return 0;
 +}
 +
 +
 +int tls_global_set_params(void *tls_ctx,
 +                        const struct tls_connection_params *params)
 +{
 +      struct tls_data *data = tls_ctx;
 +      SSL_CTX *ssl_ctx = data->ssl;
 +      unsigned long err;
 +
 +      while ((err = ERR_get_error())) {
 +              wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
 +                         __func__, ERR_error_string(err, NULL));
 +      }
 +
 +      if (tls_global_ca_cert(data, params->ca_cert) ||
 +          tls_global_client_cert(data, params->client_cert) ||
 +          tls_global_private_key(data, params->private_key,
 +                                 params->private_key_passwd) ||
 +          tls_global_dh(data, params->dh_file)) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to set global parameters");
 +              return -1;
 +      }
 +
 +      if (params->openssl_ciphers &&
 +          SSL_CTX_set_cipher_list(ssl_ctx, params->openssl_ciphers) != 1) {
 +              wpa_printf(MSG_INFO,
 +                         "OpenSSL: Failed to set cipher string '%s'",
 +                         params->openssl_ciphers);
 +              return -1;
 +      }
 +
 +#ifdef SSL_OP_NO_TICKET
 +      if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
 +              SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
 +#ifdef SSL_CTX_clear_options
 +      else
 +              SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
 +#endif /* SSL_clear_options */
 +#endif /*  SSL_OP_NO_TICKET */
 +
 +#ifdef HAVE_OCSP
 +      SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_status_cb);
 +      SSL_CTX_set_tlsext_status_arg(ssl_ctx, ssl_ctx);
 +      os_free(tls_global->ocsp_stapling_response);
 +      if (params->ocsp_stapling_response)
 +              tls_global->ocsp_stapling_response =
 +                      os_strdup(params->ocsp_stapling_response);
 +      else
 +              tls_global->ocsp_stapling_response = NULL;
 +#endif /* HAVE_OCSP */
 +
 +      return 0;
 +}
 +
 +
 +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
 +/* Pre-shared secred requires a patch to openssl, so this function is
 + * commented out unless explicitly needed for EAP-FAST in order to be able to
 + * build this file with unmodified openssl. */
 +
- #if OPENSSL_VERSION_NUMBER < 0x10100000L
++#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)
 +#else /* OPENSSL_IS_BORINGSSL */
 +static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
 +                         STACK_OF(SSL_CIPHER) *peer_ciphers,
 +                         SSL_CIPHER **cipher, void *arg)
 +#endif /* OPENSSL_IS_BORINGSSL */
 +{
 +      struct tls_connection *conn = arg;
 +      int ret;
 +
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
 +      if (conn == NULL || conn->session_ticket_cb == NULL)
 +              return 0;
 +
 +      ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
 +                                    conn->session_ticket,
 +                                    conn->session_ticket_len,
 +                                    s->s3->client_random,
 +                                    s->s3->server_random, secret);
 +#else
 +      unsigned char client_random[SSL3_RANDOM_SIZE];
 +      unsigned char server_random[SSL3_RANDOM_SIZE];
 +
 +      if (conn == NULL || conn->session_ticket_cb == NULL)
 +              return 0;
 +
 +      SSL_get_client_random(s, client_random, sizeof(client_random));
 +      SSL_get_server_random(s, server_random, sizeof(server_random));
 +
 +      ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
 +                                    conn->session_ticket,
 +                                    conn->session_ticket_len,
 +                                    client_random,
 +                                    server_random, secret);
 +#endif
 +
 +      os_free(conn->session_ticket);
 +      conn->session_ticket = NULL;
 +
 +      if (ret <= 0)
 +              return 0;
 +
 +      *secret_len = SSL_MAX_MASTER_KEY_LENGTH;
 +      return 1;
 +}
 +
 +
 +static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
 +                                   int len, void *arg)
 +{
 +      struct tls_connection *conn = arg;
 +
 +      if (conn == NULL || conn->session_ticket_cb == NULL)
 +              return 0;
 +
 +      wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len);
 +
 +      os_free(conn->session_ticket);
 +      conn->session_ticket = NULL;
 +
 +      wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
 +                  "extension", data, len);
 +
 +      conn->session_ticket = os_malloc(len);
 +      if (conn->session_ticket == NULL)
 +              return 0;
 +
 +      os_memcpy(conn->session_ticket, data, len);
 +      conn->session_ticket_len = len;
 +
 +      return 1;
 +}
 +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
 +
 +
 +int tls_connection_set_session_ticket_cb(void *tls_ctx,
 +                                       struct tls_connection *conn,
 +                                       tls_session_ticket_cb cb,
 +                                       void *ctx)
 +{
 +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
 +      conn->session_ticket_cb = cb;
 +      conn->session_ticket_cb_ctx = ctx;
 +
 +      if (cb) {
 +              if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
 +                                            conn) != 1)
 +                      return -1;
 +              SSL_set_session_ticket_ext_cb(conn->ssl,
 +                                            tls_session_ticket_ext_cb, conn);
 +      } else {
 +              if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
 +                      return -1;
 +              SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL);
 +      }
 +
 +      return 0;
 +#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
 +      return -1;
 +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
 +}
 +
 +
 +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
 +}
 +
 +
 +void tls_connection_set_success_data(struct tls_connection *conn,
 +                                   struct wpabuf *data)
 +{
 +      SSL_SESSION *sess;
 +      struct wpabuf *old;
 +
 +      if (tls_ex_idx_session < 0)
 +              goto fail;
 +      sess = SSL_get_session(conn->ssl);
 +      if (!sess)
 +              goto fail;
 +      old = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
 +      if (old) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: Replacing old success data %p",
 +                         old);
 +              wpabuf_free(old);
 +      }
 +      if (SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
 +              goto fail;
 +
 +      wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p", data);
 +      conn->success_data = 1;
 +      return;
 +
 +fail:
 +      wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data");
 +      wpabuf_free(data);
 +}
 +
 +
 +void tls_connection_set_success_data_resumed(struct tls_connection *conn)
 +{
 +      wpa_printf(MSG_DEBUG,
 +                 "OpenSSL: Success data accepted for resumed session");
 +      conn->success_data = 1;
 +}
 +
 +
 +const struct wpabuf *
 +tls_connection_get_success_data(struct tls_connection *conn)
 +{
 +      SSL_SESSION *sess;
 +
 +      if (tls_ex_idx_session < 0 ||
 +          !(sess = SSL_get_session(conn->ssl)))
 +              return NULL;
 +      return SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
 +}
 +
 +
 +void tls_connection_remove_session(struct tls_connection *conn)
 +{
 +      SSL_SESSION *sess;
 +
 +      sess = SSL_get_session(conn->ssl);
 +      if (!sess)
 +              return;
 +
 +      if (SSL_CTX_remove_session(conn->ssl_ctx, sess) != 1)
 +              wpa_printf(MSG_DEBUG,
 +                         "OpenSSL: Session was not cached");
 +      else
 +              wpa_printf(MSG_DEBUG,
 +                         "OpenSSL: Removed cached session to disable session resumption");
 +}
index 0000000,2a62d5c..2a62d5c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,19 +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 */
index 0000000,8b37b34..8b37b34
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,846 +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 */
  #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 +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 +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
         */
        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 +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 +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 {
        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 +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;
        /** 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;
  
   * 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 */
        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 +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;
        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 +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 +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 +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
         *
         * @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
  
        /**
         * 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
         * 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
         * @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);
  
         *      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
         * 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
         * 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
         * 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
         * 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 +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 +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;
  
        /**
         * struct interface_status - Data for EVENT_INTERFACE_STATUS
         */
        struct interface_status {
+               unsigned int ifindex;
                char ifname[100];
                enum {
                        EVENT_INTERFACE_ADDED, EVENT_INTERFACE_REMOVED
                 * 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 {
         * @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;
                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;
  
        /**
                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;
  };
  
  /**
  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 +4937,52 @@@ int vht_supported(const struct hostapd_
  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 */
@@@ -189,13 -189,13 +189,13 @@@ set80211priv(struct atheros_driver_dat
            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 +222,10 @@@ set80211param(struct atheros_driver_dat
  {
        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 +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 +422,7 @@@ atheros_set_sta_authorized(void *priv, 
        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 +455,9 @@@ atheros_del_key(void *priv, const u8 *a
        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 +538,20 @@@ atheros_set_key(const char *ifname, voi
                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 +575,11 @@@ atheros_get_seqnum(const char *ifname, 
        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))) {
  #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 +616,7 @@@ static in
  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 +629,19 @@@ atheros_read_sta_driver_data(void *priv
        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 +668,7 @@@ atheros_sta_clear_stats(void *priv, con
        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 +744,7 @@@ atheros_sta_deauth(void *priv, const u
  
        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 +768,7 @@@ atheros_sta_disassoc(void *priv, const 
  
        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 +794,7 @@@ static int atheros_set_qos_map(void *ct
                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 +855,29 @@@ static void atheros_raw_receive(void *c
                   (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__);
                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 +1123,8 @@@ atheros_new_sta(struct atheros_driver_d
        /*
         * 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
  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 +1188,10 @@@ atheros_wireless_event_wireless_custom(
  #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 "
                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
                 * 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;
                                    (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);
                }
                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;
                                    (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 +1387,7 @@@ atheros_wireless_event_atheros_custom(s
  
  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;
        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;
                        /* 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;
                }
  
                         * 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) {
                                atheros_wireless_event_wireless_custom(
                                        drv, buf, buf + iwe->u.data.length);
                        }
-                       free(buf);
+                       os_free(buf);
                        break;
                }
  
@@@ -1500,7 -1503,7 +1503,7 @@@ atheros_get_we_version(struct atheros_d
        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 +1572,7 @@@ atheros_send_eapol(void *priv, const u
         */
        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!",
                }
        }
        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 +1625,9 @@@ atheros_init(struct hostapd_data *hapd
                           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",
        } 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 +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 +1731,7 @@@ atheros_set_ssid(void *priv, const u8 *
        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 +1752,7 @@@ atheros_get_ssid(void *priv, u8 *buf, i
        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 +1851,8 @@@ static int atheros_set_ap(void *priv, s
  #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];
        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 "
  
  #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 */
        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;
        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 +142,7 @@@ bsd_get80211(void *priv, struct ieee802
        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 +183,7 @@@ bsd_get_ssid(void *priv, u8 *ssid, int 
        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 +206,7 @@@ bsd_set_ssid(void *priv, const u8 *ssid
        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 +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 +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 +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)
                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 +618,7 @@@ bsd_set_freq(void *priv, struct hostapd
        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 +772,8 @@@ bsd_sta_disassoc(void *priv, const u8 *
  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;
        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",
                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 +857,15 @@@ bsd_init(struct hostapd_data *hapd, str
                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,
        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 +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 +956,7 @@@ wpa_driver_bsd_get_bssid(void *priv, u
        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 +990,7 @@@ wpa_driver_bsd_set_wpa_internal(void *p
        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;
  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 +1210,8 @@@ wpa_driver_bsd_scan(void *priv, struct 
  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;
        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",
                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);
        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 */
                        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 +1376,16 @@@ wpa_driver_bsd_add_scan_entry(struct wp
        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 +1540,7 @@@ get80211opmode(struct bsd_driver_data *
        (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;
  }
  
  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)
        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
        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",
        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 +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 +1657,74 @@@ wpa_driver_bsd_get_capa(void *priv, str
  }
  #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,
        .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,
@@@ -80,6 -80,7 +80,7 @@@ const char * event_to_string(enum wpa_e
        E2S(NEW_PEER_CANDIDATE);
        E2S(ACS_CHANNEL_SELECTED);
        E2S(DFS_CAC_STARTED);
+       E2S(P2P_LO_STOP);
        }
  
        return "UNKNOWN";
@@@ -183,12 -184,12 +184,12 @@@ wpa_get_wowlan_triggers(const char *wow
  
        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 +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
+ }
@@@ -258,7 -258,8 +258,8 @@@ static int hostap_init_sockets(struct h
  
  
  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 +308,7 @@@ static int hostap_send_eapol(void *priv
        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 +814,7 @@@ hostapd_wireless_event_wireless_custom(
  
  
  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;
        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;
  
                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 +1046,7 @@@ static int hostap_sta_deauth(void *priv
        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 +1084,7 @@@ static int hostap_sta_disassoc(void *pr
        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 +1162,7 @@@ static void wpa_driver_hostap_poll_clie
        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);
  }
  
  
@@@ -11,6 -11,7 +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 +486,12 @@@ static int macsec_qca_set_replay_protec
  }
  
  
- 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;
        }
  
@@@ -35,6 -35,7 +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 +781,7 @@@ static int wpa_driver_ndis_scan(void *p
  
  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);
  }
  
  
@@@ -176,13 -176,19 +176,19 @@@ wpa_driver_nl80211_finish_drv_init(stru
  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 +200,10 @@@ static int nl80211_leave_ibss(struct wp
  
  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 +449,8 @@@ static int nl_get_multicast_id(struct n
  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 +769,15 @@@ static void nl80211_put_wiphy_data_ap(s
  }
  
  
+ 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 +801,12 @@@ static int wpa_driver_nl80211_get_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);
        }
  
        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);
        }
  
        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 +915,7 @@@ nl80211_find_drv(struct nl80211_global 
        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 +935,6 @@@ static void wpa_driver_nl80211_event_rt
        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);
                   (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) &&
                                       -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 */
                }
                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 +1117,6 @@@ static void wpa_driver_nl80211_event_rt
        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);
                   (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];
  
                                   "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 +1547,16 @@@ static void nl80211_check_global(struc
  
  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 +1569,16 @@@ static void wpa_driver_nl80211_rfkill_u
                           "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 +1663,65 @@@ static void nl80211_destroy_bss(struct 
  }
  
  
+ 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)
  
        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) {
        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 +1995,10 @@@ static int nl80211_mgmt_subscribe_non_a
        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 +2060,49 @@@ static int nl80211_register_spurious_cl
  }
  
  
+ 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[] = {
                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
                }
        }
  
+       if (nl80211_action_subscribe_ap(bss))
+               goto out_err;
        if (nl80211_register_spurious_class3(bss))
                goto out_err;
  
@@@ -2032,10 -2160,7 +2160,7 @@@ static int nl80211_mgmt_subscribe_ap_de
        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 +2311,11 @@@ wpa_driver_nl80211_finish_drv_init(stru
        if (!bss->if_dynamic && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
                bss->static_ap = 1;
  
+       if (first &&
+           nl80211_get_ifmode(bss) != NL80211_IFTYPE_P2P_DEVICE &&
+           linux_iface_up(drv->global->ioctl_sock, bss->ifname) > 0)
+               drv->start_iface_up = 1;
        if (wpa_driver_nl80211_capa(drv))
                return -1;
  
  
        if (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;
        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) {
                                   "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 +2419,7 @@@ static int wpa_driver_nl80211_del_beaco
  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);
        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);
  
  
        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 +2616,7 @@@ static int wpa_cipher_to_cipher_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)
  {
  
        return ret;
  }
+ #endif /* CONFIG_DRIVER_NL80211_QCA */
  
  
  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",
                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 +3241,9 @@@ static int wpa_driver_nl80211_send_fram
                                         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;
  
        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 +3296,9 @@@ static int wpa_driver_nl80211_send_mlme
                                        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;
                }
                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)) {
                                              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 &&
        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 +3473,48 @@@ static int nl80211_put_beacon_int(struc
  }
  
  
+ 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)
  {
        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;
  
            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) {
                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",
            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",
        }
  #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)",
                                           "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
                        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 +3841,12 @@@ static int nl80211_put_freq_params(stru
                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 +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;
  }
  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 +3952,17 @@@ static int wpa_driver_nl80211_sta_add(v
        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",
                                    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) {
                        /*
                         * 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;
                }
                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) {
        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 +4235,11 @@@ void nl80211_remove_iface(struct wpa_dr
        /* 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)
  }
  
  
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 +4347,7 @@@ static int nl80211_create_iface_once(st
            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 +4430,8 @@@ static int nl80211_setup_ap(struct i802
  
        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 +4551,7 @@@ static int wpa_driver_nl80211_hapd_send
        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 +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 +4956,24 @@@ static int nl80211_connect_common(struc
        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;
        }
        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 +5013,7 @@@ static int wpa_driver_nl80211_try_conne
        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 ||
                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 +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 +5207,9 @@@ static int wpa_driver_nl80211_set_mode_
        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 +5566,8 @@@ static int get_sta_handler(struct nl_ms
                [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),
        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 +5778,7 @@@ static int i802_sta_deauth(void *priv, 
        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 +5805,7 @@@ static int i802_sta_disassoc(void *priv
        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 +5820,9 @@@ static void dump_ifidx(struct wpa_drive
        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;
  }
  
  
- 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;
        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;
                }
        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;
                }
  }
  
  
- 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 +5994,7 @@@ static void handle_eapol(int sock, voi
                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 +6021,7 @@@ static int i802_check_bridge(struct wpa
                }
                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 +6083,15 @@@ static void *i802_init(struct hostapd_d
                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';
        }
                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],
  
        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 +6266,8 @@@ static int wpa_driver_nl80211_if_add(vo
                                     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;
                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)
             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 +6427,10 @@@ static int wpa_driver_nl80211_if_remove
        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 +6508,8 @@@ static int nl80211_send_frame_cmd(struc
                                  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;
             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;
  
  
                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 +6604,28 @@@ static int wpa_driver_nl80211_send_acti
             !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;
        }
  }
  
  
+ 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 +6883,13 @@@ static int wpa_driver_nl80211_deinit_p2
  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 +6962,12 @@@ static int nl80211_signal_poll(void *pr
  
        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 +6982,21 @@@ static int nl80211_send_frame(void *pri
  {
        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;
        }
  #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;
        }
  }
  
  
- static void * nl80211_global_init(void)
+ static void * nl80211_global_init(void *ctx)
  {
        struct nl80211_global *global;
        struct netlink_config *cfg;
        global = os_zalloc(sizeof(*global));
        if (global == NULL)
                return NULL;
+       global->ctx = ctx;
        global->ioctl_sock = -1;
        dl_list_init(&global->interfaces);
        global->if_add_ifindex = -1;
@@@ -6954,7 -7388,7 +7388,7 @@@ static void nl80211_send_null_frame(str
        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 +7658,19 @@@ static int driver_nl80211_scan2(void *p
                                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 +7708,13 @@@ static int driver_nl80211_if_remove(voi
  
  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 +7789,7 @@@ static int wpa_driver_nl80211_update_ft
  }
  
  
- 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 +7944,10 @@@ static int wpa_driver_nl80211_status(vo
                                  "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,
                                  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 +8012,8 @@@ static int nl80211_switch_channel(void 
        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,
            (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) ||
        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 +8355,7 @@@ static int nl80211_set_wowlan(void *pri
  }
  
  
+ #ifdef CONFIG_DRIVER_NL80211_QCA
  static int nl80211_roaming(void *priv, int allowed, const u8 *bssid)
  {
        struct i802_bss *bss = priv;
  
        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)
        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 +8460,46 @@@ static int nl80211_put_mesh_id(struct n
  }
  
  
+ 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)
  {
            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);
                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) {
                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 +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 +9225,215 @@@ static int nl80211_set_prob_oper_freq(v
  }
  
  
+ 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",
        .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,
        .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,
        .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,
  };
@@@ -25,6 -25,7 +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 +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;
        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;
        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;
  
        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 */
        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 +259,8 @@@ nl80211_get_hw_feature_data(void *priv
  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 +295,13 @@@ void wpa_driver_nl80211_scan_timeout(vo
  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 */
@@@ -66,7 -66,6 +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 +128,6 @@@ static void wiphy_info_supported_iftype
                case NL80211_IFTYPE_P2P_CLIENT:
                        info->p2p_client_supported = 1;
                        break;
-               case NL80211_IFTYPE_MONITOR:
-                       info->monitor_supported = 1;
-                       break;
                }
        }
  }
@@@ -352,13 -348,20 +348,20 @@@ static void wiphy_info_ext_feature_flag
                                         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 +431,9 @@@ static void wiphy_info_feature_flags(st
  
        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 +482,74 @@@ static void wiphy_info_wowlan_triggers(
  }
  
  
+ 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];
        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]),
                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]);
                                  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]));
                        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;
                }
        }
  
+       wiphy_info_extended_capab(drv, tb[NL80211_ATTR_IFTYPE_EXT_CAPA]);
        if (tb[NL80211_ATTR_VENDOR_DATA]) {
                struct nlattr *nl;
                int rem;
                                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;
                                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 */
                                }
                        }
  
                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 +800,6 @@@ static int wpa_driver_nl80211_get_info(
        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 =
        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 +903,12 @@@ static int features_info_handler(struc
  
                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 +967,17 @@@ static void qca_nl80211_get_features(st
  
        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)
  {
         * 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
        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 +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 +1186,7 @@@ static int phy_info_freqs(struct phy_in
                                   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 +1232,7 @@@ static int phy_info_rates(struct hostap
  
        mode->rates = os_calloc(mode->num_rates, sizeof(int));
        if (!mode->rates)
-               return NL_SKIP;
+               return NL_STOP;
  
        idx = 0;
  
@@@ -1125,8 -1261,10 +1261,10 @@@ static int phy_info_band(struct phy_inf
                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)];
        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 +1520,7 @@@ static void nl80211_reg_rule_sec(struc
  
  
  static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
-                                int end)
+                                int end, int max_bw)
  {
        int c;
  
  
                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 +1593,7 @@@ static void nl80211_reg_rule_vht(struc
                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 +1731,7 @@@ nl80211_get_hw_feature_data(void *priv
                .num_modes = num_modes,
                .modes = NULL,
                .last_mode = -1,
+               .failed = 0,
        };
  
        *num_modes = 0;
  
        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);
        }
@@@ -265,10 -265,12 +265,12 @@@ static void mlme_event_connect(struct w
                               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;
                return;
        }
  
+       drv->connect_reassoc = 0;
        status_code = status ? nla_get_u16(status) : WLAN_STATUS_SUCCESS;
  
        if (cmd == NL80211_CMD_CONNECT) {
                        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;
        }
                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]);
                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 +576,10 @@@ static void mlme_event_mgmt(struct i802
                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 +656,39 @@@ static void mlme_event_deauth_disassoc(
                         * 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;
                }
  
                                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 +916,7 @@@ static void mlme_event_join_ibss(struc
                                 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 "
                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 +1020,7 @@@ static void mlme_event_ft_event(struct 
  
  
  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;
        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");
        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) {
                }
        }
        if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
-               char msg[200], *pos, *end;
+               char msg[300], *pos, *end;
                int res;
  
                pos = msg;
@@@ -1109,7 -1163,7 +1163,7 @@@ static void nl80211_new_peer_candidate(
                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 +1208,7 @@@ static void nl80211_new_station_event(s
  
  
  static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
+                                     struct i802_bss *bss,
                                      struct nlattr **tb)
  {
        u8 *addr;
                   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;
        }
  
  
        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 +1499,8 @@@ static void nl80211_spurious_frame(stru
  }
  
  
+ #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 +1650,12 @@@ static void qca_nl80211_key_mgmt_auth(s
                           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 +1745,165 @@@ static void qca_nl80211_dfs_offload_rad
  }
  
  
+ 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)
  {
        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;
        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 +2060,7 @@@ static void do_process_drv_event(struc
  {
        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);
        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:
                                   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,
                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);
@@@ -136,7 -136,7 +136,7 @@@ static void handle_monitor_read(int soc
                        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:
@@@ -1,5 -1,6 +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 +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 +96,20 @@@ static int nl80211_get_noise_for_scan_r
  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 +142,8 @@@ nl80211_scan_common(struct i802_bss *bs
                                goto fail;
                }
                nla_nest_end(msg, ssids);
+       } else {
+               wpa_printf(MSG_DEBUG, "nl80211: Passive scan requested");
        }
  
        if (params->extra_ies) {
@@@ -252,6 -265,13 +265,13 @@@ int wpa_driver_nl80211_scan(struct i802
                        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) {
        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);
  }
  
  
+ 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;
                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) {
                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 +538,6 @@@ int wpa_driver_nl80211_stop_sched_scan(
  }
  
  
- 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)
  {
        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 +708,9 @@@ int bss_info_handler(struct nl_msg *msg
                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 +861,263 @@@ void nl80211_dump_scan(struct wpa_drive
  
        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 */
@@@ -161,11 -161,11 +161,11 @@@ wpa_driver_privsep_get_scan_results2(vo
                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);
@@@ -1,6 -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 +401,9 @@@ static void * wpa_driver_roboswitch_ini
                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);
@@@ -422,7 -422,7 +422,7 @@@ static void wpa_driver_wext_event_assoc
  
  
  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;
        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;
                        }
                        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;
                                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;
                                             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;
                                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;
                                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 +1220,7 @@@ static void wext_get_scan_ssid(struct i
                               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 +1316,7 @@@ static void wext_get_scan_rate(struct i
        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 +1369,7 @@@ static void wext_get_scan_custom(struc
        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 +1441,8 @@@ static void wpa_driver_wext_add_scan_en
        /* 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 +1530,11 @@@ struct wpa_scan_results * wpa_driver_we
        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;
@@@ -8,12 -8,17 +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 */
  #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[] =
  {
@@@ -29,12 -29,15 +29,15 @@@ DRV_OBJS += ../src/drivers/driver_nl802
  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 +63,9 @@@ els
    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 +164,10 @@@ ifdef NEED_RFKIL
  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
@@@ -25,12 -25,15 +25,15 @@@ DRV_OBJS += src/drivers/driver_nl80211_
  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 +51,9 @@@ els
    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 +149,10 @@@ ifdef NEED_RFKIL
  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
@@@ -10,6 -10,7 +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 +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 */
   * @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
   *    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.
   *    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 +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 +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 +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 +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,
   *    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 +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 +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
   * 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,
        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,
  
  #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 +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 +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,
  #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 +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 +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 +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 +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 +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 +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 +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 */
@@@ -8,6 -8,7 +8,7 @@@
  
  #include "includes.h"
  #include <fcntl.h>
+ #include <limits.h>
  
  #include "utils/common.h"
  #include "utils/eloop.h"
@@@ -47,6 -48,7 +48,7 @@@ struct rfkill_data 
        struct rfkill_config *cfg;
        int fd;
        int blocked;
+       uint32_t idx;
  };
  
  
@@@ -69,12 -71,13 +71,13 @@@ static void rfkill_receive(int sock, vo
                           (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 +105,23 @@@ struct rfkill_data * rfkill_init(struc
        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) {
                                   (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;
                        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 +194,8 @@@ fail2
        close(rfkill->fd);
  fail:
        os_free(rfkill);
+       /* use standard free function to match realpath() */
+       free(phy);
        return NULL;
  }
  
@@@ -44,9 -44,7 +44,7 @@@ static int eap_eke_dhcomp_len(u8 dhgrou
        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 +164,10 @@@ int eap_eke_dh_init(u8 group, u8 *ret_p
        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 +406,8 @@@ int eap_eke_shared_secret(struct eap_ek
        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 +627,7 @@@ int eap_eke_prot(struct eap_eke_sessio
  
        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;
  
                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 +675,8 @@@ int eap_eke_decrypt_prot(struct eap_eke
        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 +727,14 @@@ int eap_eke_session_init(struct eap_eke
        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;
@@@ -93,8 -93,7 +93,7 @@@ void eap_fast_derive_master_secret(cons
  }
  
  
- 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;
  
        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;
        }
  }
  
  
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
         *        "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,0000000..40d8a42
mode 100644,000000..100644
--- /dev/null
@@@ -1,115 -1,0 +1,115 @@@
-                        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);
 +/*
 + * EAP-FAST definitions (RFC 4851)
 + * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
 + *
 + * This software may be distributed under the terms of the BSD license.
 + * See README for more details.
 + */
 +
 +#ifndef EAP_FAST_H
 +#define EAP_FAST_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +#define EAP_FAST_VERSION 1
 +#define EAP_FAST_KEY_LEN 64
 +#define EAP_FAST_SIMCK_LEN 40
 +#define EAP_FAST_SKS_LEN 40
 +#define EAP_FAST_CMK_LEN 20
 +
 +#define TLS_EXT_PAC_OPAQUE 35
 +
 +/*
 + * RFC 5422: Section 4.2.1 - Formats for PAC TLV Attributes / Type Field
 + * Note: bit 0x8000 (Mandatory) and bit 0x4000 (Reserved) are also defined
 + * in the general PAC TLV format (Section 4.2).
 + */
 +#define PAC_TYPE_PAC_KEY 1
 +#define PAC_TYPE_PAC_OPAQUE 2
 +#define PAC_TYPE_CRED_LIFETIME 3
 +#define PAC_TYPE_A_ID 4
 +#define PAC_TYPE_I_ID 5
 +/*
 + * 6 was previous assigned for SERVER_PROTECTED_DATA, but
 + * draft-cam-winget-eap-fast-provisioning-02.txt changed this to Reserved.
 + */
 +#define PAC_TYPE_A_ID_INFO 7
 +#define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8
 +#define PAC_TYPE_PAC_INFO 9
 +#define PAC_TYPE_PAC_TYPE 10
 +
 +#ifdef _MSC_VER
 +#pragma pack(push, 1)
 +#endif /* _MSC_VER */
 +
 +struct pac_tlv_hdr {
 +      be16 type;
 +      be16 len;
 +} STRUCT_PACKED;
 +
 +#ifdef _MSC_VER
 +#pragma pack(pop)
 +#endif /* _MSC_VER */
 +
 +
 +#define EAP_FAST_PAC_KEY_LEN 32
 +
 +/* RFC 5422: 4.2.6 PAC-Type TLV */
 +#define PAC_TYPE_TUNNEL_PAC 1
 +/* Application Specific Short Lived PACs (only in volatile storage) */
 +/* User Authorization PAC */
 +#define PAC_TYPE_USER_AUTHORIZATION 3
 +/* Application Specific Long Lived PACs */
 +/* Machine Authentication PAC */
 +#define PAC_TYPE_MACHINE_AUTHENTICATION 2
 +
 +
 +/*
 + * RFC 5422:
 + * Section 3.3 - Key Derivations Used in the EAP-FAST Provisioning Exchange
 + */
 +struct eap_fast_key_block_provisioning {
 +      /* Extra key material after TLS key_block */
 +      u8 session_key_seed[EAP_FAST_SKS_LEN];
 +      u8 server_challenge[16]; /* MSCHAPv2 ServerChallenge */
 +      u8 client_challenge[16]; /* MSCHAPv2 ClientChallenge */
 +};
 +
 +
 +struct wpabuf;
 +struct tls_connection;
 +
 +struct eap_fast_tlv_parse {
 +      u8 *eap_payload_tlv;
 +      size_t eap_payload_tlv_len;
 +      struct eap_tlv_crypto_binding_tlv *crypto_binding;
 +      size_t crypto_binding_len;
 +      int iresult;
 +      int result;
 +      int request_action;
 +      u8 *pac;
 +      size_t pac_len;
 +};
 +
 +void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len);
 +void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data,
 +                    u16 len);
 +void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type,
 +                        const struct wpabuf *data);
 +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,
++                       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);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_FAST_H */
@@@ -92,7 -92,8 +92,8 @@@ static int eap_gpsk_gkdf_sha256(const u
        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 +535,7 @@@ int eap_gpsk_compute_mic(const u8 *sk, 
                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:
                break;
        }
  
+       if (ret)
+               wpa_printf(MSG_DEBUG, "EAP-GPSK: Could not compute MIC");
        return ret;
  }
@@@ -57,7 -57,8 +57,8 @@@ int eap_pax_kdf(u8 mac_id, const u8 *ke
        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 +107,8 @@@ int eap_pax_mac(u8 mac_id, const u8 *ke
        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;
@@@ -115,6 -115,26 +115,26 @@@ int compute_password_element(EAP_PWD_gr
          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;
@@@ -121,7 -121,7 +121,7 @@@ static int eap_sake_parse_add_attr(stru
                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);
@@@ -62,13 -62,15 +62,15 @@@ int ikev2_integ_hash(int alg, const u8 
        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 +100,13 @@@ int ikev2_prf_hash(int alg, const u8 *k
  {
        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;
  }
  
  
@@@ -48,6 -48,8 +48,8 @@@ static void eap_sm_parseEapReq(struct e
  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 +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 +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 +1386,10 @@@ static int eap_sm_imsi_identity(struct 
        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
                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 +1459,27 @@@ struct wpabuf * eap_sm_buildIdentity(st
                                  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 +1520,9 @@@ static void eap_sm_processNotify(struc
  
  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 +1854,11 @@@ static void eap_peer_sm_tls_event(void 
        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 +2181,10 @@@ int eap_sm_get_status(struct eap_sm *sm
  #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;
        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)
  {
@@@ -1492,7 -1492,6 +1492,6 @@@ static u8 * eap_aka_get_emsk(struct eap
  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");
        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);
  }
  
  
  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,
        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,0000000..fca972f
mode 100644,000000..100644
--- /dev/null
@@@ -1,826 -1,0 +1,840 @@@
-        * server certificate. If this string is set, the server sertificate is
 +/*
 + * EAP peer configuration data
 + * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
 + *
 + * This software may be distributed under the terms of the BSD license.
 + * See README for more details.
 + */
 +
 +#ifndef EAP_CONFIG_H
 +#define EAP_CONFIG_H
 +
 +#include <openssl/x509.h>
 +
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +/* http://tools.ietf.org/html/draft-ietf-emu-chbind-13#section-5.3.1 */
 +#define CHBIND_CODE_REQUEST 1
 +#define CHBIND_CODE_SUCCESS 2
 +#define CHBIND_CODE_FAILURE 3
 +/* http://tools.ietf.org/html/draft-ietf-emu-chbind-13#section-5.3. */
 +#define CHBIND_NSID_RADIUS 1
 +
 +struct eap_peer_chbind_config
 +{
 +    /* namespace id for this channel binding info */
 +    int nsid;
 +
 +    /* data to be sent in channel binding request */
 +    u8 *req_data;
 +
 +    size_t req_data_len;
 +
 +    /* lower level callback invoked when response is received */
 +    void (*response_cb)(void *ctx, int code, int nsid, u8 *resp_data, size_t resp_data_len);
 +
 +    /* context for response callback */
 +    void *ctx;
 +};
 +
 +/**
 + * struct eap_peer_config - EAP peer configuration/credentials
 + */
 +struct eap_peer_config {
 +      /**
 +       * identity - EAP Identity
 +       *
 +       * This field is used to set the real user identity or NAI (for
 +       * EAP-PSK/PAX/SAKE/GPSK).
 +       */
 +      u8 *identity;
 +
 +      /**
 +       * identity_len - EAP Identity length
 +       */
 +      size_t identity_len;
 +
 +      /**
 +       * anonymous_identity -  Anonymous EAP Identity
 +       *
 +       * This field is used for unencrypted use with EAP types that support
 +       * different tunnelled identity, e.g., EAP-TTLS, in order to reveal the
 +       * real identity (identity field) only to the authentication server.
 +       *
 +       * If not set, the identity field will be used for both unencrypted and
 +       * protected fields.
 +       *
 +       * This field can also be used with EAP-SIM/AKA/AKA' to store the
 +       * pseudonym identity.
 +       */
 +      u8 *anonymous_identity;
 +
 +      /**
 +       * anonymous_identity_len - Length of anonymous_identity
 +       */
 +      size_t anonymous_identity_len;
 +
 +      /**
 +       * password - Password string for EAP
 +       *
 +       * This field can include either the plaintext password (default
 +       * option) or a NtPasswordHash (16-byte MD4 hash of the unicode
 +       * presentation of the password) if flags field has
 +       * EAP_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can
 +       * only be used with authentication mechanism that use this hash as the
 +       * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2,
 +       * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
 +       *
 +       * In addition, this field is used to configure a pre-shared key for
 +       * EAP-PSK/PAX/SAKE/GPSK. The length of the PSK must be 16 for EAP-PSK
 +       * and EAP-PAX and 32 for EAP-SAKE. EAP-GPSK can use a variable length
 +       * PSK.
 +       */
 +      u8 *password;
 +
 +      /**
 +       * password_len - Length of password field
 +       */
 +      size_t password_len;
 +
 +      /**
 +       * ca_cert - File path to CA certificate file (PEM/DER)
 +       *
 +       * This file can have one or more trusted CA certificates. If ca_cert
 +       * and ca_path are not included, server certificate will not be
 +       * verified. This is insecure and a trusted CA certificate should
 +       * always be configured when using EAP-TLS/TTLS/PEAP. Full path to the
 +       * file should be used since working directory may change when
 +       * wpa_supplicant is run in the background.
 +       *
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       *
 +       * Alternatively, this can be used to only perform matching of the
 +       * server certificate (SHA-256 hash of the DER encoded X.509
 +       * certificate). In this case, the possible CA certificates in the
 +       * server certificate chain are ignored and only the server certificate
 +       * is verified. This is configured with the following format:
 +       * hash:://server/sha256/cert_hash_in_hex
 +       * For example: "hash://server/sha256/
 +       * 5a1bc1296205e6fdbe3979728efe3920798885c1c4590b5f90f43222d239ca6a"
 +       *
 +       * On Windows, trusted CA certificates can be loaded from the system
 +       * certificate store by setting this to cert_store://name, e.g.,
 +       * ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT".
 +       * Note that when running wpa_supplicant as an application, the user
 +       * certificate store (My user account) is used, whereas computer store
 +       * (Computer account) is used when running wpasvc as a service.
 +       */
 +      u8 *ca_cert;
 +
 +      /**
 +       * ca_path - Directory path for CA certificate files (PEM)
 +       *
 +       * This path may contain multiple CA certificates in OpenSSL format.
 +       * Common use for this is to point to system trusted CA list which is
 +       * often installed into directory like /etc/ssl/certs. If configured,
 +       * these certificates are added to the list of trusted CAs. ca_cert
 +       * may also be included in that case, but it is not required.
 +       */
 +      u8 *ca_path;
 +
 +      /**
 +       * client_cert - File path to client certificate file (PEM/DER)
 +       *
 +       * This field is used with EAP method that use TLS authentication.
 +       * Usually, this is only configured for EAP-TLS, even though this could
 +       * in theory be used with EAP-TTLS and EAP-PEAP, too. Full path to the
 +       * file should be used since working directory may change when
 +       * wpa_supplicant is run in the background.
 +       *
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       */
 +      u8 *client_cert;
 +
 +      /**
 +       * private_key - File path to client private key file (PEM/DER/PFX)
 +       *
 +       * When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
 +       * commented out. Both the private key and certificate will be read
 +       * from the PKCS#12 file in this case. Full path to the file should be
 +       * used since working directory may change when wpa_supplicant is run
 +       * in the background.
 +       *
 +       * Windows certificate store can be used by leaving client_cert out and
 +       * configuring private_key in one of the following formats:
 +       *
 +       * cert://substring_to_match
 +       *
 +       * hash://certificate_thumbprint_in_hex
 +       *
 +       * For example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
 +       *
 +       * Note that when running wpa_supplicant as an application, the user
 +       * certificate store (My user account) is used, whereas computer store
 +       * (Computer account) is used when running wpasvc as a service.
 +       *
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       */
 +      u8 *private_key;
 +
 +      /**
 +       * private_key_passwd - Password for private key file
 +       *
 +       * If left out, this will be asked through control interface.
 +       */
 +      char *private_key_passwd;
 +
 +      /**
 +       * 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 not use this configuration. However, it is
 +       * possible setup RSA to use ephemeral DH key exchange. In addition,
 +       * ciphers with DSA keys always use ephemeral DH keys. This can be used
 +       * to achieve forward secrecy. If the file is in DSA parameters format,
 +       * it will be automatically converted into DH params. Full path to the
 +       * file should be used since working directory may change when
 +       * wpa_supplicant is run in the background.
 +       *
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       */
 +      u8 *dh_file;
 +
 +      /**
 +       * subject_match - Constraint for server certificate subject
 +       *
 +       * This substring is matched against the subject of the authentication
-        * Note: Since this is a substring match, this cannot be used securily
++       * 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
 +       *
-        * If this string is set, the server sertificate is only accepted if it
++       * 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.
 +       */
 +      u8 *subject_match;
 +
 +      /**
 +       * altsubject_match - Constraint for server certificate alt. subject
 +       *
 +       * Semicolon separated string of entries to be matched against the
 +       * alternative subject name of the authentication server certificate.
-      * If non-null, specifies a callback method that can be used to
-      * override the validity of a peer certificate.
++       * 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
 +       */
 +      u8 *altsubject_match;
 +
 +      /**
 +       * domain_suffix_match - Constraint for server domain name
 +       *
 +       * If set, this FQDN is used as a suffix match requirement for the
 +       * 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. Suffix match here means that the
 +       * host/domain name is compared one label at a time starting from the
 +       * top-level domain and all the labels in domain_suffix_match shall be
 +       * included in the certificate. The certificate may include additional
 +       * sub-level labels in addition to the required labels.
 +       *
 +       * For example, domain_suffix_match=example.com would match
 +       * test.example.com but would not match test-example.com.
 +       */
 +      char *domain_suffix_match;
 +
 +      /**
 +       * domain_match - Constraint for server domain name
 +       *
 +       * If set, this FQDN is used as a full match requirement for the
 +       * 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 full match comparison. This behavior is similar to
 +       * domain_suffix_match, but has the requirement of a full match, i.e.,
 +       * no subdomains or wildcard matches are allowed. Case-insensitive
 +       * comparison is used, so "Example.com" matches "example.com", but would
 +       * not match "test.Example.com".
 +       */
 +      char *domain_match;
 +
 +      /**
 +       * ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2)
 +       *
 +       * This file can have one or more trusted CA certificates. If ca_cert2
 +       * and ca_path2 are not included, server certificate will not be
 +       * verified. This is insecure and a trusted CA certificate should
 +       * always be configured. Full path to the file should be used since
 +       * working directory may change when wpa_supplicant is run in the
 +       * background.
 +       *
 +       * This field is like ca_cert, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       *
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       */
 +      u8 *ca_cert2;
 +
 +      /**
 +       * ca_path2 - Directory path for CA certificate files (PEM) (Phase 2)
 +       *
 +       * This path may contain multiple CA certificates in OpenSSL format.
 +       * Common use for this is to point to system trusted CA list which is
 +       * often installed into directory like /etc/ssl/certs. If configured,
 +       * these certificates are added to the list of trusted CAs. ca_cert
 +       * may also be included in that case, but it is not required.
 +       *
 +       * This field is like ca_path, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       */
 +      u8 *ca_path2;
 +
 +      /**
 +       * client_cert2 - File path to client certificate file
 +       *
 +       * This field is like client_cert, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
 +       * file should be used since working directory may change when
 +       * wpa_supplicant is run in the background.
 +       *
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       */
 +      u8 *client_cert2;
 +
 +      /**
 +       * private_key2 - File path to client private key file
 +       *
 +       * This field is like private_key, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
 +       * file should be used since working directory may change when
 +       * wpa_supplicant is run in the background.
 +       *
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       */
 +      u8 *private_key2;
 +
 +      /**
 +       * private_key2_passwd -  Password for private key file
 +       *
 +       * This field is like private_key_passwd, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       */
 +      char *private_key2_passwd;
 +
 +      /**
 +       * dh_file2 - File path to DH/DSA parameters file (in PEM format)
 +       *
 +       * This field is like dh_file, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
 +       * file should be used since working directory may change when
 +       * wpa_supplicant is run in the background.
 +       *
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       */
 +      u8 *dh_file2;
 +
 +      /**
 +       * subject_match2 - Constraint for server certificate subject
 +       *
 +       * This field is like subject_match, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       */
 +      u8 *subject_match2;
 +
 +      /**
 +       * altsubject_match2 - Constraint for server certificate alt. subject
 +       *
 +       * This field is like altsubject_match, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       */
 +      u8 *altsubject_match2;
 +
 +      /**
 +       * domain_suffix_match2 - Constraint for server domain name
 +       *
 +       * This field is like domain_suffix_match, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       */
 +      char *domain_suffix_match2;
 +
 +      /**
 +       * domain_match2 - Constraint for server domain name
 +       *
 +       * This field is like domain_match, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       */
 +      char *domain_match2;
 +
 +      /**
 +       * eap_methods - Allowed EAP methods
 +       *
 +       * (vendor=EAP_VENDOR_IETF,method=EAP_TYPE_NONE) terminated list of
 +       * allowed EAP methods or %NULL if all methods are accepted.
 +       */
 +      struct eap_method_type *eap_methods;
 +
 +      /**
 +       * phase1 - Phase 1 (outer authentication) parameters
 +       *
 +       * String with field-value pairs, e.g., "peapver=0" or
 +       * "peapver=1 peaplabel=1".
 +       *
 +       * 'peapver' can be used to force which PEAP version (0 or 1) is used.
 +       *
 +       * 'peaplabel=1' can be used to force new label, "client PEAP
 +       * encryption", to be used during key derivation when PEAPv1 or newer.
 +       *
 +       * Most existing PEAPv1 implementation seem to be using the old label,
 +       * "client EAP encryption", and wpa_supplicant is now using that as the
 +       * default value.
 +       *
 +       * Some servers, e.g., Radiator, may require peaplabel=1 configuration
 +       * to interoperate with PEAPv1; see eap_testing.txt for more details.
 +       *
 +       * 'peap_outer_success=0' can be used to terminate PEAP authentication
 +       * on tunneled EAP-Success. This is required with some RADIUS servers
 +       * that implement draft-josefsson-pppext-eap-tls-eap-05.txt (e.g.,
 +       * Lucent NavisRadius v4.4.0 with PEAP in "IETF Draft 5" mode).
 +       *
 +       * include_tls_length=1 can be used to force wpa_supplicant to include
 +       * TLS Message Length field in all TLS messages even if they are not
 +       * fragmented.
 +       *
 +       * sim_min_num_chal=3 can be used to configure EAP-SIM to require three
 +       * challenges (by default, it accepts 2 or 3).
 +       *
 +       * result_ind=1 can be used to enable EAP-SIM and EAP-AKA to use
 +       * protected result indication.
 +       *
 +       * fast_provisioning option can be used to enable in-line provisioning
 +       * of EAP-FAST credentials (PAC):
 +       * 0 = disabled,
 +       * 1 = allow unauthenticated provisioning,
 +       * 2 = allow authenticated provisioning,
 +       * 3 = allow both unauthenticated and authenticated provisioning
 +       *
 +       * fast_max_pac_list_len=num option can be used to set the maximum
 +       * number of PAC entries to store in a PAC list (default: 10).
 +       *
 +       * fast_pac_format=binary option can be used to select binary format
 +       * for storing PAC entries in order to save some space (the default
 +       * text format uses about 2.5 times the size of minimal binary format).
 +       *
 +       * crypto_binding option can be used to control PEAPv0 cryptobinding
 +       * behavior:
 +       * 0 = do not use cryptobinding (default)
 +       * 1 = use cryptobinding if server supports it
 +       * 2 = require cryptobinding
 +       *
 +       * EAP-WSC (WPS) uses following options: pin=Device_Password and
 +       * uuid=Device_UUID
 +       *
 +       * For wired IEEE 802.1X authentication, "allow_canned_success=1" can be
 +       * used to configure a mode that allows EAP-Success (and EAP-Failure)
 +       * without going through authentication step. Some switches use such
 +       * sequence when forcing the port to be authorized/unauthorized or as a
 +       * fallback option if the authentication server is unreachable. By
 +       * default, wpa_supplicant discards such frames to protect against
 +       * potential attacks by rogue devices, but this option can be used to
 +       * disable that protection for cases where the server/authenticator does
 +       * not need to be authenticated.
 +       */
 +      char *phase1;
 +
 +      /**
 +       * phase2 - Phase2 (inner authentication with TLS tunnel) parameters
 +       *
 +       * String with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
 +       * "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS. "mschapv2_retry=0" can
 +       * be used to disable MSCHAPv2 password retry in authentication failure
 +       * cases.
 +       */
 +      char *phase2;
 +
 +      /**
 +       * pcsc - Parameters for PC/SC smartcard interface for USIM and GSM SIM
 +       *
 +       * This field is used to configure PC/SC smartcard interface.
 +       * Currently, the only configuration is whether this field is %NULL (do
 +       * not use PC/SC) or non-NULL (e.g., "") to enable PC/SC.
 +       *
 +       * This field is used for EAP-SIM and EAP-AKA.
 +       */
 +      char *pcsc;
 +
 +      /**
 +       * pin - PIN for USIM, GSM SIM, and smartcards
 +       *
 +       * This field is used to configure PIN for SIM and smartcards for
 +       * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
 +       * smartcard is used for private key operations.
 +       *
 +       * If left out, this will be asked through control interface.
 +       */
 +      char *pin;
 +
 +      /**
 +       * engine - Enable OpenSSL engine (e.g., for smartcard access)
 +       *
 +       * This is used if private key operations for EAP-TLS are performed
 +       * using a smartcard.
 +       */
 +      int engine;
 +
 +      /**
 +       * engine_id - Engine ID for OpenSSL engine
 +       *
 +       * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
 +       * engine.
 +       *
 +       * This is used if private key operations for EAP-TLS are performed
 +       * using a smartcard.
 +       */
 +      char *engine_id;
 +
 +      /**
 +       * engine2 - Enable OpenSSL engine (e.g., for smartcard) (Phase 2)
 +       *
 +       * This is used if private key operations for EAP-TLS are performed
 +       * using a smartcard.
 +       *
 +       * This field is like engine, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       */
 +      int engine2;
 +
 +
 +      /**
 +       * pin2 - PIN for USIM, GSM SIM, and smartcards (Phase 2)
 +       *
 +       * This field is used to configure PIN for SIM and smartcards for
 +       * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
 +       * smartcard is used for private key operations.
 +       *
 +       * This field is like pin2, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       *
 +       * If left out, this will be asked through control interface.
 +       */
 +      char *pin2;
 +
 +      /**
 +       * engine2_id - Engine ID for OpenSSL engine (Phase 2)
 +       *
 +       * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
 +       * engine.
 +       *
 +       * This is used if private key operations for EAP-TLS are performed
 +       * using a smartcard.
 +       *
 +       * This field is like engine_id, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       */
 +      char *engine2_id;
 +
 +
 +      /**
 +       * key_id - Key ID for OpenSSL engine
 +       *
 +       * This is used if private key operations for EAP-TLS are performed
 +       * using a smartcard.
 +       */
 +      char *key_id;
 +
 +      /**
 +       * cert_id - Cert ID for OpenSSL engine
 +       *
 +       * This is used if the certificate operations for EAP-TLS are performed
 +       * using a smartcard.
 +       */
 +      char *cert_id;
 +
 +      /**
 +       * ca_cert_id - CA Cert ID for OpenSSL engine
 +       *
 +       * This is used if the CA certificate for EAP-TLS is on a smartcard.
 +       */
 +      char *ca_cert_id;
 +
 +      /**
 +       * key2_id - Key ID for OpenSSL engine (phase2)
 +       *
 +       * This is used if private key operations for EAP-TLS are performed
 +       * using a smartcard.
 +       */
 +      char *key2_id;
 +
 +      /**
 +       * cert2_id - Cert ID for OpenSSL engine (phase2)
 +       *
 +       * This is used if the certificate operations for EAP-TLS are performed
 +       * using a smartcard.
 +       */
 +      char *cert2_id;
 +
 +      /**
 +       * ca_cert2_id - CA Cert ID for OpenSSL engine (phase2)
 +       *
 +       * This is used if the CA certificate for EAP-TLS is on a smartcard.
 +       */
 +      char *ca_cert2_id;
 +
 +      /**
 +       * otp - One-time-password
 +       *
 +       * This field should not be set in configuration step. It is only used
 +       * internally when OTP is entered through the control interface.
 +       */
 +      u8 *otp;
 +
 +      /**
 +       * otp_len - Length of the otp field
 +       */
 +      size_t otp_len;
 +
 +      /**
 +       * pending_req_identity - Whether there is a pending identity request
 +       *
 +       * This field should not be set in configuration step. It is only used
 +       * internally when control interface is used to request needed
 +       * information.
 +       */
 +      int pending_req_identity;
 +
 +      /**
 +       * pending_req_password - Whether there is a pending password request
 +       *
 +       * This field should not be set in configuration step. It is only used
 +       * internally when control interface is used to request needed
 +       * information.
 +       */
 +      int pending_req_password;
 +
 +      /**
 +       * pending_req_pin - Whether there is a pending PIN request
 +       *
 +       * This field should not be set in configuration step. It is only used
 +       * internally when control interface is used to request needed
 +       * information.
 +       */
 +      int pending_req_pin;
 +
 +      /**
 +       * pending_req_new_password - Pending password update request
 +       *
 +       * This field should not be set in configuration step. It is only used
 +       * internally when control interface is used to request needed
 +       * information.
 +       */
 +      int pending_req_new_password;
 +
 +      /**
 +       * pending_req_passphrase - Pending passphrase request
 +       *
 +       * This field should not be set in configuration step. It is only used
 +       * internally when control interface is used to request needed
 +       * information.
 +       */
 +      int pending_req_passphrase;
 +
 +      /**
 +       * pending_req_otp - Whether there is a pending OTP request
 +       *
 +       * This field should not be set in configuration step. It is only used
 +       * internally when control interface is used to request needed
 +       * information.
 +       */
 +      char *pending_req_otp;
 +
 +      /**
 +       * pending_req_otp_len - Length of the pending OTP request
 +       */
 +      size_t pending_req_otp_len;
 +
 +      /**
 +       * pac_file - File path or blob name for the PAC entries (EAP-FAST)
 +       *
 +       * wpa_supplicant will need to be able to create this file and write
 +       * updates to it when PAC is being provisioned or refreshed. Full path
 +       * to the file should be used since working directory may change when
 +       * wpa_supplicant is run in the background.
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       */
 +      char *pac_file;
 +
 +      /**
 +       * mschapv2_retry - MSCHAPv2 retry in progress
 +       *
 +       * This field is used internally by EAP-MSCHAPv2 and should not be set
 +       * as part of configuration.
 +       */
 +      int mschapv2_retry;
 +
 +      /**
 +       * new_password - New password for password update
 +       *
 +       * This field is used during MSCHAPv2 password update. This is normally
 +       * requested from the user through the control interface and not set
 +       * from configuration.
 +       */
 +      u8 *new_password;
 +
 +      /**
 +       * new_password_len - Length of new_password field
 +       */
 +      size_t new_password_len;
 +
 +      /**
 +       * fragment_size - Maximum EAP fragment size in bytes (default 1398)
 +       *
 +       * This value limits the fragment size for EAP methods that support
 +       * fragmentation (e.g., EAP-TLS and EAP-PEAP). This value should be set
 +       * small enough to make the EAP messages fit in MTU of the network
 +       * interface used for EAPOL. The default value is suitable for most
 +       * cases.
 +       */
 +      int fragment_size;
 +
 +    /**
 +     * chbind_config - eap channel binding config data
 +     */
 +    struct eap_peer_chbind_config *chbind_config;
 +
 +    /**
 +     * chbind_config_len - channel binding config data count
 +     */
 +    size_t chbind_config_len;
 +
 +#define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0)
 +#define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1)
 +      /**
 +       * flags - Network configuration flags (bitfield)
 +       *
 +       * This variable is used for internal flags to describe further details
 +       * for the network parameters.
 +       * bit 0 = password is represented as a 16-byte NtPasswordHash value
 +       *         instead of plaintext password
 +       * bit 1 = password is stored in external storage; the value in the
 +       *         password field is the name of that external entry
 +       */
 +      u32 flags;
 +
 +      /**
 +       * ocsp - Whether to use/require OCSP to check server certificate
 +       *
 +       * 0 = do not use OCSP stapling (TLS certificate status extension)
 +       * 1 = try to use OCSP stapling, but not require response
 +       * 2 = require valid OCSP stapling response
 +       */
 +      int ocsp;
 +
 +      /**
 +       * external_sim_resp - Response from external SIM processing
 +       *
 +       * This field should not be set in configuration step. It is only used
 +       * internally when control interface is used to request external
 +       * SIM/USIM processing.
 +       */
 +      char *external_sim_resp;
 +
 +      /**
 +       * sim_num - User selected SIM identifier
 +       *
 +       * This variable is used for identifying which SIM is used if the system
 +       * has more than one.
 +       */
 +      int sim_num;
 +
 +      /**
 +       * openssl_ciphers - OpenSSL cipher string
 +       *
 +       * This is an OpenSSL specific configuration option for configuring the
 +       * ciphers for this connection. If not set, the default cipher suite
 +       * list is used.
 +       */
 +      char *openssl_ciphers;
 +
 +      /**
 +       * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
 +       */
 +      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;
++
 +    /**
++     * 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;
 +};
 +
 +
 +/**
 + * struct wpa_config_blob - Named configuration blob
 + *
 + * This data structure is used to provide storage for binary objects to store
 + * abstract information like certificates and private keys inlined with the
 + * configuration data.
 + */
 +struct wpa_config_blob {
 +      /**
 +       * name - Blob name
 +       */
 +      char *name;
 +
 +      /**
 +       * data - Pointer to binary data
 +       */
 +      u8 *data;
 +
 +      /**
 +       * len - Length of binary data
 +       */
 +      size_t len;
 +
 +      /**
 +       * next - Pointer to next blob in the configuration
 +       */
 +      struct wpa_config_blob *next;
 +};
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_CONFIG_H */
@@@ -452,6 -452,7 +452,7 @@@ static struct wpabuf * eap_eke_process_
        /* 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 +771,6 @@@ static u8 * eap_eke_get_session_id(stru
  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");
        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);
  }
@@@ -1,6 -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 +67,7 @@@ struct eap_fast_data 
        int simck_idx;
  
        struct wpabuf *pending_phase2_req;
+       struct wpabuf *pending_resp;
  };
  
  
@@@ -112,8 -113,8 +113,8 @@@ static int eap_fast_session_ticket_cb(v
  }
  
  
- 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;
  
                wpa_printf(MSG_DEBUG, "EAP-FAST: Using binary format for PAC "
                           "list");
        }
-       return 0;
  }
  
  
@@@ -158,10 -157,8 +157,8 @@@ static void * eap_fast_init(struct eap_
        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 +251,16 @@@ static void eap_fast_deinit(struct eap_
        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 +275,7 @@@ static int eap_fast_derive_key_auth(str
         * 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 +303,6 @@@ static int eap_fast_derive_key_provisio
        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 +709,10 @@@ static int eap_fast_get_cmk(struct eap_
        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 +1095,7 @@@ static int eap_fast_parse_decrypted(str
        /* 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 +1442,7 @@@ static int eap_fast_clear_pac_opaque_ex
  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) {
        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 +1568,34 @@@ static struct wpabuf * eap_fast_process
                        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,
                        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 +1681,8 @@@ static void eap_fast_deinit_for_reauth(
        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 +1760,7 @@@ static u8 * eap_fast_get_session_id(str
        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 +1796,6 @@@ static u8 * eap_fast_get_emsk(struct ea
  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");
  #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);
  }
@@@ -455,7 -455,8 +455,8 @@@ int eap_fast_load_pac(struct eap_sm *sm
        }
  
        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 +710,7 @@@ static void eap_fast_pac_get_a_id(struc
        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 +802,10 @@@ int eap_fast_load_pac_bin(struct eap_s
        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)
@@@ -771,7 -771,6 +771,6 @@@ static u8 * eap_gpsk_get_session_id(str
  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");
        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);
  }
@@@ -127,7 -127,6 +127,6 @@@ static struct wpabuf * eap_gtc_process(
  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");
        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,0000000..f1f5d55
mode 100644,000000..100644
--- /dev/null
@@@ -1,397 -1,0 +1,399 @@@
 +/*
 + * EAP peer state machines internal structures (RFC 4137)
 + * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
 + *
 + * This software may be distributed under the terms of the BSD license.
 + * See README for more details.
 + */
 +
 +#ifndef EAP_I_H
 +#define EAP_I_H
 +
 +#include "wpabuf.h"
 +#include "utils/list.h"
 +#include "eap_peer/eap.h"
 +#include "eap_common/eap_common.h"
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +/* RFC 4137 - EAP Peer state machine */
 +
 +typedef enum {
 +      DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC
 +} EapDecision;
 +
 +typedef enum {
 +      METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE
 +} EapMethodState;
 +
 +/**
 + * struct eap_method_ret - EAP return values from struct eap_method::process()
 + *
 + * These structure contains OUT variables for the interface between peer state
 + * machine and methods (RFC 4137, Sect. 4.2). eapRespData will be returned as
 + * the return value of struct eap_method::process() so it is not included in
 + * this structure.
 + */
 +struct eap_method_ret {
 +      /**
 +       * ignore - Whether method decided to drop the current packed (OUT)
 +       */
 +      Boolean ignore;
 +
 +      /**
 +       * methodState - Method-specific state (IN/OUT)
 +       */
 +      EapMethodState methodState;
 +
 +      /**
 +       * decision - Authentication decision (OUT)
 +       */
 +      EapDecision decision;
 +
 +      /**
 +       * allowNotifications - Whether method allows notifications (OUT)
 +       */
 +      Boolean allowNotifications;
 +};
 +
 +
 +/**
 + * struct eap_method - EAP method interface
 + * This structure defines the EAP method interface. Each method will need to
 + * register its own EAP type, EAP name, and set of function pointers for method
 + * specific operations. This interface is based on section 4.4 of RFC 4137.
 + */
 +struct eap_method {
 +      /**
 +       * vendor - EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)
 +       */
 +      int vendor;
 +
 +      /**
 +       * method - EAP type number (EAP_TYPE_*)
 +       */
 +      EapType method;
 +
 +      /**
 +       * name - Name of the method (e.g., "TLS")
 +       */
 +      const char *name;
 +
 +      /**
 +       * init - Initialize an EAP method
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * Returns: Pointer to allocated private data, or %NULL on failure
 +       *
 +       * This function is used to initialize the EAP method explicitly
 +       * instead of using METHOD_INIT state as specific in RFC 4137. The
 +       * method is expected to initialize it method-specific state and return
 +       * a pointer that will be used as the priv argument to other calls.
 +       */
 +      void * (*init)(struct eap_sm *sm);
 +
 +      /**
 +       * deinit - Deinitialize an EAP method
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       *
 +       * Deinitialize the EAP method and free any allocated private data.
 +       */
 +      void (*deinit)(struct eap_sm *sm, void *priv);
 +
 +      /**
 +       * process - Process an EAP request
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       * @ret: Return values from EAP request validation and processing
 +       * @reqData: EAP request to be processed (eapReqData)
 +       * Returns: Pointer to allocated EAP response packet (eapRespData)
 +       *
 +       * This function is a combination of m.check(), m.process(), and
 +       * m.buildResp() procedures defined in section 4.4 of RFC 4137 In other
 +       * words, this function validates the incoming request, processes it,
 +       * and build a response packet. m.check() and m.process() return values
 +       * are returned through struct eap_method_ret *ret variable. Caller is
 +       * responsible for freeing the returned EAP response packet.
 +       */
 +      struct wpabuf * (*process)(struct eap_sm *sm, void *priv,
 +                                 struct eap_method_ret *ret,
 +                                 const struct wpabuf *reqData);
 +
 +      /**
 +       * isKeyAvailable - Find out whether EAP method has keying material
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       * Returns: %TRUE if key material (eapKeyData) is available
 +       */
 +      Boolean (*isKeyAvailable)(struct eap_sm *sm, void *priv);
 +
 +      /**
 +       * getKey - Get EAP method specific keying material (eapKeyData)
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       * @len: Pointer to variable to store key length (eapKeyDataLen)
 +       * Returns: Keying material (eapKeyData) or %NULL if not available
 +       *
 +       * This function can be used to get the keying material from the EAP
 +       * method. The key may already be stored in the method-specific private
 +       * data or this function may derive the key.
 +       */
 +      u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len);
 +
 +      /**
 +       * get_status - Get EAP method status
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       * @buf: Buffer for status information
 +       * @buflen: Maximum buffer length
 +       * @verbose: Whether to include verbose status information
 +       * Returns: Number of bytes written to buf
 +       *
 +       * Query EAP method for status information. This function fills in a
 +       * text area with current status information from the EAP method. If
 +       * the buffer (buf) is not large enough, status information will be
 +       * truncated to fit the buffer.
 +       */
 +      int (*get_status)(struct eap_sm *sm, void *priv, char *buf,
 +                        size_t buflen, int verbose);
 +
 +      /**
 +       * has_reauth_data - Whether method is ready for fast reauthentication
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       * Returns: %TRUE or %FALSE based on whether fast reauthentication is
 +       * possible
 +       *
 +       * This function is an optional handler that only EAP methods
 +       * supporting fast re-authentication need to implement.
 +       */
 +      Boolean (*has_reauth_data)(struct eap_sm *sm, void *priv);
 +
 +      /**
 +       * deinit_for_reauth - Release data that is not needed for fast re-auth
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       *
 +       * This function is an optional handler that only EAP methods
 +       * supporting fast re-authentication need to implement. This is called
 +       * when authentication has been completed and EAP state machine is
 +       * requesting that enough state information is maintained for fast
 +       * re-authentication
 +       */
 +      void (*deinit_for_reauth)(struct eap_sm *sm, void *priv);
 +
 +      /**
 +       * init_for_reauth - Prepare for start of fast re-authentication
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       *
 +       * This function is an optional handler that only EAP methods
 +       * supporting fast re-authentication need to implement. This is called
 +       * when EAP authentication is started and EAP state machine is
 +       * requesting fast re-authentication to be used.
 +       */
 +      void * (*init_for_reauth)(struct eap_sm *sm, void *priv);
 +
 +      /**
 +       * get_identity - Get method specific identity for re-authentication
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       * @len: Length of the returned identity
 +       * Returns: Pointer to the method specific identity or %NULL if default
 +       * identity is to be used
 +       *
 +       * This function is an optional handler that only EAP methods
 +       * that use method specific identity need to implement.
 +       */
 +      const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len);
 +
 +      /**
 +       * free - Free EAP method data
 +       * @method: Pointer to the method data registered with
 +       * eap_peer_method_register().
 +       *
 +       * This function will be called when the EAP method is being
 +       * unregistered. If the EAP method allocated resources during
 +       * registration (e.g., allocated struct eap_method), they should be
 +       * freed in this function. No other method functions will be called
 +       * after this call. If this function is not defined (i.e., function
 +       * pointer is %NULL), a default handler is used to release the method
 +       * data with free(method). This is suitable for most cases.
 +       */
 +      void (*free)(struct eap_method *method);
 +
 +#define EAP_PEER_METHOD_INTERFACE_VERSION 1
 +      /**
 +       * version - Version of the EAP peer method interface
 +       *
 +       * The EAP peer method implementation should set this variable to
 +       * EAP_PEER_METHOD_INTERFACE_VERSION. This is used to verify that the
 +       * EAP method is using supported API version when using dynamically
 +       * loadable EAP methods.
 +       */
 +      int version;
 +
 +      /**
 +       * next - Pointer to the next EAP method
 +       *
 +       * This variable is used internally in the EAP method registration code
 +       * to create a linked list of registered EAP methods.
 +       */
 +      struct eap_method *next;
 +
 +#ifdef CONFIG_DYNAMIC_EAP_METHODS
 +      /**
 +       * dl_handle - Handle for the dynamic library
 +       *
 +       * This variable is used internally in the EAP method registration code
 +       * to store a handle for the dynamic library. If the method is linked
 +       * in statically, this is %NULL.
 +       */
 +      void *dl_handle;
 +#endif /* CONFIG_DYNAMIC_EAP_METHODS */
 +
 +      /**
 +       * get_emsk - Get EAP method specific keying extended material (EMSK)
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       * @len: Pointer to a variable to store EMSK length
 +       * Returns: EMSK or %NULL if not available
 +       *
 +       * This function can be used to get the extended keying material from
 +       * the EAP method. The key may already be stored in the method-specific
 +       * private data or this function may derive the key.
 +       */
 +      u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len);
 +
 +      /**
 +       * getSessionId - Get EAP method specific Session-Id
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       * @len: Pointer to a variable to store Session-Id length
 +       * Returns: Session-Id or %NULL if not available
 +       *
 +       * This function can be used to get the Session-Id from the EAP method.
 +       * The Session-Id may already be stored in the method-specific private
 +       * data or this function may derive the Session-Id.
 +       */
 +      u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len);
 +};
 +
 +
 +struct eap_erp_key {
 +      struct dl_list list;
 +      size_t rRK_len;
 +      size_t rIK_len;
 +      u8 rRK[ERP_MAX_KEY_LEN];
 +      u8 rIK[ERP_MAX_KEY_LEN];
 +      u32 next_seq;
 +      char keyname_nai[];
 +};
 +
 +/**
 + * struct eap_sm - EAP state machine data
 + */
 +struct eap_sm {
 +      enum {
 +              EAP_INITIALIZE, EAP_DISABLED, EAP_IDLE, EAP_RECEIVED,
 +              EAP_GET_METHOD, EAP_METHOD, EAP_SEND_RESPONSE, EAP_DISCARD,
 +              EAP_IDENTITY, EAP_NOTIFICATION, EAP_RETRANSMIT, EAP_SUCCESS,
 +              EAP_FAILURE
 +      } EAP_state;
 +      /* Long-term local variables */
 +      EapType selectedMethod;
 +      EapMethodState methodState;
 +      int lastId;
 +      struct wpabuf *lastRespData;
 +      EapDecision decision;
 +      /* Short-term local variables */
 +      Boolean rxReq;
 +      Boolean rxSuccess;
 +      Boolean rxFailure;
 +      int reqId;
 +      EapType reqMethod;
 +      int reqVendor;
 +      u32 reqVendorMethod;
 +      Boolean ignore;
 +      /* Constants */
 +      int ClientTimeout;
 +
 +      /* Miscellaneous variables */
 +      Boolean allowNotifications; /* peer state machine <-> methods */
 +      struct wpabuf *eapRespData; /* peer to lower layer */
 +      Boolean eapKeyAvailable; /* peer to lower layer */
 +      u8 *eapKeyData; /* peer to lower layer */
 +      size_t eapKeyDataLen; /* peer to lower layer */
 +      u8 *eapSessionId; /* peer to lower layer */
 +      size_t eapSessionIdLen; /* peer to lower layer */
 +      const struct eap_method *m; /* selected EAP method */
 +      /* not defined in RFC 4137 */
 +      Boolean changed;
 +      void *eapol_ctx;
 +      const struct eapol_callbacks *eapol_cb;
 +      void *eap_method_priv;
 +      int init_phase2;
 +      int fast_reauth;
 +      Boolean reauthInit; /* send EAP-Identity/Re-auth */
 +      u32 erp_seq;
 +
 +      Boolean rxResp /* LEAP only */;
 +      Boolean leap_done;
 +      Boolean peap_done;
 +      u8 req_sha1[20]; /* SHA1() of the current EAP packet */
 +      u8 last_sha1[20]; /* SHA1() of the previously received EAP packet; used
 +                         * in duplicate request detection. */
 +
 +      void *msg_ctx;
 +      void *scard_ctx;
 +      void *ssl_ctx;
 +      void *ssl_ctx2;
 +
 +      unsigned int workaround;
 +
 +      /* Optional challenges generated in Phase 1 (EAP-FAST) */
 +      u8 *peer_challenge, *auth_challenge;
 +
 +      int num_rounds;
 +      int force_disabled;
 +
 +      struct wps_context *wps;
 +
 +      int prev_failure;
 +      struct eap_peer_config *last_config;
 +
 +      struct ext_password_data *ext_pw;
 +      struct wpabuf *ext_pw_buf;
 +
 +      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 */
 +};
 +
 +const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
 +const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len);
 +const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash);
 +const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len);
 +const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len);
 +void eap_clear_config_otp(struct eap_sm *sm);
 +const char * eap_get_config_phase1(struct eap_sm *sm);
 +const char * eap_get_config_phase2(struct eap_sm *sm);
 +int eap_get_config_fragment_size(struct eap_sm *sm);
 +struct eap_peer_config * eap_get_config(struct eap_sm *sm);
 +void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob);
 +const struct wpa_config_blob *
 +eap_get_config_blob(struct eap_sm *sm, const char *name);
 +void eap_notify_pending(struct eap_sm *sm);
 +int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_I_H */
@@@ -513,7 -513,6 +513,6 @@@ static u8 * eap_ikev2_get_session_id(st
  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,
        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);
  }
@@@ -393,7 -393,6 +393,6 @@@ static u8 * eap_leap_getKey(struct eap_
  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");
        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);
  }
@@@ -102,7 -102,6 +102,6 @@@ static struct wpabuf * eap_md5_process(
  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");
        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);
  }
@@@ -18,6 -18,8 +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 +297,7 @@@ struct eap_method * eap_peer_method_all
   * 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);
  }
  
  /**
   * 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,0000000..ee4a1f5
mode 100644,000000..100644
--- /dev/null
@@@ -1,119 -1,0 +1,118 @@@
- void eap_peer_method_free(struct eap_method *method);
 +/*
 + * EAP peer: Method registration
 + * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
 + *
 + * This software may be distributed under the terms of the BSD license.
 + * See README for more details.
 + */
 +
 +#ifndef EAP_METHODS_H
 +#define EAP_METHODS_H
 +
 +#include "eap_common/eap_defs.h"
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method);
 +const struct eap_method * eap_peer_get_methods(size_t *count);
 +
 +struct eap_method * eap_peer_method_alloc(int version, int vendor,
 +                                        EapType method, const char *name);
 +int eap_peer_method_register(struct eap_method *method);
 +
 +
 +#ifdef IEEE8021X_EAPOL
 +
 +EapType eap_peer_get_type(const char *name, int *vendor);
 +const char * eap_get_name(int vendor, EapType type);
 +size_t eap_get_names(char *buf, size_t buflen);
 +char ** eap_get_names_as_string_array(size_t *num);
 +void eap_peer_unregister_methods(void);
 +
 +#else /* IEEE8021X_EAPOL */
 +
 +static inline EapType eap_peer_get_type(const char *name, int *vendor)
 +{
 +      *vendor = EAP_VENDOR_IETF;
 +      return EAP_TYPE_NONE;
 +}
 +
 +static inline const char * eap_get_name(int vendor, EapType type)
 +{
 +      return NULL;
 +}
 +
 +static inline size_t eap_get_names(char *buf, size_t buflen)
 +{
 +      return 0;
 +}
 +
 +static inline int eap_peer_register_methods(void)
 +{
 +      return 0;
 +}
 +
 +static inline void eap_peer_unregister_methods(void)
 +{
 +}
 +
 +static inline char ** eap_get_names_as_string_array(size_t *num)
 +{
 +      return NULL;
 +}
 +
 +#endif /* IEEE8021X_EAPOL */
 +
 +
 +#ifdef CONFIG_DYNAMIC_EAP_METHODS
 +
 +int eap_peer_method_load(const char *so);
 +int eap_peer_method_unload(struct eap_method *method);
 +
 +#else /* CONFIG_DYNAMIC_EAP_METHODS */
 +
 +static inline int eap_peer_method_load(const char *so UNUSED)
 +{
 +      return 0;
 +}
 +
 +static inline int eap_peer_method_unload(struct eap_method *method UNUSED)
 +{
 +      return 0;
 +}
 +
 +#endif /* CONFIG_DYNAMIC_EAP_METHODS */
 +
 +/* EAP peer method registration calls for statically linked in methods */
 +int eap_peer_md5_register(void);
 +int eap_peer_tls_register(void);
 +int eap_peer_unauth_tls_register(void);
 +int eap_peer_wfa_unauth_tls_register(void);
 +int eap_peer_mschapv2_register(void);
 +int eap_peer_peap_register(void);
 +int eap_peer_ttls_register(void);
 +int eap_peer_gtc_register(void);
 +int eap_peer_otp_register(void);
 +int eap_peer_sim_register(void);
 +int eap_peer_leap_register(void);
 +int eap_peer_psk_register(void);
 +int eap_peer_aka_register(void);
 +int eap_peer_aka_prime_register(void);
 +int eap_peer_fast_register(void);
 +int eap_peer_pax_register(void);
 +int eap_peer_sake_register(void);
 +int eap_peer_gpsk_register(void);
 +int eap_peer_wsc_register(void);
 +int eap_peer_ikev2_register(void);
 +int eap_peer_vendor_test_register(void);
 +int eap_peer_tnc_register(void);
 +int eap_peer_pwd_register(void);
 +int eap_peer_eke_register(void);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_METHODS_H */
@@@ -880,7 -880,6 +880,6 @@@ static u8 * eap_mschapv2_getKey(struct 
  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,
        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);
  }
@@@ -83,7 -83,6 +83,6 @@@ static struct wpabuf * eap_otp_process(
  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 +93,5 @@@
        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);
  }
@@@ -276,9 -276,16 +276,16 @@@ static struct wpabuf * eap_pax_process_
        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");
        /* 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 +482,13 @@@ static u8 * eap_pax_getKey(struct eap_s
                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 +507,13 @@@ static u8 * eap_pax_get_emsk(struct eap
                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 +542,6 @@@ static u8 * eap_pax_get_session_id(stru
  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");
        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);
  }
@@@ -1,6 -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 +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 +70,8 @@@
  };
  
  
- 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;
  
                wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
        }
  #endif /* EAP_TNC */
-       return 0;
  }
  
  
@@@ -144,11 -143,8 +143,8 @@@ static void * eap_peap_init(struct eap_
        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 +187,7 @@@ static void eap_peap_deinit(struct eap_
        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 +253,7 @@@ static int eap_peap_derive_cmk(struct e
  {
        u8 *tk;
        u8 isk[32], imck[60];
+       int resumed;
  
        /*
         * Tunnel key (TK) is the first 60 octets of the key generated by
                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 +339,8 @@@ static int eap_tlv_add_cryptobinding(st
                    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 +651,7 @@@ static int eap_peap_phase2_request(stru
                                        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 +1010,34 @@@ static struct wpabuf * eap_peap_process
            !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,
                        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 +1165,8 @@@ static void eap_peap_deinit_for_reauth(
        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 +1281,6 @@@ static u8 * eap_peap_get_session_id(str
  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");
        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);
  }
@@@ -480,7 -480,6 +480,6 @@@ static u8 * eap_psk_get_emsk(struct eap
  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");
        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);
  }
@@@ -418,7 -418,6 +418,6 @@@ eap_pwd_perform_commit_exchange(struct 
                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 +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 +774,8 @@@ eap_pwd_perform_confirm_exchange(struc
        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 +904,7 @@@ eap_pwd_process(struct eap_sm *sm, voi
        /*
         * 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 "
                        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));
         * 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 +1054,6 @@@ static u8 * eap_pwd_get_emsk(struct eap
  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");
        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);
  }
@@@ -309,11 -309,20 +309,20 @@@ static struct wpabuf * eap_sake_process
                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 +503,6 @@@ static u8 * eap_sake_get_emsk(struct ea
  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");
        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);
  }
@@@ -249,6 -249,7 +249,7 @@@ static int eap_sim_gsm_auth(struct eap_
                        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]) ||
                }
                return 0;
        }
+ #endif /* PCSC_FUNCS */
  
  #ifdef CONFIG_SIM_SIMULATOR
        if (conf->password) {
@@@ -1135,7 -1137,7 +1137,7 @@@ static void * eap_sim_init_for_reauth(s
        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 +1237,6 @@@ static u8 * eap_sim_get_emsk(struct eap
  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");
        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);
  }
@@@ -1,6 -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 +25,7 @@@ struct eap_tls_data 
        size_t id_len;
        void *ssl_ctx;
        u8 eap_type;
+       struct wpabuf *pending_resp;
  };
  
  
@@@ -142,6 -143,7 +143,7 @@@ static void eap_tls_deinit(struct eap_s
        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 +218,32 @@@ static struct wpabuf * eap_tls_process(
        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)
                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 +294,10 @@@ static Boolean eap_tls_has_reauth_data(
  
  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 +390,6 @@@ static u8 * eap_tls_get_session_id(stru
  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");
        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);
  }
  
  
  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,
        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 */
  
  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,
        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,0000000..0d17122
mode 100644,000000..100644
--- /dev/null
@@@ -1,1115 -1,0 +1,1124 @@@
-       if (config->ocsp == 2)
 +/*
 + * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
 + * Copyright (c) 2004-2013, 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/sha1.h"
 +#include "crypto/tls.h"
 +#include "eap_i.h"
 +#include "eap_tls_common.h"
 +#include "eap_config.h"
 +
 +
 +static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
 +                                       u8 code, u8 identifier)
 +{
 +      if (type == EAP_UNAUTH_TLS_TYPE)
 +              return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS,
 +                                   EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len,
 +                                   code, identifier);
 +      if (type == EAP_WFA_UNAUTH_TLS_TYPE)
 +              return eap_msg_alloc(EAP_VENDOR_WFA_NEW,
 +                                   EAP_VENDOR_WFA_UNAUTH_TLS, payload_len,
 +                                   code, identifier);
 +      return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
 +                           identifier);
 +}
 +
 +
 +static int eap_tls_check_blob(struct eap_sm *sm, const char **name,
 +                            const u8 **data, size_t *data_len)
 +{
 +      const struct wpa_config_blob *blob;
 +
 +      if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0)
 +              return 0;
 +
 +      blob = eap_get_config_blob(sm, *name + 7);
 +      if (blob == NULL) {
 +              wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not "
 +                         "found", __func__, *name + 7);
 +              return -1;
 +      }
 +
 +      *name = NULL;
 +      *data = blob->data;
 +      *data_len = blob->len;
 +
 +      return 0;
 +}
 +
 +
 +static void eap_tls_params_flags(struct tls_connection_params *params,
 +                               const char *txt)
 +{
 +      if (txt == NULL)
 +              return;
 +      if (os_strstr(txt, "tls_allow_md5=1"))
 +              params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5;
 +      if (os_strstr(txt, "tls_disable_time_checks=1"))
 +              params->flags |= TLS_CONN_DISABLE_TIME_CHECKS;
 +      if (os_strstr(txt, "tls_disable_session_ticket=1"))
 +              params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
 +      if (os_strstr(txt, "tls_disable_session_ticket=0"))
 +              params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET;
 +      if (os_strstr(txt, "tls_disable_tlsv1_0=1"))
 +              params->flags |= TLS_CONN_DISABLE_TLSv1_0;
 +      if (os_strstr(txt, "tls_disable_tlsv1_0=0"))
 +              params->flags &= ~TLS_CONN_DISABLE_TLSv1_0;
 +      if (os_strstr(txt, "tls_disable_tlsv1_1=1"))
 +              params->flags |= TLS_CONN_DISABLE_TLSv1_1;
 +      if (os_strstr(txt, "tls_disable_tlsv1_1=0"))
 +              params->flags &= ~TLS_CONN_DISABLE_TLSv1_1;
 +      if (os_strstr(txt, "tls_disable_tlsv1_2=1"))
 +              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;
 +}
 +
 +
 +static void eap_tls_params_from_conf1(struct tls_connection_params *params,
 +                                    struct eap_peer_config *config)
 +{
 +      params->ca_cert = (char *) config->ca_cert;
 +      params->ca_path = (char *) config->ca_path;
 +      params->client_cert = (char *) config->client_cert;
 +      params->private_key = (char *) config->private_key;
 +      params->private_key_passwd = (char *) config->private_key_passwd;
 +      params->dh_file = (char *) config->dh_file;
 +      params->subject_match = (char *) config->subject_match;
 +      params->altsubject_match = (char *) config->altsubject_match;
 +      params->suffix_match = config->domain_suffix_match;
 +      params->domain_match = config->domain_match;
 +      params->engine = config->engine;
 +      params->engine_id = config->engine_id;
 +      params->pin = config->pin;
 +      params->key_id = config->key_id;
 +      params->cert_id = config->cert_id;
 +      params->ca_cert_id = config->ca_cert_id;
 +      eap_tls_params_flags(params, config->phase1);
 +    params->server_cert_cb = config->server_cert_cb;
 +    params->server_cert_ctx = config->server_cert_ctx;
 +}
 +
 +
 +static void eap_tls_params_from_conf2(struct tls_connection_params *params,
 +                                    struct eap_peer_config *config)
 +{
 +      params->ca_cert = (char *) config->ca_cert2;
 +      params->ca_path = (char *) config->ca_path2;
 +      params->client_cert = (char *) config->client_cert2;
 +      params->private_key = (char *) config->private_key2;
 +      params->private_key_passwd = (char *) config->private_key2_passwd;
 +      params->dh_file = (char *) config->dh_file2;
 +      params->subject_match = (char *) config->subject_match2;
 +      params->altsubject_match = (char *) config->altsubject_match2;
 +      params->suffix_match = config->domain_suffix_match2;
 +      params->domain_match = config->domain_match2;
 +      params->engine = config->engine2;
 +      params->engine_id = config->engine2_id;
 +      params->pin = config->pin2;
 +      params->key_id = config->key2_id;
 +      params->cert_id = config->cert2_id;
 +      params->ca_cert_id = config->ca_cert2_id;
 +      eap_tls_params_flags(params, config->phase2);
 +    params->server_cert_cb = config->server_cert_cb;
 +    params->server_cert_ctx = config->server_cert_ctx;
 +}
 +
 +
 +static int eap_tls_params_from_conf(struct eap_sm *sm,
 +                                  struct eap_ssl_data *data,
 +                                  struct tls_connection_params *params,
 +                                  struct eap_peer_config *config, int phase2)
 +{
 +      os_memset(params, 0, sizeof(*params));
 +      if (sm->workaround && data->eap_type != EAP_TYPE_FAST) {
 +              /*
 +               * Some deployed authentication servers seem to be unable to
 +               * handle the TLS Session Ticket extension (they are supposed
 +               * to ignore unrecognized TLS extensions, but end up rejecting
 +               * the ClientHello instead). As a workaround, disable use of
 +               * TLS Sesson Ticket extension for EAP-TLS, EAP-PEAP, and
 +               * EAP-TTLS (EAP-FAST uses session ticket, so any server that
 +               * supports EAP-FAST does not need this workaround).
 +               */
 +              params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
 +      }
 +      if (phase2) {
 +              wpa_printf(MSG_DEBUG, "TLS: using phase2 config options");
 +              eap_tls_params_from_conf2(params, config);
 +      } else {
 +              wpa_printf(MSG_DEBUG, "TLS: using phase1 config options");
 +              eap_tls_params_from_conf1(params, config);
 +              if (data->eap_type == EAP_TYPE_FAST)
 +                      params->flags |= TLS_CONN_EAP_FAST;
 +      }
 +
 +      /*
 +       * Use blob data, if available. Otherwise, leave reference to external
 +       * file as-is.
 +       */
 +      if (eap_tls_check_blob(sm, &params->ca_cert, &params->ca_cert_blob,
 +                             &params->ca_cert_blob_len) ||
 +          eap_tls_check_blob(sm, &params->client_cert,
 +                             &params->client_cert_blob,
 +                             &params->client_cert_blob_len) ||
 +          eap_tls_check_blob(sm, &params->private_key,
 +                             &params->private_key_blob,
 +                             &params->private_key_blob_len) ||
 +          eap_tls_check_blob(sm, &params->dh_file, &params->dh_blob,
 +                             &params->dh_blob_len)) {
 +              wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs");
 +              return -1;
 +      }
 +
 +      params->openssl_ciphers = config->openssl_ciphers;
 +
++      sm->ext_cert_check = !!(params->flags & TLS_CONN_EXT_CERT_CHECK);
++
 +      return 0;
 +}
 +
 +
 +static int eap_tls_init_connection(struct eap_sm *sm,
 +                                 struct eap_ssl_data *data,
 +                                 struct eap_peer_config *config,
 +                                 struct tls_connection_params *params)
 +{
 +      int res;
 +
 +      if (config->ocsp)
 +              params->flags |= TLS_CONN_REQUEST_OCSP;
-       if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, 0,
-                              out, len)) {
++      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 "
 +                         "connection");
 +              return -1;
 +      }
 +
 +      res = tls_connection_set_params(data->ssl_ctx, data->conn, params);
 +      if (res == TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN) {
 +              /*
 +               * At this point with the pkcs11 engine the PIN is wrong. We
 +               * reset the PIN in the configuration to be sure to not use it
 +               * again and the calling function must request a new one.
 +               */
 +              wpa_printf(MSG_INFO,
 +                         "TLS: Bad PIN provided, requesting a new one");
 +              os_free(config->pin);
 +              config->pin = NULL;
 +              eap_sm_request_pin(sm);
 +              sm->ignore = TRUE;
 +      } else if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to initialize engine");
 +      } else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to load private key");
 +              sm->ignore = TRUE;
 +      }
 +      if (res) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
 +                         "parameters");
 +              tls_connection_deinit(data->ssl_ctx, data->conn);
 +              data->conn = NULL;
 +              return -1;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +/**
 + * eap_peer_tls_ssl_init - Initialize shared TLS functionality
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * @config: Pointer to the network configuration
 + * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function is used to initialize shared TLS functionality for EAP-TLS,
 + * EAP-PEAP, EAP-TTLS, and EAP-FAST.
 + */
 +int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
 +                        struct eap_peer_config *config, u8 eap_type)
 +{
 +      struct tls_connection_params params;
 +
 +      if (config == NULL)
 +              return -1;
 +
 +      data->eap = sm;
 +      data->eap_type = eap_type;
 +      data->phase2 = sm->init_phase2;
 +      data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
 +              sm->ssl_ctx;
 +      if (eap_tls_params_from_conf(sm, data, &params, config, data->phase2) <
 +          0)
 +              return -1;
 +
 +      if (eap_tls_init_connection(sm, data, config, &params) < 0)
 +              return -1;
 +
 +      data->tls_out_limit = config->fragment_size;
 +      if (data->phase2) {
 +              /* Limit the fragment size in the inner TLS authentication
 +               * since the outer authentication with EAP-PEAP does not yet
 +               * support fragmentation */
 +              if (data->tls_out_limit > 100)
 +                      data->tls_out_limit -= 100;
 +      }
 +
 +      if (config->phase1 &&
 +          os_strstr(config->phase1, "include_tls_length=1")) {
 +              wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in "
 +                         "unfragmented packets");
 +              data->include_tls_length = 1;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +/**
 + * eap_peer_tls_ssl_deinit - Deinitialize shared TLS functionality
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + *
 + * This function deinitializes shared TLS functionality that was initialized
 + * with eap_peer_tls_ssl_init().
 + */
 +void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
 +{
 +      tls_connection_deinit(data->ssl_ctx, data->conn);
 +      eap_peer_tls_reset_input(data);
 +      eap_peer_tls_reset_output(data);
 +}
 +
 +
 +/**
 + * eap_peer_tls_derive_key - Derive a key based on TLS session data
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * @label: Label string for deriving the keys, e.g., "client EAP encryption"
 + * @len: Length of the key material to generate (usually 64 for MSK)
 + * Returns: Pointer to allocated key on success or %NULL on failure
 + *
 + * This function uses TLS-PRF to generate pseudo-random data based on the TLS
 + * session data (client/server random and master key). Each key type may use a
 + * different label to bind the key usage into the generated material.
 + *
 + * The caller is responsible for freeing the returned buffer.
 + */
 +u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
 +                           const char *label, size_t len)
 +{
 +      u8 *out;
 +
 +      out = os_malloc(len);
 +      if (out == NULL)
 +              return NULL;
 +
-       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_export_key(data->ssl_ctx, data->conn, label, out,
++                                    len)) {
 +              os_free(out);
 +              return NULL;
 +      }
 +
 +      return out;
 +}
 +
 +
 +/**
 + * eap_peer_tls_derive_session_id - Derive a Session-Id based on TLS data
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
 + * @len: Pointer to length of the session ID generated
 + * Returns: Pointer to allocated Session-Id on success or %NULL on failure
 + *
 + * This function derive the Session-Id based on the TLS session data
 + * (client/server random and method type).
 + *
 + * The caller is responsible for freeing the returned buffer.
 + */
 +u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
 +                                  struct eap_ssl_data *data, u8 eap_type,
 +                                  size_t *len)
 +{
 +      struct tls_random keys;
 +      u8 *out;
 +
++      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;
 +      out = os_malloc(*len);
 +      if (out == NULL)
 +              return NULL;
 +
 +      /* Session-Id = EAP type || client.random || server.random */
 +      out[0] = eap_type;
 +      os_memcpy(out + 1, keys.client_random, keys.client_random_len);
 +      os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
 +                keys.server_random_len);
 +
 +      return out;
 +}
 +
 +
 +/**
 + * eap_peer_tls_reassemble_fragment - Reassemble a received fragment
 + * @data: Data for TLS processing
 + * @in_data: Next incoming TLS segment
 + * Returns: 0 on success, 1 if more data is needed for the full message, or
 + * -1 on error
 + */
 +static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data,
 +                                          const struct wpabuf *in_data)
 +{
 +      size_t tls_in_len, in_len;
 +
 +      tls_in_len = data->tls_in ? wpabuf_len(data->tls_in) : 0;
 +      in_len = in_data ? wpabuf_len(in_data) : 0;
 +
 +      if (tls_in_len + in_len == 0) {
 +              /* No message data received?! */
 +              wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: "
 +                         "tls_in_left=%lu tls_in_len=%lu in_len=%lu",
 +                         (unsigned long) data->tls_in_left,
 +                         (unsigned long) tls_in_len,
 +                         (unsigned long) in_len);
 +              eap_peer_tls_reset_input(data);
 +              return -1;
 +      }
 +
 +      if (tls_in_len + in_len > 65536) {
 +              /*
 +               * Limit length to avoid rogue servers from causing large
 +               * memory allocations.
 +               */
 +              wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size over "
 +                         "64 kB)");
 +              eap_peer_tls_reset_input(data);
 +              return -1;
 +      }
 +
 +      if (in_len > data->tls_in_left) {
 +              /* Sender is doing something odd - reject message */
 +              wpa_printf(MSG_INFO, "SSL: more data than TLS message length "
 +                         "indicated");
 +              eap_peer_tls_reset_input(data);
 +              return -1;
 +      }
 +
 +      if (wpabuf_resize(&data->tls_in, in_len) < 0) {
 +              wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS "
 +                         "data");
 +              eap_peer_tls_reset_input(data);
 +              return -1;
 +      }
 +      if (in_data)
 +              wpabuf_put_buf(data->tls_in, in_data);
 +      data->tls_in_left -= in_len;
 +
 +      if (data->tls_in_left > 0) {
 +              wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
 +                         "data", (unsigned long) data->tls_in_left);
 +              return 1;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +/**
 + * eap_peer_tls_data_reassemble - Reassemble TLS data
 + * @data: Data for TLS processing
 + * @in_data: Next incoming TLS segment
 + * @need_more_input: Variable for returning whether more input data is needed
 + * to reassemble this TLS packet
 + * Returns: Pointer to output data, %NULL on error or when more data is needed
 + * for the full message (in which case, *need_more_input is also set to 1).
 + *
 + * This function reassembles TLS fragments. Caller must not free the returned
 + * data buffer since an internal pointer to it is maintained.
 + */
 +static const struct wpabuf * eap_peer_tls_data_reassemble(
 +      struct eap_ssl_data *data, const struct wpabuf *in_data,
 +      int *need_more_input)
 +{
 +      *need_more_input = 0;
 +
 +      if (data->tls_in_left > wpabuf_len(in_data) || data->tls_in) {
 +              /* Message has fragments */
 +              int res = eap_peer_tls_reassemble_fragment(data, in_data);
 +              if (res) {
 +                      if (res == 1)
 +                              *need_more_input = 1;
 +                      return NULL;
 +              }
 +
 +              /* Message is now fully reassembled. */
 +      } else {
 +              /* No fragments in this message, so just make a copy of it. */
 +              data->tls_in_left = 0;
 +              data->tls_in = wpabuf_dup(in_data);
 +              if (data->tls_in == NULL)
 +                      return NULL;
 +      }
 +
 +      return data->tls_in;
 +}
 +
 +
 +/**
 + * eap_tls_process_input - Process incoming TLS message
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * @in_data: Message received from the server
 + * @out_data: Buffer for returning a pointer to application data (if available)
 + * Returns: 0 on success, 1 if more input data is needed, 2 if application data
 + * is available, -1 on failure
 + */
 +static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data,
 +                               const struct wpabuf *in_data,
 +                               struct wpabuf **out_data)
 +{
 +      const struct wpabuf *msg;
 +      int need_more_input;
 +      struct wpabuf *appl_data;
 +
 +      msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input);
 +      if (msg == NULL)
 +              return need_more_input ? 1 : -1;
 +
 +      /* Full TLS message reassembled - continue handshake processing */
 +      if (data->tls_out) {
 +              /* This should not happen.. */
 +              wpa_printf(MSG_INFO, "SSL: eap_tls_process_input - pending "
 +                         "tls_out data even though tls_out_len = 0");
 +              wpabuf_free(data->tls_out);
 +              WPA_ASSERT(data->tls_out == NULL);
 +      }
 +      appl_data = NULL;
 +      data->tls_out = tls_connection_handshake(data->ssl_ctx, data->conn,
 +                                               msg, &appl_data);
 +
 +      eap_peer_tls_reset_input(data);
 +
 +      if (appl_data &&
 +          tls_connection_established(data->ssl_ctx, data->conn) &&
 +          !tls_connection_get_failed(data->ssl_ctx, data->conn)) {
 +              wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data",
 +                                  appl_data);
 +              *out_data = appl_data;
 +              return 2;
 +      }
 +
 +      wpabuf_free(appl_data);
 +
 +      return 0;
 +}
 +
 +
 +/**
 + * eap_tls_process_output - Process outgoing TLS message
 + * @data: Data for TLS processing
 + * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
 + * @peap_version: Version number for EAP-PEAP/TTLS
 + * @id: EAP identifier for the response
 + * @ret: Return value to use on success
 + * @out_data: Buffer for returning the allocated output buffer
 + * Returns: ret (0 or 1) on success, -1 on failure
 + */
 +static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,
 +                                int peap_version, u8 id, int ret,
 +                                struct wpabuf **out_data)
 +{
 +      size_t len;
 +      u8 *flags;
 +      int more_fragments, length_included;
 +
 +      if (data->tls_out == NULL)
 +              return -1;
 +      len = wpabuf_len(data->tls_out) - data->tls_out_pos;
 +      wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "
 +                 "%lu bytes)",
 +                 (unsigned long) len,
 +                 (unsigned long) wpabuf_len(data->tls_out));
 +
 +      /*
 +       * Limit outgoing message to the configured maximum size. Fragment
 +       * message if needed.
 +       */
 +      if (len > data->tls_out_limit) {
 +              more_fragments = 1;
 +              len = data->tls_out_limit;
 +              wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments "
 +                         "will follow", (unsigned long) len);
 +      } else
 +              more_fragments = 0;
 +
 +      length_included = data->tls_out_pos == 0 &&
 +              (wpabuf_len(data->tls_out) > data->tls_out_limit ||
 +               data->include_tls_length);
 +      if (!length_included &&
 +          eap_type == EAP_TYPE_PEAP && peap_version == 0 &&
 +          !tls_connection_established(data->eap->ssl_ctx, data->conn)) {
 +              /*
 +               * Windows Server 2008 NPS really wants to have the TLS Message
 +               * length included in phase 0 even for unfragmented frames or
 +               * it will get very confused with Compound MAC calculation and
 +               * Outer TLVs.
 +               */
 +              length_included = 1;
 +      }
 +
 +      *out_data = eap_tls_msg_alloc(eap_type, 1 + length_included * 4 + len,
 +                                    EAP_CODE_RESPONSE, id);
 +      if (*out_data == NULL)
 +              return -1;
 +
 +      flags = wpabuf_put(*out_data, 1);
 +      *flags = peap_version;
 +      if (more_fragments)
 +              *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
 +      if (length_included) {
 +              *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
 +              wpabuf_put_be32(*out_data, wpabuf_len(data->tls_out));
 +      }
 +
 +      wpabuf_put_data(*out_data,
 +                      wpabuf_head_u8(data->tls_out) + data->tls_out_pos,
 +                      len);
 +      data->tls_out_pos += len;
 +
 +      if (!more_fragments)
 +              eap_peer_tls_reset_output(data);
 +
 +      return ret;
 +}
 +
 +
 +/**
 + * eap_peer_tls_process_helper - Process TLS handshake message
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
 + * @peap_version: Version number for EAP-PEAP/TTLS
 + * @id: EAP identifier for the response
 + * @in_data: Message received from the server
 + * @out_data: Buffer for returning a pointer to the response message
 + * Returns: 0 on success, 1 if more input data is needed, 2 if application data
 + * is available, or -1 on failure
 + *
 + * This function can be used to process TLS handshake messages. It reassembles
 + * the received fragments and uses a TLS library to process the messages. The
 + * response data from the TLS library is fragmented to suitable output messages
 + * that the caller can send out.
 + *
 + * out_data is used to return the response message if the return value of this
 + * function is 0, 2, or -1. In case of failure, the message is likely a TLS
 + * alarm message. The caller is responsible for freeing the allocated buffer if
 + * *out_data is not %NULL.
 + *
 + * This function is called for each received TLS message during the TLS
 + * handshake after eap_peer_tls_process_init() call and possible processing of
 + * TLS Flags field. Once the handshake has been completed, i.e., when
 + * tls_connection_established() returns 1, EAP method specific decrypting of
 + * the tunneled data is used.
 + */
 +int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
 +                              EapType eap_type, int peap_version,
 +                              u8 id, const struct wpabuf *in_data,
 +                              struct wpabuf **out_data)
 +{
 +      int ret = 0;
 +
 +      *out_data = NULL;
 +
 +      if (data->tls_out && wpabuf_len(data->tls_out) > 0 &&
 +          wpabuf_len(in_data) > 0) {
 +              wpa_printf(MSG_DEBUG, "SSL: Received non-ACK when output "
 +                         "fragments are waiting to be sent out");
 +              return -1;
 +      }
 +
 +      if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) {
 +              /*
 +               * No more data to send out - expect to receive more data from
 +               * the AS.
 +               */
 +              int res = eap_tls_process_input(sm, data, in_data, out_data);
 +              if (res) {
 +                      /*
 +                       * Input processing failed (res = -1) or more data is
 +                       * needed (res = 1).
 +                       */
 +                      return res;
 +              }
 +
 +              /*
 +               * The incoming message has been reassembled and processed. The
 +               * response was allocated into data->tls_out buffer.
 +               */
 +      }
 +
 +      if (data->tls_out == NULL) {
 +              /*
 +               * No outgoing fragments remaining from the previous message
 +               * and no new message generated. This indicates an error in TLS
 +               * processing.
 +               */
 +              eap_peer_tls_reset_output(data);
 +              return -1;
 +      }
 +
 +      if (tls_connection_get_failed(data->ssl_ctx, data->conn)) {
 +              /* TLS processing has failed - return error */
 +              wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
 +                         "report error (len=%u)",
 +                         (unsigned int) wpabuf_len(data->tls_out));
 +              ret = -1;
 +              /* TODO: clean pin if engine used? */
 +              if (wpabuf_len(data->tls_out) == 0) {
 +                      wpabuf_free(data->tls_out);
 +                      data->tls_out = NULL;
 +                      return -1;
 +              }
 +      }
 +
 +      if (wpabuf_len(data->tls_out) == 0) {
 +              /*
 +               * TLS negotiation should now be complete since all other cases
 +               * needing more data should have been caught above based on
 +               * the TLS Message Length field.
 +               */
 +              wpa_printf(MSG_DEBUG, "SSL: No data to be sent out");
 +              wpabuf_free(data->tls_out);
 +              data->tls_out = NULL;
 +              return 1;
 +      }
 +
 +      /* Send the pending message (in fragments, if needed). */
 +      return eap_tls_process_output(data, eap_type, peap_version, id, ret,
 +                                    out_data);
 +}
 +
 +
 +/**
 + * eap_peer_tls_build_ack - Build a TLS ACK frame
 + * @id: EAP identifier for the response
 + * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
 + * @peap_version: Version number for EAP-PEAP/TTLS
 + * Returns: Pointer to the allocated ACK frame or %NULL on failure
 + */
 +struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
 +                                     int peap_version)
 +{
 +      struct wpabuf *resp;
 +
 +      resp = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_RESPONSE, id);
 +      if (resp == NULL)
 +              return NULL;
 +      wpa_printf(MSG_DEBUG, "SSL: Building ACK (type=%d id=%d ver=%d)",
 +                 (int) eap_type, id, peap_version);
 +      wpabuf_put_u8(resp, peap_version); /* Flags */
 +      return resp;
 +}
 +
 +
 +/**
 + * eap_peer_tls_reauth_init - Re-initialize shared TLS for session resumption
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * Returns: 0 on success, -1 on failure
 + */
 +int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data)
 +{
 +      eap_peer_tls_reset_input(data);
 +      eap_peer_tls_reset_output(data);
 +      return tls_connection_shutdown(data->ssl_ctx, data->conn);
 +}
 +
 +
 +/**
 + * eap_peer_tls_status - Get TLS status
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * @buf: Buffer for status information
 + * @buflen: Maximum buffer length
 + * @verbose: Whether to include verbose status information
 + * Returns: Number of bytes written to buf.
 + */
 +int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
 +                      char *buf, size_t buflen, int verbose)
 +{
 +      char version[20], name[128];
 +      int len = 0, ret;
 +
 +      if (tls_get_version(data->ssl_ctx, data->conn, version,
 +                          sizeof(version)) < 0)
 +              version[0] = '\0';
 +      if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) < 0)
 +              name[0] = '\0';
 +
 +      ret = os_snprintf(buf + len, buflen - len,
 +                        "eap_tls_version=%s\n"
 +                        "EAP TLS cipher=%s\n"
 +                        "tls_session_reused=%d\n",
 +                        version, name,
 +                        tls_connection_resumed(data->ssl_ctx, data->conn));
 +      if (os_snprintf_error(buflen - len, ret))
 +              return len;
 +      len += ret;
 +
 +      return len;
 +}
 +
 +
 +/**
 + * eap_peer_tls_process_init - Initial validation/processing of EAP requests
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
 + * @ret: Return values from EAP request validation and processing
 + * @reqData: EAP request to be processed (eapReqData)
 + * @len: Buffer for returning length of the remaining payload
 + * @flags: Buffer for returning TLS flags
 + * Returns: Pointer to payload after TLS flags and length or %NULL on failure
 + *
 + * This function validates the EAP header and processes the optional TLS
 + * Message Length field. If this is the first fragment of a TLS message, the
 + * TLS reassembly code is initialized to receive the indicated number of bytes.
 + *
 + * EAP-TLS, EAP-PEAP, EAP-TTLS, and EAP-FAST methods are expected to use this
 + * function as the first step in processing received messages. They will need
 + * to process the flags (apart from Message Length Included) that are returned
 + * through the flags pointer and the message payload that will be returned (and
 + * the length is returned through the len pointer). Return values (ret) are set
 + * for continuation of EAP method processing. The caller is responsible for
 + * setting these to indicate completion (either success or failure) based on
 + * the authentication result.
 + */
 +const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
 +                                   struct eap_ssl_data *data,
 +                                   EapType eap_type,
 +                                   struct eap_method_ret *ret,
 +                                   const struct wpabuf *reqData,
 +                                   size_t *len, u8 *flags)
 +{
 +      const u8 *pos;
 +      size_t left;
 +      unsigned int tls_msg_len;
 +
 +      /* Ignore errors before we do anything*/
 +      (void) tls_get_errors(sm->ssl_ctx);
 +
 +      //// if (tls_get_errors(data->ssl_ctx)) {
 +      ////    wpa_printf(MSG_INFO, "SSL: TLS errors detected");
 +      ////    ret->ignore = TRUE;
 +      ////    return NULL;
 +      //// }
 +
 +      if (eap_type == EAP_UNAUTH_TLS_TYPE)
 +              pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
 +                                     EAP_VENDOR_TYPE_UNAUTH_TLS, reqData,
 +                                     &left);
 +      else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
 +              pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
 +                                     EAP_VENDOR_WFA_UNAUTH_TLS, reqData,
 +                                     &left);
 +      else
 +              pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData,
 +                                     &left);
 +      if (pos == NULL) {
 +              ret->ignore = TRUE;
 +              return NULL;
 +      }
 +      if (left == 0) {
 +              wpa_printf(MSG_DEBUG, "SSL: Invalid TLS message: no Flags "
 +                         "octet included");
 +              if (!sm->workaround) {
 +                      ret->ignore = TRUE;
 +                      return NULL;
 +              }
 +
 +              wpa_printf(MSG_DEBUG, "SSL: Workaround - assume no Flags "
 +                         "indicates ACK frame");
 +              *flags = 0;
 +      } else {
 +              *flags = *pos++;
 +              left--;
 +      }
 +      wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - "
 +                 "Flags 0x%02x", (unsigned long) wpabuf_len(reqData),
 +                 *flags);
 +      if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
 +              if (left < 4) {
 +                      wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
 +                                 "length");
 +                      ret->ignore = TRUE;
 +                      return NULL;
 +              }
 +              tls_msg_len = WPA_GET_BE32(pos);
 +              wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
 +                         tls_msg_len);
 +              if (data->tls_in_left == 0) {
 +                      data->tls_in_total = tls_msg_len;
 +                      data->tls_in_left = tls_msg_len;
 +                      wpabuf_free(data->tls_in);
 +                      data->tls_in = NULL;
 +              }
 +              pos += 4;
 +              left -= 4;
 +
 +              if (left > tls_msg_len) {
 +                      wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d "
 +                                 "bytes) smaller than this fragment (%d "
 +                                 "bytes)", (int) tls_msg_len, (int) left);
 +                      ret->ignore = TRUE;
 +                      return NULL;
 +              }
 +      }
 +
 +      ret->ignore = FALSE;
 +      ret->methodState = METHOD_MAY_CONT;
 +      ret->decision = DECISION_FAIL;
 +      ret->allowNotifications = TRUE;
 +
 +      *len = left;
 +      return pos;
 +}
 +
 +
 +/**
 + * eap_peer_tls_reset_input - Reset input buffers
 + * @data: Data for TLS processing
 + *
 + * This function frees any allocated memory for input buffers and resets input
 + * state.
 + */
 +void eap_peer_tls_reset_input(struct eap_ssl_data *data)
 +{
 +      data->tls_in_left = data->tls_in_total = 0;
 +      wpabuf_free(data->tls_in);
 +      data->tls_in = NULL;
 +}
 +
 +
 +/**
 + * eap_peer_tls_reset_output - Reset output buffers
 + * @data: Data for TLS processing
 + *
 + * This function frees any allocated memory for output buffers and resets
 + * output state.
 + */
 +void eap_peer_tls_reset_output(struct eap_ssl_data *data)
 +{
 +      data->tls_out_pos = 0;
 +      wpabuf_free(data->tls_out);
 +      data->tls_out = NULL;
 +}
 +
 +
 +/**
 + * eap_peer_tls_decrypt - Decrypt received phase 2 TLS message
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * @in_data: Message received from the server
 + * @in_decrypted: Buffer for returning a pointer to the decrypted message
 + * Returns: 0 on success, 1 if more input data is needed, or -1 on failure
 + */
 +int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data,
 +                       const struct wpabuf *in_data,
 +                       struct wpabuf **in_decrypted)
 +{
 +      const struct wpabuf *msg;
 +      int need_more_input;
 +
 +      msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input);
 +      if (msg == NULL)
 +              return need_more_input ? 1 : -1;
 +
 +      *in_decrypted = tls_connection_decrypt(data->ssl_ctx, data->conn, msg);
 +      eap_peer_tls_reset_input(data);
 +      if (*in_decrypted == NULL) {
 +              wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data");
 +              return -1;
 +      }
 +      return 0;
 +}
 +
 +
 +/**
 + * eap_peer_tls_encrypt - Encrypt phase 2 TLS message
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
 + * @peap_version: Version number for EAP-PEAP/TTLS
 + * @id: EAP identifier for the response
 + * @in_data: Plaintext phase 2 data to encrypt or %NULL to continue fragments
 + * @out_data: Buffer for returning a pointer to the encrypted response message
 + * Returns: 0 on success, -1 on failure
 + */
 +int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
 +                       EapType eap_type, int peap_version, u8 id,
 +                       const struct wpabuf *in_data,
 +                       struct wpabuf **out_data)
 +{
 +      if (in_data) {
 +              eap_peer_tls_reset_output(data);
 +              data->tls_out = tls_connection_encrypt(data->ssl_ctx,
 +                                                     data->conn, in_data);
 +              if (data->tls_out == NULL) {
 +                      wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 "
 +                                 "data (in_len=%lu)",
 +                                 (unsigned long) wpabuf_len(in_data));
 +                      eap_peer_tls_reset_output(data);
 +                      return -1;
 +              }
 +      }
 +
 +      return eap_tls_process_output(data, eap_type, peap_version, id, 0,
 +                                    out_data);
 +}
 +
 +
 +/**
 + * eap_peer_select_phase2_methods - Select phase 2 EAP method
 + * @config: Pointer to the network configuration
 + * @prefix: 'phase2' configuration prefix, e.g., "auth="
 + * @types: Buffer for returning allocated list of allowed EAP methods
 + * @num_types: Buffer for returning number of allocated EAP methods
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function is used to parse EAP method list and select allowed methods
 + * for Phase2 authentication.
 + */
 +int eap_peer_select_phase2_methods(struct eap_peer_config *config,
 +                                 const char *prefix,
 +                                 struct eap_method_type **types,
 +                                 size_t *num_types)
 +{
 +      char *start, *pos, *buf;
 +      struct eap_method_type *methods = NULL, *_methods;
 +      u32 method;
 +      size_t num_methods = 0, prefix_len;
 +
 +      if (config == NULL || config->phase2 == NULL)
 +              goto get_defaults;
 +
 +      start = buf = os_strdup(config->phase2);
 +      if (buf == NULL)
 +              return -1;
 +
 +      prefix_len = os_strlen(prefix);
 +
 +      while (start && *start != '\0') {
 +              int vendor;
 +              pos = os_strstr(start, prefix);
 +              if (pos == NULL)
 +                      break;
 +              if (start != pos && *(pos - 1) != ' ') {
 +                      start = pos + prefix_len;
 +                      continue;
 +              }
 +
 +              start = pos + prefix_len;
 +              pos = os_strchr(start, ' ');
 +              if (pos)
 +                      *pos++ = '\0';
 +              method = eap_get_phase2_type(start, &vendor);
 +              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,
 +                                                  sizeof(*methods));
 +                      if (_methods == NULL) {
 +                              os_free(methods);
 +                              os_free(buf);
 +                              return -1;
 +                      }
 +                      methods = _methods;
 +                      methods[num_methods - 1].vendor = vendor;
 +                      methods[num_methods - 1].method = method;
 +              }
 +
 +              start = pos;
 +      }
 +
 +      os_free(buf);
 +
 +get_defaults:
 +      if (methods == NULL)
 +              methods = eap_get_phase2_types(config, &num_methods);
 +
 +      if (methods == NULL) {
 +              wpa_printf(MSG_ERROR, "TLS: No Phase2 EAP methods available");
 +              return -1;
 +      }
 +      wpa_hexdump(MSG_DEBUG, "TLS: Phase2 EAP types",
 +                  (u8 *) methods,
 +                  num_methods * sizeof(struct eap_method_type));
 +
 +      *types = methods;
 +      *num_types = num_methods;
 +
 +      return 0;
 +}
 +
 +
 +/**
 + * eap_peer_tls_phase2_nak - Generate EAP-Nak for Phase 2
 + * @types: Buffer for returning allocated list of allowed EAP methods
 + * @num_types: Buffer for returning number of allocated EAP methods
 + * @hdr: EAP-Request header (and the following EAP type octet)
 + * @resp: Buffer for returning the EAP-Nak message
 + * Returns: 0 on success, -1 on failure
 + */
 +int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types,
 +                          struct eap_hdr *hdr, struct wpabuf **resp)
 +{
 +      u8 *pos = (u8 *) (hdr + 1);
 +      size_t i;
 +
 +      /* TODO: add support for expanded Nak */
 +      wpa_printf(MSG_DEBUG, "TLS: Phase 2 Request: Nak type=%d", *pos);
 +      wpa_hexdump(MSG_DEBUG, "TLS: Allowed Phase2 EAP types",
 +                  (u8 *) types, num_types * sizeof(struct eap_method_type));
 +      *resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK, num_types,
 +                            EAP_CODE_RESPONSE, hdr->identifier);
 +      if (*resp == NULL)
 +              return -1;
 +
 +      for (i = 0; i < num_types; i++) {
 +              if (types[i].vendor == EAP_VENDOR_IETF &&
 +                  types[i].method < 256)
 +                      wpabuf_put_u8(*resp, types[i].method);
 +      }
 +
 +      eap_update_len(*resp);
 +
 +      return 0;
 +}
@@@ -10,6 -10,7 +10,7 @@@
  
  #include "common.h"
  #include "eap_i.h"
+ #include "eap_config.h"
  #include "tncc.h"
  
  
@@@ -35,12 -36,16 +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 +350,6 @@@ static struct wpabuf * eap_tnc_process(
        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 +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");
        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,0000000..12ea169
mode 100644,000000..100644
--- /dev/null
@@@ -1,1956 -1,0 +1,2048 @@@
-  * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
 +/*
 + * EAP peer method: EAP-TTLS (RFC 5281)
-   EapDecision cbDecision;
++ * 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 "common.h"
 +#include "radius/radius.h"
 +#include "crypto/ms_funcs.h"
 +#include "crypto/sha1.h"
 +#include "crypto/tls.h"
 +#include "eap_common/chap.h"
 +#include "eap_common/eap_ttls.h"
 +#include "mschapv2.h"
 +#include "eap_i.h"
 +#include "eap_tls_common.h"
 +#include "eap_config.h"
 +
 +
 +#define EAP_TTLS_VERSION 0
 +
 +
 +static void eap_ttls_deinit(struct eap_sm *sm, void *priv);
 +
 +
 +struct eap_ttls_data {
 +      struct eap_ssl_data ssl;
 +
 +      int ttls_version;
 +
 +      const struct eap_method *phase2_method;
 +      void *phase2_priv;
 +      int phase2_success;
 +      int phase2_start;
++      EapDecision decision_succ;
 +
 +      enum phase2_types {
 +              EAP_TTLS_PHASE2_EAP,
 +              EAP_TTLS_PHASE2_MSCHAPV2,
 +              EAP_TTLS_PHASE2_MSCHAP,
 +              EAP_TTLS_PHASE2_PAP,
 +              EAP_TTLS_PHASE2_CHAP
 +      } phase2_type;
 +      struct eap_method_type phase2_eap_type;
 +      struct eap_method_type *phase2_eap_types;
 +      size_t num_phase2_eap_types;
 +
 +      u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN];
 +      int auth_response_valid;
 +      u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; /* MSCHAPv2 master key */
 +      u8 ident;
 +      int resuming; /* starting a resumed session */
 +      int reauth; /* reauthentication */
 +      u8 *key_data;
 +      u8 *session_id;
 +      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*/
-               } 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;
++      EapDecision cbDecision;
 +#ifdef EAP_TNC
 +      int ready_for_tnc;
 +      int tnc_started;
 +#endif /* EAP_TNC */
 +};
 +
 +
 +/* draft-ietf-emu-chbind-13 section 5.3 */
 +
 +#ifdef _MSC_VER
 +#pragma pack(push, 1)
 +#endif /* _MSC_VER */
 +
 +struct chbind_hdr {
 +      u16 len;
 +      u8 nsid;
 +} STRUCT_PACKED;
 +
 +#ifdef _MSC_VER
 +#pragma pack(pop)
 +#endif /* _MSC_VER */
 +
 +
 +
 +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));
 +      if (data == NULL)
 +              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;
-       int ret;
 +              }
 +      }
++
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected);
 +
 +      if (data->phase2_type == EAP_TTLS_PHASE2_EAP) {
 +              if (eap_peer_select_phase2_methods(config, "autheap=",
 +                                                 &data->phase2_eap_types,
 +                                                 &data->num_phase2_eap_types)
 +                  < 0) {
 +                      eap_ttls_deinit(sm, data);
 +                      return NULL;
 +              }
 +
 +              data->phase2_eap_type.vendor = EAP_VENDOR_IETF;
 +              data->phase2_eap_type.method = EAP_TYPE_NONE;
 +      }
 +
 +      if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TTLS)) {
 +              wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
 +              eap_ttls_deinit(sm, data);
 +              return NULL;
 +      }
 +
 +      return data;
 +}
 +
 +
 +static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm,
 +                                     struct eap_ttls_data *data)
 +{
 +      if (data->phase2_priv && data->phase2_method) {
 +              data->phase2_method->deinit(sm, data->phase2_priv);
 +              data->phase2_method = NULL;
 +              data->phase2_priv = NULL;
 +      }
 +}
 +
 +
 +static void eap_ttls_free_key(struct eap_ttls_data *data)
 +{
 +      if (data->key_data) {
 +              bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
 +              data->key_data = NULL;
 +      }
 +}
 +
 +
 +static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
 +{
 +      struct eap_ttls_data *data = priv;
 +      if (data == NULL)
 +              return;
 +      eap_ttls_phase2_eap_deinit(sm, data);
 +      os_free(data->phase2_eap_types);
 +      eap_peer_tls_ssl_deinit(sm, &data->ssl);
 +      eap_ttls_free_key(data);
 +      os_free(data->session_id);
 +      wpabuf_free(data->pending_phase2_req);
++      wpabuf_free(data->pending_resp);
 +      os_free(data);
 +}
 +
 +
 +static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id,
 +                           int mandatory, size_t len)
 +{
 +      struct ttls_avp_vendor *avp;
 +      u8 flags;
 +      size_t hdrlen;
 +
 +      avp = (struct ttls_avp_vendor *) avphdr;
 +      flags = mandatory ? AVP_FLAGS_MANDATORY : 0;
 +      if (vendor_id) {
 +              flags |= AVP_FLAGS_VENDOR;
 +              hdrlen = sizeof(*avp);
 +              avp->vendor_id = host_to_be32(vendor_id);
 +      } else {
 +              hdrlen = sizeof(struct ttls_avp);
 +      }
 +
 +      avp->avp_code = host_to_be32(avp_code);
 +      avp->avp_length = host_to_be32(((u32) flags << 24) |
 +                                     (u32) (hdrlen + len));
 +
 +      return avphdr + hdrlen;
 +}
 +
 +
 +static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code,
 +                           u32 vendor_id, int mandatory,
 +                           const u8 *data, size_t len)
 +{
 +      u8 *pos;
 +      pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len);
 +      os_memcpy(pos, data, len);
 +      pos += len;
 +      AVP_PAD(start, pos);
 +      return pos;
 +}
 +
 +
 +static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code,
 +                                  int mandatory)
 +{
 +      struct wpabuf *msg;
 +      u8 *avp, *pos;
 +
 +      msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4);
 +      if (msg == NULL) {
 +              wpabuf_free(*resp);
 +              *resp = NULL;
 +              return -1;
 +      }
 +
 +      avp = wpabuf_mhead(msg);
 +      pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, wpabuf_len(*resp));
 +      os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp));
 +      pos += wpabuf_len(*resp);
 +      AVP_PAD(avp, pos);
 +      wpabuf_free(*resp);
 +      wpabuf_put(msg, pos - avp);
 +      *resp = msg;
 +      return 0;
 +}
 +
 +/* chop up resp into multiple vsa's as necessary*/
 +static int eap_ttls_avp_radius_vsa_encapsulate(struct wpabuf **resp, u32 vendor,
 +                                      u8 attr, int mandatory)
 +{
 +      struct wpabuf *msg;
 +      u8 *avp, *pos, *src, *final;
 +      size_t size = wpabuf_len(*resp);
 +      size_t num_msgs = 1 + (size / 248);
 +      size_t msg_wrapper_size = sizeof(struct ttls_avp_vendor) + 6;
 +      size_t allocated_total = num_msgs * (4 + msg_wrapper_size) + size;
 +
 +      msg = wpabuf_alloc(allocated_total);
 +      if (msg == NULL) {
 +              wpabuf_free(*resp);
 +              *resp = NULL;
 +              return -1;
 +      }
 +      src = wpabuf_mhead(*resp);
 +      avp = wpabuf_mhead(msg);
 +      while (size > 0) {
 +              int avp_size = size > 248 ? 248 : size;
 +              size -= avp_size;
 +              pos = eap_ttls_avp_hdr(avp, RADIUS_ATTR_VENDOR_SPECIFIC, 0, mandatory,
 +                                     avp_size+6);
 +              wpabuf_put(msg, pos-avp);
 +              wpabuf_put_be32(msg, vendor);
 +              wpabuf_put_u8(msg, (u8) attr);
 +              wpabuf_put_u8(msg, (u8) avp_size+2);
 +              wpabuf_put_data(msg, src, avp_size);
 +              src += avp_size;
 +              pos = wpabuf_mhead_u8(msg) + wpabuf_len(msg);
 +              final = pos; /*keep pos so we know how much padding is added*/
 +              AVP_PAD(avp, final); /*final modified*/
 +              if (final > pos)
 +                      wpabuf_put(msg, final-pos);
 +              avp = final;
 +      }
 +      /* check avp-wpabuf_mhead(msg) < allocated_total */
 +      wpabuf_free(*resp);
 +      *resp = msg;
 +      return 0;
 +}
 +
 +static int eap_ttls_v0_derive_key(struct eap_sm *sm,
 +                                struct eap_ttls_data *data)
 +{
 +      eap_ttls_free_key(data);
 +      data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
 +                                               "ttls keying material",
 +                                               EAP_TLS_KEY_LEN +
 +                                               EAP_EMSK_LEN);
 +      if (!data->key_data) {
 +              wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key");
 +              return -1;
 +      }
 +
 +      wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
 +                      data->key_data, EAP_TLS_KEY_LEN);
 +      wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived EMSK",
 +                      data->key_data + EAP_TLS_KEY_LEN,
 +                      EAP_EMSK_LEN);
 +
 +      os_free(data->session_id);
 +      data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
 +                                                        EAP_TYPE_TTLS,
 +                                                        &data->id_len);
 +      if (data->session_id) {
 +              wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id",
 +                          data->session_id, data->id_len);
 +      } else {
 +              wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id");
 +      }
 +
 +      return 0;
 +}
 +
 +
 +#ifndef CONFIG_FIPS
 +static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
 +                                      struct eap_ttls_data *data, size_t len)
 +{
 +      return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len);
 +}
 +#endif /* CONFIG_FIPS */
 +
 +
 +static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data,
 +                                            u8 method)
 +{
 +      size_t i;
 +      for (i = 0; i < data->num_phase2_eap_types; i++) {
 +              if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF ||
 +                  data->phase2_eap_types[i].method != method)
 +                      continue;
 +
 +              data->phase2_eap_type.vendor =
 +                      data->phase2_eap_types[i].vendor;
 +              data->phase2_eap_type.method =
 +                      data->phase2_eap_types[i].method;
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected "
 +                         "Phase 2 EAP vendor %d method %d",
 +                         data->phase2_eap_type.vendor,
 +                         data->phase2_eap_type.method);
 +              break;
 +      }
 +}
 +
 +
 +static int eap_ttls_phase2_eap_process(struct eap_sm *sm,
 +                                     struct eap_ttls_data *data,
 +                                     struct eap_method_ret *ret,
 +                                     struct eap_hdr *hdr, size_t len,
 +                                     struct wpabuf **resp)
 +{
 +      struct wpabuf msg;
 +      struct eap_method_ret iret;
 +
 +      os_memset(&iret, 0, sizeof(iret));
 +      wpabuf_set(&msg, hdr, len);
 +      *resp = data->phase2_method->process(sm, data->phase2_priv, &iret,
 +                                           &msg);
 +      if ((iret.methodState == METHOD_DONE ||
 +           iret.methodState == METHOD_MAY_CONT) &&
 +          (iret.decision == DECISION_UNCOND_SUCC ||
 +           iret.decision == DECISION_COND_SUCC ||
 +           iret.decision == DECISION_FAIL)) {
 +              ret->methodState = iret.methodState;
 +              ret->decision = iret.decision;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm,
 +                                            struct eap_ttls_data *data,
 +                                            struct eap_method_ret *ret,
 +                                            struct eap_hdr *hdr, size_t len,
 +                                            u8 method, struct wpabuf **resp)
 +{
 +#ifdef EAP_TNC
 +      if (data->tnc_started && data->phase2_method &&
 +          data->phase2_priv && method == EAP_TYPE_TNC &&
 +          data->phase2_eap_type.method == EAP_TYPE_TNC)
 +              return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len,
 +                                                 resp);
 +
 +      if (data->ready_for_tnc && !data->tnc_started &&
 +          method == EAP_TYPE_TNC) {
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed "
 +                         "EAP method");
 +              data->tnc_started = 1;
 +      }
 +
 +      if (data->tnc_started) {
 +              if (data->phase2_eap_type.vendor != EAP_VENDOR_IETF ||
 +                  data->phase2_eap_type.method == EAP_TYPE_TNC) {
 +                      wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected EAP "
 +                                 "type %d for TNC", method);
 +                      return -1;
 +              }
 +
 +              data->phase2_eap_type.vendor = EAP_VENDOR_IETF;
 +              data->phase2_eap_type.method = method;
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected "
 +                         "Phase 2 EAP vendor %d method %d (TNC)",
 +                         data->phase2_eap_type.vendor,
 +                         data->phase2_eap_type.method);
 +
 +              if (data->phase2_type == EAP_TTLS_PHASE2_EAP)
 +                      eap_ttls_phase2_eap_deinit(sm, data);
 +      }
 +#endif /* EAP_TNC */
 +
 +      if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF &&
 +          data->phase2_eap_type.method == EAP_TYPE_NONE)
 +              eap_ttls_phase2_select_eap_method(data, method);
 +
 +      if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE)
 +      {
 +              if (eap_peer_tls_phase2_nak(data->phase2_eap_types,
 +                                          data->num_phase2_eap_types,
 +                                          hdr, resp))
 +                      return -1;
 +              return 0;
 +      }
 +
 +      if (data->phase2_priv == NULL) {
 +              data->phase2_method = eap_peer_get_eap_method(
 +                      EAP_VENDOR_IETF, method);
 +              if (data->phase2_method) {
 +                      sm->init_phase2 = 1;
 +                      data->phase2_priv = data->phase2_method->init(sm);
 +                      sm->init_phase2 = 0;
 +              }
 +      }
 +      if (data->phase2_priv == NULL || data->phase2_method == NULL) {
 +              wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize "
 +                         "Phase 2 EAP method %d", method);
 +              return -1;
 +      }
 +
 +      return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, resp);
 +}
 +
 +
 +static int eap_ttls_phase2_request_eap(struct eap_sm *sm,
 +                                     struct eap_ttls_data *data,
 +                                     struct eap_method_ret *ret,
 +                                     struct eap_hdr *hdr,
 +                                     struct wpabuf **resp)
 +{
 +      size_t len = be_to_host16(hdr->length);
 +      u8 *pos;
 +      struct eap_peer_config *config = eap_get_config(sm);
 +
 +      if (len <= sizeof(struct eap_hdr)) {
 +              wpa_printf(MSG_INFO, "EAP-TTLS: too short "
 +                         "Phase 2 request (len=%lu)", (unsigned long) len);
 +              return -1;
 +      }
 +      pos = (u8 *) (hdr + 1);
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d", *pos);
 +      switch (*pos) {
 +      case EAP_TYPE_IDENTITY:
 +              *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
 +              break;
 +      default:
 +              if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len,
 +                                                     *pos, resp) < 0)
 +                      return -1;
 +              break;
 +      }
 +
 +      if (*resp == NULL &&
 +          (config->pending_req_identity || config->pending_req_password ||
 +           config->pending_req_otp)) {
 +              return 0;
 +      }
 +
 +      if (*resp == NULL)
 +              return -1;
 +
 +      wpa_hexdump_buf(MSG_DEBUG, "EAP-TTLS: AVP encapsulate EAP Response",
 +                      *resp);
 +      return eap_ttls_avp_encapsulate(resp, RADIUS_ATTR_EAP_MESSAGE, 1);
 +}
 +
 +
 +static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
 +                                          struct eap_ttls_data *data,
 +                                          struct eap_method_ret *ret,
 +                                          struct wpabuf **resp)
 +{
 +#ifdef CONFIG_FIPS
 +      wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPV2 not supported in FIPS build");
 +      return -1;
 +#else /* CONFIG_FIPS */
 +#ifdef EAP_MSCHAPv2
 +      struct wpabuf *msg;
 +      u8 *buf, *pos, *challenge, *peer_challenge;
 +      const u8 *identity, *password;
 +      size_t identity_len, password_len;
 +      int pwhash;
 +
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request");
 +
 +      identity = eap_get_config_identity(sm, &identity_len);
 +      password = eap_get_config_password2(sm, &password_len, &pwhash);
 +      if (identity == NULL || password == NULL)
 +              return -1;
 +
 +      msg = wpabuf_alloc(identity_len + 1000);
 +      if (msg == NULL) {
 +              wpa_printf(MSG_ERROR,
 +                         "EAP-TTLS/MSCHAPV2: Failed to allocate memory");
 +              return -1;
 +      }
 +      pos = buf = wpabuf_mhead(msg);
 +
 +      /* User-Name */
 +      pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
 +                             identity, identity_len);
 +
 +      /* MS-CHAP-Challenge */
 +      challenge = eap_ttls_implicit_challenge(
 +              sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1);
 +      if (challenge == NULL) {
 +              wpabuf_free(msg);
 +              wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
 +                         "implicit challenge");
 +              return -1;
 +      }
 +
 +      pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE,
 +                             RADIUS_VENDOR_ID_MICROSOFT, 1,
 +                             challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
 +
 +      /* MS-CHAP2-Response */
 +      pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_RESPONSE,
 +                             RADIUS_VENDOR_ID_MICROSOFT, 1,
 +                             EAP_TTLS_MSCHAPV2_RESPONSE_LEN);
 +      data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN];
 +      *pos++ = data->ident;
 +      *pos++ = 0; /* Flags */
 +      if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) {
 +              os_free(challenge);
 +              wpabuf_free(msg);
 +              wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get "
 +                         "random data for peer challenge");
 +              return -1;
 +      }
 +      peer_challenge = pos;
 +      pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN;
 +      os_memset(pos, 0, 8); /* Reserved, must be zero */
 +      pos += 8;
 +      if (mschapv2_derive_response(identity, identity_len, password,
 +                                   password_len, pwhash, challenge,
 +                                   peer_challenge, pos, data->auth_response,
 +                                   data->master_key)) {
 +              os_free(challenge);
 +              wpabuf_free(msg);
 +              wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
 +                         "response");
 +              return -1;
 +      }
 +      data->auth_response_valid = 1;
 +
 +      pos += 24;
 +      os_free(challenge);
 +      AVP_PAD(buf, pos);
 +
 +      wpabuf_put(msg, pos - buf);
 +      *resp = msg;
 +
 +      return 0;
 +#else /* EAP_MSCHAPv2 */
 +      wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
 +      return -1;
 +#endif /* EAP_MSCHAPv2 */
 +#endif /* CONFIG_FIPS */
 +}
 +
 +
 +static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
 +                                        struct eap_ttls_data *data,
 +                                        struct eap_method_ret *ret,
 +                                        struct wpabuf **resp)
 +{
 +#ifdef CONFIG_FIPS
 +      wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAP not supported in FIPS build");
 +      return -1;
 +#else /* CONFIG_FIPS */
 +      struct wpabuf *msg;
 +      u8 *buf, *pos, *challenge;
 +      const u8 *identity, *password;
 +      size_t identity_len, password_len;
 +      int pwhash;
 +
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request");
 +
 +      identity = eap_get_config_identity(sm, &identity_len);
 +      password = eap_get_config_password2(sm, &password_len, &pwhash);
 +      if (identity == NULL || password == NULL)
 +              return -1;
 +
 +      msg = wpabuf_alloc(identity_len + 1000);
 +      if (msg == NULL) {
 +              wpa_printf(MSG_ERROR,
 +                         "EAP-TTLS/MSCHAP: Failed to allocate memory");
 +              return -1;
 +      }
 +      pos = buf = wpabuf_mhead(msg);
 +
 +      /* User-Name */
 +      pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
 +                             identity, identity_len);
 +
 +      /* MS-CHAP-Challenge */
 +      challenge = eap_ttls_implicit_challenge(
 +              sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1);
 +      if (challenge == NULL) {
 +              wpabuf_free(msg);
 +              wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive "
 +                         "implicit challenge");
 +              return -1;
 +      }
 +
 +      pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE,
 +                             RADIUS_VENDOR_ID_MICROSOFT, 1,
 +                             challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN);
 +
 +      /* MS-CHAP-Response */
 +      pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE,
 +                             RADIUS_VENDOR_ID_MICROSOFT, 1,
 +                             EAP_TTLS_MSCHAP_RESPONSE_LEN);
 +      data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN];
 +      *pos++ = data->ident;
 +      *pos++ = 1; /* Flags: Use NT style passwords */
 +      os_memset(pos, 0, 24); /* LM-Response */
 +      pos += 24;
 +      if (pwhash) {
 +              challenge_response(challenge, password, pos); /* NT-Response */
 +              wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash",
 +                              password, 16);
 +      } else {
 +              nt_challenge_response(challenge, password, password_len,
 +                                    pos); /* NT-Response */
 +              wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password",
 +                                    password, password_len);
 +      }
 +      wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge",
 +                  challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN);
 +      wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24);
 +      pos += 24;
 +      os_free(challenge);
 +      AVP_PAD(buf, pos);
 +
 +      wpabuf_put(msg, pos - buf);
 +      *resp = msg;
 +
 +      /* EAP-TTLS/MSCHAP does not provide tunneled success
 +       * notification, so assume that Phase2 succeeds. */
 +      ret->methodState = METHOD_DONE;
 +      ret->decision = DECISION_COND_SUCC;
 +
 +      return 0;
 +#endif /* CONFIG_FIPS */
 +}
 +
 +
 +static int eap_ttls_phase2_request_pap(struct eap_sm *sm,
 +                                     struct eap_ttls_data *data,
 +                                     struct eap_method_ret *ret,
 +                                     struct wpabuf **resp)
 +{
 +      struct wpabuf *msg;
 +      u8 *buf, *pos;
 +      size_t pad;
 +      const u8 *identity, *password;
 +      size_t identity_len, password_len;
 +
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request");
 +
 +      identity = eap_get_config_identity(sm, &identity_len);
 +      password = eap_get_config_password(sm, &password_len);
 +      if (identity == NULL || password == NULL)
 +              return -1;
 +
 +      msg = wpabuf_alloc(identity_len + password_len + 100);
 +      if (msg == NULL) {
 +              wpa_printf(MSG_ERROR,
 +                         "EAP-TTLS/PAP: Failed to allocate memory");
 +              return -1;
 +      }
 +      pos = buf = wpabuf_mhead(msg);
 +
 +      /* User-Name */
 +      pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
 +                             identity, identity_len);
 +
 +      /* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts
 +       * the data, so no separate encryption is used in the AVP itself.
 +       * However, the password is padded to obfuscate its length. */
 +      pad = password_len == 0 ? 16 : (16 - (password_len & 15)) & 15;
 +      pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1,
 +                             password_len + pad);
 +      os_memcpy(pos, password, password_len);
 +      pos += password_len;
 +      os_memset(pos, 0, pad);
 +      pos += pad;
 +      AVP_PAD(buf, pos);
 +
 +      wpabuf_put(msg, pos - buf);
 +      *resp = msg;
 +
 +      /* EAP-TTLS/PAP does not provide tunneled success notification,
 +       * so assume that Phase2 succeeds. */
 +      ret->methodState = METHOD_DONE;
 +      ret->decision = DECISION_COND_SUCC;
 +
 +      return 0;
 +}
 +
 +
 +static int eap_ttls_phase2_request_chap(struct eap_sm *sm,
 +                                      struct eap_ttls_data *data,
 +                                      struct eap_method_ret *ret,
 +                                      struct wpabuf **resp)
 +{
 +#ifdef CONFIG_FIPS
 +      wpa_printf(MSG_ERROR, "EAP-TTLS: CHAP not supported in FIPS build");
 +      return -1;
 +#else /* CONFIG_FIPS */
 +      struct wpabuf *msg;
 +      u8 *buf, *pos, *challenge;
 +      const u8 *identity, *password;
 +      size_t identity_len, password_len;
 +
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request");
 +
 +      identity = eap_get_config_identity(sm, &identity_len);
 +      password = eap_get_config_password(sm, &password_len);
 +      if (identity == NULL || password == NULL)
 +              return -1;
 +
 +      msg = wpabuf_alloc(identity_len + 1000);
 +      if (msg == NULL) {
 +              wpa_printf(MSG_ERROR,
 +                         "EAP-TTLS/CHAP: Failed to allocate memory");
 +              return -1;
 +      }
 +      pos = buf = wpabuf_mhead(msg);
 +
 +      /* User-Name */
 +      pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
 +                             identity, identity_len);
 +
 +      /* CHAP-Challenge */
 +      challenge = eap_ttls_implicit_challenge(
 +              sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1);
 +      if (challenge == NULL) {
 +              wpabuf_free(msg);
 +              wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive "
 +                         "implicit challenge");
 +              return -1;
 +      }
 +
 +      pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1,
 +                             challenge, EAP_TTLS_CHAP_CHALLENGE_LEN);
 +
 +      /* CHAP-Password */
 +      pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1,
 +                             1 + EAP_TTLS_CHAP_PASSWORD_LEN);
 +      data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN];
 +      *pos++ = data->ident;
 +
 +      /* MD5(Ident + Password + Challenge) */
 +      chap_md5(data->ident, password, password_len, challenge,
 +               EAP_TTLS_CHAP_CHALLENGE_LEN, pos);
 +
 +      wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username",
 +                        identity, identity_len);
 +      wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password",
 +                            password, password_len);
 +      wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge",
 +                  challenge, EAP_TTLS_CHAP_CHALLENGE_LEN);
 +      wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password",
 +                  pos, EAP_TTLS_CHAP_PASSWORD_LEN);
 +      pos += EAP_TTLS_CHAP_PASSWORD_LEN;
 +      os_free(challenge);
 +      AVP_PAD(buf, pos);
 +
 +      wpabuf_put(msg, pos - buf);
 +      *resp = msg;
 +
 +      /* EAP-TTLS/CHAP does not provide tunneled success
 +       * notification, so assume that Phase2 succeeds. */
 +      ret->methodState = METHOD_DONE;
 +      ret->decision = DECISION_COND_SUCC;
 +
 +      return 0;
 +#endif /* CONFIG_FIPS */
 +}
 +
 +
 +static int eap_ttls_phase2_request(struct eap_sm *sm,
 +                                 struct eap_ttls_data *data,
 +                                 struct eap_method_ret *ret,
 +                                 struct eap_hdr *hdr,
 +                                 struct wpabuf **resp)
 +{
 +      int res = 0;
 +      size_t len;
 +      enum phase2_types phase2_type = data->phase2_type;
 +
 +#ifdef EAP_TNC
 +      if (data->tnc_started) {
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: Processing TNC");
 +              phase2_type = EAP_TTLS_PHASE2_EAP;
 +      }
 +#endif /* EAP_TNC */
 +
 +      if (phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 ||
 +          phase2_type == EAP_TTLS_PHASE2_MSCHAP ||
 +          phase2_type == EAP_TTLS_PHASE2_PAP ||
 +          phase2_type == EAP_TTLS_PHASE2_CHAP) {
 +              if (eap_get_config_identity(sm, &len) == NULL) {
 +                      wpa_printf(MSG_INFO,
 +                                 "EAP-TTLS: Identity not configured");
 +                      eap_sm_request_identity(sm);
 +                      if (eap_get_config_password(sm, &len) == NULL)
 +                              eap_sm_request_password(sm);
 +                      return 0;
 +              }
 +
 +              if (eap_get_config_password(sm, &len) == NULL) {
 +                      wpa_printf(MSG_INFO,
 +                                 "EAP-TTLS: Password not configured");
 +                      eap_sm_request_password(sm);
 +                      return 0;
 +              }
 +      }
 +
 +      switch (phase2_type) {
 +      case EAP_TTLS_PHASE2_EAP:
 +              res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp);
 +              break;
 +      case EAP_TTLS_PHASE2_MSCHAPV2:
 +              res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp);
 +              break;
 +      case EAP_TTLS_PHASE2_MSCHAP:
 +              res = eap_ttls_phase2_request_mschap(sm, data, ret, resp);
 +              break;
 +      case EAP_TTLS_PHASE2_PAP:
 +              res = eap_ttls_phase2_request_pap(sm, data, ret, resp);
 +              break;
 +      case EAP_TTLS_PHASE2_CHAP:
 +              res = eap_ttls_phase2_request_chap(sm, data, ret, resp);
 +              break;
 +      default:
 +              wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown");
 +              res = -1;
 +              break;
 +      }
 +
 +      if (res < 0) {
 +              ret->methodState = METHOD_DONE;
 +              ret->decision = DECISION_FAIL;
 +      }
 +
 +      return res;
 +}
 +
 +
 +struct ttls_parse_avp {
 +      u8 *mschapv2;
 +      u8 *eapdata;
 +      size_t eap_len;
 +      u8 *chbind_data;
 +      size_t chbind_len;
 +      int mschapv2_error;
 +};
 +
 +
 +static int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen,
 +                                 struct ttls_parse_avp *parse)
 +{
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message");
 +      if (parse->eapdata == NULL) {
 +              parse->eapdata = os_malloc(dlen);
 +              if (parse->eapdata == NULL) {
 +                      wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate "
 +                                 "memory for Phase 2 EAP data");
 +                      return -1;
 +              }
 +              os_memcpy(parse->eapdata, dpos, dlen);
 +              parse->eap_len = dlen;
 +      } else {
 +              u8 *neweap = os_realloc(parse->eapdata, parse->eap_len + dlen);
 +              if (neweap == NULL) {
 +                      wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate "
 +                                 "memory for Phase 2 EAP data");
 +                      return -1;
 +              }
 +              os_memcpy(neweap + parse->eap_len, dpos, dlen);
 +              parse->eapdata = neweap;
 +              parse->eap_len += dlen;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +static int eap_ttls_parse_attr_chbind(const u8 *dpos, size_t dlen,
 +                                 struct ttls_parse_avp *parse)
 +{
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - Channel Binding Message");
 +
 +      if (parse->chbind_data == NULL) {
 +              parse->chbind_data = os_malloc(dlen);
 +              if (parse->chbind_data == NULL) {
 +                      wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate "
 +                                 "memory for Phase 2 channel binding data");
 +                      return -1;
 +              }
 +              os_memcpy(parse->chbind_data, dpos, dlen);
 +              parse->chbind_len = dlen;
 +      } else {
 +        /* TODO: can this really happen?  maybe just make this an error? */
 +              u8 *newchbind = os_realloc(parse->chbind_data,
 +                                         parse->chbind_len + dlen);
 +              if (newchbind == NULL) {
 +                      wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate "
 +                                 "memory for Phase 2 channel binding data");
 +                      return -1;
 +              }
 +              os_memcpy(newchbind + parse->chbind_len, dpos, dlen);
 +              parse->chbind_data = newchbind;
 +              parse->chbind_len += dlen;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +static int eap_ttls_parse_avp(u8 *pos, size_t left,
 +                            struct ttls_parse_avp *parse)
 +{
 +      struct ttls_avp *avp;
 +      u32 avp_code, avp_length, vendor_id = 0;
 +      u8 avp_flags, *dpos;
 +      size_t dlen;
 +
 +      avp = (struct ttls_avp *) pos;
 +      avp_code = be_to_host32(avp->avp_code);
 +      avp_length = be_to_host32(avp->avp_length);
 +      avp_flags = (avp_length >> 24) & 0xff;
 +      avp_length &= 0xffffff;
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x "
 +                 "length=%d", (int) avp_code, avp_flags,
 +                 (int) avp_length);
 +
 +      if (avp_length > left) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow "
 +                         "(len=%d, left=%lu) - dropped",
 +                         (int) avp_length, (unsigned long) left);
 +              return -1;
 +      }
 +
 +      if (avp_length < sizeof(*avp)) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length %d",
 +                         avp_length);
 +              return -1;
 +      }
 +
 +      dpos = (u8 *) (avp + 1);
 +      dlen = avp_length - sizeof(*avp);
 +      if (avp_flags & AVP_FLAGS_VENDOR) {
 +              if (dlen < 4) {
 +                      wpa_printf(MSG_WARNING, "EAP-TTLS: Vendor AVP "
 +                                 "underflow");
 +                      return -1;
 +              }
 +              vendor_id = WPA_GET_BE32(dpos);
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d",
 +                         (int) vendor_id);
 +              dpos += 4;
 +              dlen -= 4;
 +      }
 +
 +      wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen);
 +
 +      if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) {
 +              if (eap_ttls_parse_attr_eap(dpos, dlen, parse) < 0)
 +                      return -1;
 +      } else if (vendor_id == RADIUS_VENDOR_ID_UKERNA &&
 +                 avp_code == RADIUS_ATTR_UKERNA_CHBIND) {
 +              /* message containing channel binding data */
 +              if (eap_ttls_parse_attr_chbind(dpos, dlen, parse) < 0)
 +                      return -1;
 +      } else if (vendor_id == 0 && avp_code == RADIUS_ATTR_REPLY_MESSAGE) {
 +              /* This is an optional message that can be displayed to
 +               * the user. */
 +              wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: AVP - Reply-Message",
 +                                dpos, dlen);
 +      } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
 +                 avp_code == RADIUS_ATTR_MS_CHAP2_SUCCESS) {
 +              wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP2-Success",
 +                                dpos, dlen);
 +              if (dlen != 43) {
 +                      wpa_printf(MSG_WARNING, "EAP-TTLS: Unexpected "
 +                                 "MS-CHAP2-Success length "
 +                                 "(len=%lu, expected 43)",
 +                                 (unsigned long) dlen);
 +                      return -1;
 +              }
 +              parse->mschapv2 = dpos;
 +      } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
 +                 avp_code == RADIUS_ATTR_MS_CHAP_ERROR) {
 +              wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP-Error",
 +                                dpos, dlen);
 +              parse->mschapv2_error = 1;
 +      } else if (avp_flags & AVP_FLAGS_MANDATORY) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported mandatory AVP "
 +                         "code %d vendor_id %d - dropped",
 +                         (int) avp_code, (int) vendor_id);
 +              return -1;
 +      } else {
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported AVP "
 +                         "code %d vendor_id %d",
 +                         (int) avp_code, (int) vendor_id);
 +      }
 +
 +      return avp_length;
 +}
 +
 +
 +static int eap_ttls_parse_avps(struct wpabuf *in_decrypted,
 +                             struct ttls_parse_avp *parse)
 +{
 +      u8 *pos;
 +      size_t left, pad;
 +      int avp_length;
 +
 +      pos = wpabuf_mhead(in_decrypted);
 +      left = wpabuf_len(in_decrypted);
 +      wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 AVPs", pos, left);
 +      if (left < sizeof(struct ttls_avp)) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 AVP frame"
 +                         " len=%lu expected %lu or more - dropped",
 +                         (unsigned long) left,
 +                         (unsigned long) sizeof(struct ttls_avp));
 +              return -1;
 +      }
 +
 +      /* Parse AVPs */
 +      os_memset(parse, 0, sizeof(*parse));
 +
 +      while (left > 0) {
 +              avp_length = eap_ttls_parse_avp(pos, left, parse);
 +              if (avp_length < 0)
 +                      return -1;
 +
 +              pad = (4 - (avp_length & 3)) & 3;
 +              pos += avp_length + pad;
 +              if (left < avp_length + pad)
 +                      left = 0;
 +              else
 +                      left -= avp_length + pad;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +static u8 * eap_ttls_fake_identity_request(void)
 +{
 +      struct eap_hdr *hdr;
 +      u8 *buf;
 +
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: empty data in beginning of "
 +                 "Phase 2 - use fake EAP-Request Identity");
 +      buf = os_malloc(sizeof(*hdr) + 1);
 +      if (buf == NULL) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate "
 +                         "memory for fake EAP-Identity Request");
 +              return NULL;
 +      }
 +
 +      hdr = (struct eap_hdr *) buf;
 +      hdr->code = EAP_CODE_REQUEST;
 +      hdr->identifier = 0;
 +      hdr->length = host_to_be16(sizeof(*hdr) + 1);
 +      buf[sizeof(*hdr)] = EAP_TYPE_IDENTITY;
 +
 +      return buf;
 +}
 +
 +
 +static int eap_ttls_encrypt_response(struct eap_sm *sm,
 +                                   struct eap_ttls_data *data,
 +                                   struct wpabuf *resp, u8 identifier,
 +                                   struct wpabuf **out_data)
 +{
 +      if (resp == NULL)
 +              return 0;
 +
 +      wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Encrypting Phase 2 data",
 +                          resp);
 +      if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS,
 +                               data->ttls_version, identifier,
 +                               resp, out_data)) {
 +              wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 "
 +                         "frame");
 +              wpabuf_free(resp);
 +              return -1;
 +      }
 +      wpabuf_free(resp);
 +
 +      return 0;
 +}
 +
 +static int eap_ttls_add_chbind_request(struct eap_sm *sm,
 +                                     struct eap_ttls_data *data,
 +                                     struct wpabuf **resp)
 +{
 +      struct wpabuf *chbind_req, *res;
 +      int length = 1, i;
 +      struct eap_peer_config *config = eap_get_config(sm);
 +
 +      if (!config->chbind_config || config->chbind_config_len <= 0)
 +              return -1;
 +
 +      for (i=0; i<config->chbind_config_len; i++) {
 +              length += 3 + config->chbind_config[i].req_data_len;
 +      }
 +
 +      chbind_req = wpabuf_alloc(length);
 +      if (!chbind_req)
 +              return -1;
 +
 +      wpabuf_put_u8(chbind_req, CHBIND_CODE_REQUEST);
 +      for (i=0; i<config->chbind_config_len; i++) {
 +              struct eap_peer_chbind_config *chbind_config =
 +                      &config->chbind_config[i];
 +              wpabuf_put_be16(chbind_req, chbind_config->req_data_len);
 +              wpabuf_put_u8(chbind_req, chbind_config->nsid);
 +              wpabuf_put_data(chbind_req, chbind_config->req_data,
 +                              chbind_config->req_data_len);
 +      }
 +      if (eap_ttls_avp_radius_vsa_encapsulate(&chbind_req,
 +                                       RADIUS_VENDOR_ID_UKERNA,
 +                                       RADIUS_ATTR_UKERNA_CHBIND, 0) < 0)
 +              return -1;
 +
 +      /* bleh. This will free *resp regardless of whether combined buffer
 +         alloc succeeds, which is not consistent with the other error
 +         condition behavior in this function */
 +      *resp = wpabuf_concat(chbind_req, *resp);
 +
 +      return (*resp) ? 0 : -1;
 +}
 +
 +
 +static int eap_ttls_process_chbind(struct eap_sm *sm,
 +                                 struct eap_ttls_data *data,
 +                                 struct eap_method_ret *ret,
 +                                 struct ttls_parse_avp *parse,
 +                                 struct wpabuf **resp)
 +{
 +      size_t pos=0;
 +      u8 code;
 +      u16 len;
 +      struct chbind_hdr *hdr;
 +      struct eap_peer_config *config = eap_get_config(sm);
 +      int i, found;
 +
 +
 +      if (parse->chbind_data == NULL) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: No channel binding message "
 +                         "in the packet - dropped");
 +              return -1;
 +      }
 +      if (parse->chbind_len < 1 ) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: bad channel binding response "
 +                         "frame (len=%lu, expected %lu or more) - dropped",
 +                         (unsigned long) parse->chbind_len,
 +                         (unsigned long) 1);
 +              return -1;
 +      }
 +      code = parse->chbind_data[pos++];
 +      for (i=0; i<config->chbind_config_len; i++) {
 +              struct eap_peer_chbind_config *chbind_config =
 +                      &config->chbind_config[i];
 +              pos = 1;
 +              found = 0;
 +              while (pos+sizeof(*hdr) < parse->chbind_len) {
 +                      hdr = (struct chbind_hdr *)(&parse->chbind_data[pos]);
 +                      pos += sizeof(*hdr);
 +                      len = be_to_host16(hdr->len);
 +                      if (pos + len <= parse->chbind_len) {
 +                              if (chbind_config->nsid == hdr->nsid)
 +                                      chbind_config->response_cb(
 +                                                                 chbind_config->ctx,
 +                                                                 code, hdr->nsid,
 +                                                                 &parse->chbind_data[pos], len);
 +                              found  = 1;
 +                      }
 +                      pos += len;
 +              }
 +              if (pos != parse->chbind_len) {
 +                      wpa_printf(MSG_WARNING, "EAP-TTLS: bad channel binding response "
 +                                 "frame (parsed len=%lu, expected %lu) - dropped",
 +                                 (unsigned long) pos,
 +                                 (unsigned long) parse->chbind_len);
 +                      return -1;
 +              }
 +              if (!found) {
 +                      chbind_config->response_cb(
 +                                                 chbind_config->ctx,
 +                                                 code, chbind_config->nsid,
 +                                                 NULL, 0);
 +              }
 +
 +      }
 +      return 0;
 +}
 +
 +static int eap_ttls_process_phase2_eap(struct eap_sm *sm,
 +                                     struct eap_ttls_data *data,
 +                                     struct eap_method_ret *ret,
 +                                     struct ttls_parse_avp *parse,
 +                                     struct wpabuf **resp)
 +{
 +      struct eap_hdr *hdr;
 +      size_t len;
 +
 +      if (parse->eapdata == NULL) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: No EAP Message in the "
 +                         "packet - dropped");
 +              return -1;
 +      }
 +
 +      wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP",
 +                  parse->eapdata, parse->eap_len);
 +      hdr = (struct eap_hdr *) parse->eapdata;
 +
 +      if (parse->eap_len < sizeof(*hdr)) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 EAP "
 +                         "frame (len=%lu, expected %lu or more) - dropped",
 +                         (unsigned long) parse->eap_len,
 +                         (unsigned long) sizeof(*hdr));
 +              return -1;
 +      }
 +      len = be_to_host16(hdr->length);
 +      if (len > parse->eap_len) {
 +              wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in Phase 2 "
 +                         "EAP frame (EAP hdr len=%lu, EAP data len in "
 +                         "AVP=%lu)",
 +                         (unsigned long) len,
 +                         (unsigned long) parse->eap_len);
 +              return -1;
 +      }
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d "
 +                 "identifier=%d length=%lu",
 +                 hdr->code, hdr->identifier, (unsigned long) len);
 +      switch (hdr->code) {
 +      case EAP_CODE_REQUEST:
 +              if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) {
 +                      wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request "
 +                                 "processing failed");
 +                      return -1;
 +              }
 +              break;
 +      default:
 +              wpa_printf(MSG_INFO, "EAP-TTLS: Unexpected code=%d in "
 +                         "Phase 2 EAP header", hdr->code);
 +              return -1;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
 +                                          struct eap_ttls_data *data,
 +                                          struct eap_method_ret *ret,
 +                                          struct ttls_parse_avp *parse)
 +{
 +#ifdef EAP_MSCHAPv2
 +      if (parse->mschapv2_error) {
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received "
 +                         "MS-CHAP-Error - failed");
 +              ret->methodState = METHOD_DONE;
 +              ret->decision = DECISION_FAIL;
 +              /* Reply with empty data to ACK error */
 +              return 1;
 +      }
 +
 +      if (parse->mschapv2 == NULL) {
 +#ifdef EAP_TNC
 +              if (data->phase2_success && parse->eapdata) {
 +                      /*
 +                       * Allow EAP-TNC to be started after successfully
 +                       * completed MSCHAPV2.
 +                       */
 +                      return 1;
 +              }
 +#endif /* EAP_TNC */
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success AVP "
 +                         "received for Phase2 MSCHAPV2");
 +              return -1;
 +      }
 +      if (parse->mschapv2[0] != data->ident) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: Ident mismatch for Phase 2 "
 +                         "MSCHAPV2 (received Ident 0x%02x, expected 0x%02x)",
 +                         parse->mschapv2[0], data->ident);
 +              return -1;
 +      }
 +      if (!data->auth_response_valid ||
 +          mschapv2_verify_auth_response(data->auth_response,
 +                                        parse->mschapv2 + 1, 42)) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid authenticator "
 +                         "response in Phase 2 MSCHAPV2 success request");
 +              return -1;
 +      }
 +
 +      wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 "
 +                 "authentication succeeded");
 +      ret->methodState = METHOD_DONE;
 +      ret->decision = DECISION_UNCOND_SUCC;
 +      data->phase2_success = 1;
 +
 +      /*
 +       * Reply with empty data; authentication server will reply
 +       * with EAP-Success after this.
 +       */
 +      return 1;
 +#else /* EAP_MSCHAPv2 */
 +      wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
 +      return -1;
 +#endif /* EAP_MSCHAPv2 */
 +}
 +
 +
 +#ifdef EAP_TNC
 +static int eap_ttls_process_tnc_start(struct eap_sm *sm,
 +                                    struct eap_ttls_data *data,
 +                                    struct eap_method_ret *ret,
 +                                    struct ttls_parse_avp *parse,
 +                                    struct wpabuf **resp)
 +{
 +      /* TNC uses inner EAP method after non-EAP TTLS phase 2. */
 +      if (parse->eapdata == NULL) {
 +              wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received "
 +                         "unexpected tunneled data (no EAP)");
 +              return -1;
 +      }
 +
 +      if (!data->ready_for_tnc) {
 +              wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received "
 +                         "EAP after non-EAP, but not ready for TNC");
 +              return -1;
 +      }
 +
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed "
 +                 "non-EAP method");
 +      data->tnc_started = 1;
 +
 +      if (eap_ttls_process_phase2_eap(sm, data, ret, parse, resp) < 0)
 +              return -1;
 +
 +      return 0;
 +}
 +#endif /* EAP_TNC */
 +
 +
 +static int eap_ttls_process_decrypted(struct eap_sm *sm,
 +                                    struct eap_ttls_data *data,
 +                                    struct eap_method_ret *ret,
 +                                    u8 identifier,
 +                                    struct ttls_parse_avp *parse,
 +                                    struct wpabuf *in_decrypted,
 +                                    struct wpabuf **out_data)
 +{
 +      struct wpabuf *resp = NULL;
 +      struct eap_peer_config *config = eap_get_config(sm);
 +      int res;
 +      enum phase2_types phase2_type = data->phase2_type;
 +
 +#ifdef EAP_TNC
 +      if (data->tnc_started)
 +              phase2_type = EAP_TTLS_PHASE2_EAP;
 +#endif /* EAP_TNC */
 +
 +      /* handle channel binding response here */
 +      if (parse->chbind_data) {
 +              /* received channel binding repsonse */
 +              if (eap_ttls_process_chbind(sm, data, ret, parse, &resp) < 0)
 +                      return -1;
 +              if (data->done_butfor_cb) {
 +                      ret->methodState = METHOD_DONE;
 +                      ret->decision = data->cbDecision;
 +                      data->phase2_success = 1;
 +                      return 1; /*request ack*/
 +              }
 +      }
 +
 +      switch (phase2_type) {
 +      case EAP_TTLS_PHASE2_EAP:
 +              if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) <
 +                  0)
 +                      return -1;
 +              break;
 +      case EAP_TTLS_PHASE2_MSCHAPV2:
 +              res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse);
 +#ifdef EAP_TNC
 +              if (res == 1 && parse->eapdata && data->phase2_success) {
 +                      /*
 +                       * TNC may be required as the next
 +                       * authentication method within the tunnel.
 +                       */
 +                      ret->methodState = METHOD_MAY_CONT;
 +                      data->ready_for_tnc = 1;
 +                      if (eap_ttls_process_tnc_start(sm, data, ret, parse,
 +                                                     &resp) == 0)
 +                              break;
 +              }
 +#endif /* EAP_TNC */
 +              return res;
 +      case EAP_TTLS_PHASE2_MSCHAP:
 +      case EAP_TTLS_PHASE2_PAP:
 +      case EAP_TTLS_PHASE2_CHAP:
 +#ifdef EAP_TNC
 +              if (eap_ttls_process_tnc_start(sm, data, ret, parse, &resp) <
 +                  0)
 +                      return -1;
 +              break;
 +#else /* EAP_TNC */
 +              /* EAP-TTLS/{MSCHAP,PAP,CHAP} should not send any TLS tunneled
 +               * requests to the supplicant */
 +              wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received unexpected "
 +                         "tunneled data");
 +              return -1;
 +#endif /* EAP_TNC */
 +      }
 +
 +      if (!resp && (config->pending_req_identity ||
 +                      config->pending_req_password ||
 +                      config->pending_req_otp ||
 +                      config->pending_req_new_password)) {
 +              wpabuf_free(data->pending_phase2_req);
 +              data->pending_phase2_req = wpabuf_dup(in_decrypted);
 +              return 0;
 +      }
 +
 +      /* issue channel binding request when appropriate */
 +      if (config->chbind_config && config->chbind_config_len > 0 &&
 +              !data->chbind_req_sent) {
 +              if (eap_ttls_add_chbind_request(sm, data, &resp) < 0)
 +                      return -1;
 +              data->chbind_req_sent = 1;
 +              if (ret->methodState == METHOD_DONE) {
 +                      data->done_butfor_cb = 1;
 +                      data->cbDecision = ret->decision;
 +                      ret->methodState = METHOD_MAY_CONT;
 +              }
 +      }
 +
 +      if (resp) {
 +              if (eap_ttls_encrypt_response(sm, data, resp, identifier,
 +                                            out_data) < 0)
 +                      return -1;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +static int eap_ttls_implicit_identity_request(struct eap_sm *sm,
 +                                            struct eap_ttls_data *data,
 +                                            struct eap_method_ret *ret,
 +                                            u8 identifier,
 +                                            struct wpabuf **out_data)
 +{
 +      int retval = 0;
 +      struct eap_hdr *hdr;
 +      struct wpabuf *resp;
 +
 +      hdr = (struct eap_hdr *) eap_ttls_fake_identity_request();
 +      if (hdr == NULL) {
 +              ret->methodState = METHOD_DONE;
 +              ret->decision = DECISION_FAIL;
 +              return -1;
 +      }
 +
 +      resp = NULL;
 +      if (eap_ttls_phase2_request(sm, data, ret, hdr, &resp)) {
 +              wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request "
 +                         "processing failed");
 +              retval = -1;
 +      } else {
 +              struct eap_peer_config *config = eap_get_config(sm);
 +              if (resp == NULL &&
 +                  (config->pending_req_identity ||
 +                   config->pending_req_password ||
 +                   config->pending_req_otp ||
 +                   config->pending_req_new_password)) {
 +                      /*
 +                       * Use empty buffer to force implicit request
 +                       * processing when EAP request is re-processed after
 +                       * user input.
 +                       */
 +                      wpabuf_free(data->pending_phase2_req);
 +                      data->pending_phase2_req = wpabuf_alloc(0);
 +              }
 +
 +              retval = eap_ttls_encrypt_response(sm, data, resp, identifier,
 +                                                 out_data);
 +      }
 +
 +      os_free(hdr);
 +
 +      if (retval < 0) {
 +              ret->methodState = METHOD_DONE;
 +              ret->decision = DECISION_FAIL;
 +      }
 +
 +      return retval;
 +}
 +
 +
 +static int eap_ttls_phase2_start(struct eap_sm *sm, struct eap_ttls_data *data,
 +                               struct eap_method_ret *ret, u8 identifier,
 +                               struct wpabuf **out_data)
 +{
 +      data->phase2_start = 0;
 +
 +      /*
 +       * EAP-TTLS does not use Phase2 on fast re-auth; this must be done only
 +       * if TLS part was indeed resuming a previous session. Most
 +       * Authentication Servers terminate EAP-TTLS before reaching this
 +       * point, but some do not. Make wpa_supplicant stop phase 2 here, if
 +       * needed.
 +       */
 +      if (data->reauth &&
 +          tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: Session resumption - "
 +                         "skip phase 2");
 +              *out_data = eap_peer_tls_build_ack(identifier, EAP_TYPE_TTLS,
 +                                                 data->ttls_version);
 +              ret->methodState = METHOD_DONE;
 +              ret->decision = DECISION_UNCOND_SUCC;
 +              data->phase2_success = 1;
 +              return 0;
 +      }
 +
 +      return eap_ttls_implicit_identity_request(sm, data, ret, identifier,
 +                                                out_data);
 +}
 +
 +
 +static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
 +                          struct eap_method_ret *ret, u8 identifier,
 +                          const struct wpabuf *in_data,
 +                          struct wpabuf **out_data)
 +{
 +      struct wpabuf *in_decrypted = NULL;
 +      int retval = 0;
 +      struct ttls_parse_avp parse;
 +
 +      os_memset(&parse, 0, sizeof(parse));
 +
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for"
 +                 " Phase 2",
 +                 in_data ? (unsigned long) wpabuf_len(in_data) : 0);
 +
 +      if (data->pending_phase2_req) {
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 request - "
 +                         "skip decryption and use old data");
 +              /* Clear TLS reassembly state. */
 +              eap_peer_tls_reset_input(&data->ssl);
 +
 +              in_decrypted = data->pending_phase2_req;
 +              data->pending_phase2_req = NULL;
 +              if (wpabuf_len(in_decrypted) == 0) {
 +                      wpabuf_free(in_decrypted);
 +                      return eap_ttls_implicit_identity_request(
 +                              sm, data, ret, identifier, out_data);
 +              }
 +              goto continue_req;
 +      }
 +
 +      if ((in_data == NULL || wpabuf_len(in_data) == 0) &&
 +          data->phase2_start) {
 +              return eap_ttls_phase2_start(sm, data, ret, identifier,
 +                                           out_data);
 +      }
 +
 +      if (in_data == NULL || wpabuf_len(in_data) == 0) {
 +              /* Received TLS ACK - requesting more fragments */
 +              return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS,
 +                                          data->ttls_version,
 +                                          identifier, NULL, out_data);
 +      }
 +
 +      retval = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
 +      if (retval)
 +              goto done;
 +
 +continue_req:
 +      data->phase2_start = 0;
 +
 +      if (eap_ttls_parse_avps(in_decrypted, &parse) < 0) {
 +              retval = -1;
 +              goto done;
 +      }
 +
 +      retval = eap_ttls_process_decrypted(sm, data, ret, identifier,
 +                                          &parse, in_decrypted, out_data);
 +
 +done:
 +      wpabuf_free(in_decrypted);
 +      os_free(parse.eapdata);
 +
 +      if (retval < 0) {
 +              ret->methodState = METHOD_DONE;
 +              ret->decision = DECISION_FAIL;
 +      }
 +
 +      return retval;
 +}
 +
 +
 +static int eap_ttls_process_handshake(struct eap_sm *sm,
 +                                    struct eap_ttls_data *data,
 +                                    struct eap_method_ret *ret,
 +                                    u8 identifier,
 +                                    const struct wpabuf *in_data,
 +                                    struct wpabuf **out_data)
 +{
 +      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);
 +      if (res < 0) {
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS processing failed");
 +              ret->methodState = METHOD_DONE;
 +              ret->decision = DECISION_FAIL;
 +              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");
 +              if (data->resuming) {
 +                      wpa_printf(MSG_DEBUG, "EAP-TTLS: fast reauth - may "
 +                                 "skip Phase 2");
 +                      ret->decision = DECISION_COND_SUCC;
 +                      ret->methodState = METHOD_MAY_CONT;
 +              }
 +              data->phase2_start = 1;
 +              eap_ttls_v0_derive_key(sm, data);
 +
 +              if (*out_data == NULL || wpabuf_len(*out_data) == 0) {
 +                      if (eap_ttls_decrypt(sm, data, ret, identifier,
 +                                           NULL, out_data)) {
 +                              wpa_printf(MSG_WARNING, "EAP-TTLS: "
 +                                         "failed to process early "
 +                                         "start for Phase 2");
 +                      }
 +                      res = 0;
 +              }
 +              data->resuming = 0;
 +      }
 +
 +      if (res == 2) {
 +              /*
 +               * Application data included in the handshake message.
 +               */
 +              wpabuf_free(data->pending_phase2_req);
 +              data->pending_phase2_req = *out_data;
 +              *out_data = NULL;
 +              res = eap_ttls_decrypt(sm, data, ret, identifier, in_data,
 +                                     out_data);
 +      }
 +
 +      return res;
 +}
 +
 +
 +static void eap_ttls_check_auth_status(struct eap_sm *sm, 
 +                                     struct eap_ttls_data *data,
 +                                     struct eap_method_ret *ret)
 +{
 +      if (ret->methodState == METHOD_DONE) {
 +              ret->allowNotifications = FALSE;
 +              if (ret->decision == DECISION_UNCOND_SUCC ||
 +                  ret->decision == DECISION_COND_SUCC) {
 +                      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) {
 +                              /*
 +                               * TNC may be required as the next
 +                               * authentication method within the tunnel.
 +                               */
 +                              ret->methodState = METHOD_MAY_CONT;
 +                              data->ready_for_tnc = 1;
 +                      }
 +#endif /* EAP_TNC */
 +              }
 +      } else if (ret->methodState == METHOD_MAY_CONT &&
 +                 (ret->decision == DECISION_UNCOND_SUCC ||
 +                  ret->decision == DECISION_COND_SUCC)) {
 +                      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;
 +      }
 +}
 +
 +
 +static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv,
 +                                      struct eap_method_ret *ret,
 +                                      const struct wpabuf *reqData)
 +{
 +      size_t left;
 +      int res;
 +      u8 flags, id;
 +      struct wpabuf *resp;
 +      const u8 *pos;
 +      struct eap_ttls_data *data = priv;
 +      struct wpabuf msg;
 +
 +      pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret,
 +                                      reqData, &left, &flags);
 +      if (pos == NULL)
 +              return NULL;
 +      id = eap_get_id(reqData);
 +
 +      if (flags & EAP_TLS_FLAGS_START) {
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own "
 +                         "ver=%d)", flags & EAP_TLS_VERSION_MASK,
 +                         data->ttls_version);
 +
 +              /* RFC 5281, Ch. 9.2:
 +               * "This packet MAY contain additional information in the form
 +               * of AVPs, which may provide useful hints to the client"
 +               * For now, ignore any potential extra data.
 +               */
 +              left = 0;
 +      }
 +
 +      wpabuf_set(&msg, pos, left);
 +
 +      resp = NULL;
 +      if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
 +          !data->resuming) {
 +              res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp);
 +      } else {
 +              res = eap_ttls_process_handshake(sm, data, ret, id,
 +                                               &msg, &resp);
 +      }
 +
 +      eap_ttls_check_auth_status(sm, data, ret);
 +
 +      /* FIX: what about res == -1? Could just move all error processing into
 +       * the other functions and get rid of this res==1 case here. */
 +      if (res == 1) {
 +              wpabuf_free(resp);
 +              return eap_peer_tls_build_ack(id, EAP_TYPE_TTLS,
 +                                            data->ttls_version);
 +      }
 +      return resp;
 +}
 +
 +
 +static Boolean eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv)
 +{
 +      struct eap_ttls_data *data = priv;
 +      return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
 +              data->phase2_success;
 +}
 +
 +
 +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;
 +#endif /* EAP_TNC */
 +}
 +
 +
 +static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv)
 +{
 +      struct eap_ttls_data *data = priv;
 +      eap_ttls_free_key(data);
 +      os_free(data->session_id);
 +      data->session_id = NULL;
 +      if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
 +              os_free(data);
 +              return NULL;
 +      }
 +      if (data->phase2_priv && data->phase2_method &&
 +          data->phase2_method->init_for_reauth)
 +              data->phase2_method->init_for_reauth(sm, data->phase2_priv);
 +      data->phase2_start = 0;
 +      data->phase2_success = 0;
 +      data->resuming = 1;
 +      data->reauth = 1;
 +      return priv;
 +}
 +
 +
 +static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf,
 +                             size_t buflen, int verbose)
 +{
 +      struct eap_ttls_data *data = priv;
 +      int len, ret;
 +
 +      len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
 +      ret = os_snprintf(buf + len, buflen - len,
 +                        "EAP-TTLSv%d Phase2 method=",
 +                        data->ttls_version);
 +      if (os_snprintf_error(buflen - len, ret))
 +              return len;
 +      len += ret;
 +      switch (data->phase2_type) {
 +      case EAP_TTLS_PHASE2_EAP:
 +              ret = os_snprintf(buf + len, buflen - len, "EAP-%s\n",
 +                                data->phase2_method ?
 +                                data->phase2_method->name : "?");
 +              break;
 +      case EAP_TTLS_PHASE2_MSCHAPV2:
 +              ret = os_snprintf(buf + len, buflen - len, "MSCHAPV2\n");
 +              break;
 +      case EAP_TTLS_PHASE2_MSCHAP:
 +              ret = os_snprintf(buf + len, buflen - len, "MSCHAP\n");
 +              break;
 +      case EAP_TTLS_PHASE2_PAP:
 +              ret = os_snprintf(buf + len, buflen - len, "PAP\n");
 +              break;
 +      case EAP_TTLS_PHASE2_CHAP:
 +              ret = os_snprintf(buf + len, buflen - len, "CHAP\n");
 +              break;
 +      default:
 +              ret = 0;
 +              break;
 +      }
 +      if (os_snprintf_error(buflen - len, ret))
 +              return len;
 +      len += ret;
 +
 +      return len;
 +}
 +
 +
 +static Boolean eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv)
 +{
 +      struct eap_ttls_data *data = priv;
 +      return data->key_data != NULL && data->phase2_success;
 +}
 +
 +
 +static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
 +{
 +      struct eap_ttls_data *data = priv;
 +      u8 *key;
 +
 +      if (data->key_data == NULL || !data->phase2_success)
 +              return NULL;
 +
 +      key = os_malloc(EAP_TLS_KEY_LEN);
 +      if (key == NULL)
 +              return NULL;
 +
 +      *len = EAP_TLS_KEY_LEN;
 +      os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
 +
 +      return key;
 +}
 +
 +
 +static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 +{
 +      struct eap_ttls_data *data = priv;
 +      u8 *id;
 +
 +      if (data->session_id == NULL || !data->phase2_success)
 +              return NULL;
 +
 +      id = os_malloc(data->id_len);
 +      if (id == NULL)
 +              return NULL;
 +
 +      *len = data->id_len;
 +      os_memcpy(id, data->session_id, data->id_len);
 +
 +      return id;
 +}
 +
 +
 +static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 +{
 +      struct eap_ttls_data *data = priv;
 +      u8 *key;
 +
 +      if (data->key_data == NULL)
 +              return NULL;
 +
 +      key = os_malloc(EAP_EMSK_LEN);
 +      if (key == NULL)
 +              return NULL;
 +
 +      *len = EAP_EMSK_LEN;
 +      os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
 +
 +      return key;
 +}
 +
 +
 +int eap_peer_ttls_register(void)
 +{
 +      struct eap_method *eap;
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
 +
 +      eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 +                                  EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS");
 +      if (eap == NULL)
 +              return -1;
 +
 +      eap->init = eap_ttls_init;
 +      eap->deinit = eap_ttls_deinit;
 +      eap->process = eap_ttls_process;
 +      eap->isKeyAvailable = eap_ttls_isKeyAvailable;
 +      eap->getKey = eap_ttls_getKey;
 +      eap->getSessionId = eap_ttls_get_session_id;
 +      eap->get_status = eap_ttls_get_status;
 +      eap->has_reauth_data = eap_ttls_has_reauth_data;
 +      eap->deinit_for_reauth = eap_ttls_deinit_for_reauth;
 +      eap->init_for_reauth = eap_ttls_init_for_reauth;
 +      eap->get_emsk = eap_ttls_get_emsk;
 +
++      return eap_peer_method_register(eap);
 +}
@@@ -169,7 -169,6 +169,6 @@@ static u8 * eap_vendor_test_getKey(stru
  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,
        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);
  }
@@@ -17,7 -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 +36,8 @@@ static const char * eap_wsc_state_txt(i
                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 +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,
        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);
  }
@@@ -128,7 -128,7 +128,7 @@@ static int ikev2_parse_transform(struc
  
        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 +248,7 @@@ static int ikev2_parse_proposal(struct 
  
        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;
@@@ -104,7 -104,7 +104,7 @@@ static struct tnc_if_imc *tnc_imc[TNC_M
  
  /* 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)
  }
  
  
- TNC_Result TNC_TNCC_SendMessage(
static TNC_Result TNC_TNCC_SendMessage(
        TNC_IMCID imcID,
        TNC_ConnectionID connectionID,
        TNC_BufferReference message,
  }
  
  
- TNC_Result TNC_TNCC_RequestHandshakeRetry(
static TNC_Result TNC_TNCC_RequestHandshakeRetry(
        TNC_IMCID imcID,
        TNC_ConnectionID connectionID,
        TNC_RetryReason reason)
  }
  
  
- 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')",
  }
  
  
- 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')",
  }
  
  
- TNC_Result TNC_TNCC_BindFunction(
static TNC_Result TNC_TNCC_BindFunction(
        TNC_IMCID imcID,
        char *functionName,
        void **pOutfunctionPointer)
@@@ -694,6 -695,8 +695,8 @@@ enum tncc_process_res tncc_process_if_t
        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;
@@@ -15,7 -15,6 +15,6 @@@ const struct eap_method * eap_server_ge
                                                    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);
@@@ -1319,7 -1319,6 +1319,6 @@@ static u8 * eap_aka_get_session_id(stru
  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");
        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);
  }
  
  
  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,
        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 */
@@@ -792,7 -792,6 +792,6 @@@ static u8 * eap_eke_get_session_id(stru
  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");
        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);
  }
@@@ -180,42 -180,47 +180,47 @@@ static int eap_fast_session_ticket_cb(v
                        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 +278,7 @@@ static void eap_fast_derive_key_auth(st
         * 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 +305,6 @@@ static void eap_fast_derive_key_provisi
        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 +411,13 @@@ static int eap_fast_update_icmk(struct 
  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 +1140,7 @@@ static int eap_fast_parse_tlvs(struct w
  
        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 +1565,10 @@@ static u8 * eap_fast_getKey(struct eap_
        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 +1587,10 @@@ static u8 * eap_fast_get_emsk(struct ea
        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 +1619,6 @@@ static u8 * eap_fast_get_session_id(str
  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");
        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);
  }
@@@ -631,7 -631,6 +631,6 @@@ static u8 * eap_gpsk_get_session_id(str
  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");
        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);
  }
@@@ -202,7 -202,6 +202,6 @@@ static Boolean eap_gtc_isSuccess(struc
  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");
        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);
  }
@@@ -157,7 -157,6 +157,6 @@@ static Boolean eap_identity_isSuccess(s
  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,
        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);
  }
@@@ -550,7 -550,6 +550,6 @@@ static u8 * eap_ikev2_get_session_id(st
  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,
        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);
  }
@@@ -153,7 -153,6 +153,6 @@@ static Boolean eap_md5_isSuccess(struc
  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");
        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);
  }
@@@ -87,7 -87,7 +87,7 @@@ struct eap_method * eap_server_method_a
   * 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);
  }
  
  /**
   * 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;
        }
  
@@@ -571,7 -571,6 +571,6 @@@ static Boolean eap_mschapv2_isSuccess(s
  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,
        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);
  }
@@@ -565,7 -565,6 +565,6 @@@ static u8 * eap_pax_get_session_id(stru
  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");
        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);
  }
@@@ -335,6 -335,18 +335,18 @@@ static int eap_peap_derive_cmk(struct e
                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));
  
  
        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 +1278,9 @@@ static void eap_peap_process(struct eap
  
        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 +1363,6 @@@ static u8 * eap_peap_get_session_id(str
  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");
        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);
  }
@@@ -510,7 -510,6 +510,6 @@@ static u8 * eap_psk_get_session_id(stru
  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");
        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);
  }
@@@ -178,8 -178,13 +178,13 @@@ static void eap_pwd_build_id_req(struc
                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 +975,7 @@@ static void eap_pwd_process(struct eap_
        /*
         * 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)",
                }
                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;
         * 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 +1099,6 @@@ static u8 * eap_pwd_get_session_id(stru
  int eap_server_pwd_register(void)
  {
        struct eap_method *eap;
-       int ret;
        struct timeval tp;
        struct timezone tz;
        u32 sr;
        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);
  }
  
@@@ -520,7 -520,6 +520,6 @@@ static u8 * eap_sake_get_session_id(str
  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");
        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);
  }
@@@ -846,7 -846,6 +846,6 @@@ static u8 * eap_sim_get_session_id(stru
  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");
        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);
  }
@@@ -375,7 -375,6 +375,6 @@@ static u8 * eap_tls_get_session_id(stru
  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");
        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);
  }
  
  
  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,
        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 */
  
  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,
        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 */
@@@ -115,8 -115,8 +115,8 @@@ u8 * eap_server_tls_derive_key(struct e
        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;
        }
@@@ -554,7 -554,6 +554,6 @@@ static Boolean eap_tnc_isSuccess(struc
  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");
        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);
  }
@@@ -1335,7 -1335,6 +1335,6 @@@ static u8 * eap_ttls_get_emsk(struct ea
  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");
        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);
  }
@@@ -168,7 -168,6 +168,6 @@@ static Boolean eap_vendor_test_isSucces
  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,
        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);
  }
@@@ -488,7 -488,6 +488,6 @@@ static int eap_wsc_getTimeout(struct ea
  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,
        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);
  }
@@@ -66,6 -66,7 +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];
  };
  
  
+ 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 +402,57 @@@ static void eap_sim_db_add_pending(stru
  }
  
  
+ 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)
  {
  
  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 +619,7 @@@ static void eap_sim_db_aka_resp_auth(st
  
  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 +746,13 @@@ static void eap_sim_db_close_socket(str
  /**
   * 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)
  {
        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 +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 +891,11 @@@ static int eap_sim_db_send(struct eap_s
  }
  
  
- 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 +949,7 @@@ int eap_sim_db_get_gsm_triplets(struct 
                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;
                }
  
                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;
        }
  
        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 +1415,7 @@@ int eap_sim_db_get_aka_auth(struct eap_
        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;
                }
                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;
        }
  
        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;
  }
@@@ -31,7 -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);
  
@@@ -133,7 -133,7 +133,7 @@@ static int ikev2_parse_transform(struc
  
        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 +221,7 @@@ static int ikev2_parse_proposal(struct 
  
        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;
  
        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;
@@@ -140,7 -140,7 +140,7 @@@ static struct tncs_data * tncs_get_conn
  
  
  /* 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)
  }
  
  
- TNC_Result TNC_TNCS_SendMessage(
static TNC_Result TNC_TNCS_SendMessage(
        TNC_IMVID imvID,
        TNC_ConnectionID connectionID,
        TNC_BufferReference message,
  }
  
  
- TNC_Result TNC_TNCS_RequestHandshakeRetry(
static TNC_Result TNC_TNCS_RequestHandshakeRetry(
        TNC_IMVID imvID,
        TNC_ConnectionID connectionID,
        TNC_RetryReason reason)
  }
  
  
- TNC_Result TNC_TNCS_ProvideRecommendation(
static TNC_Result TNC_TNCS_ProvideRecommendation(
        TNC_IMVID imvID,
        TNC_ConnectionID connectionID,
        TNC_IMV_Action_Recommendation recommendation,
  }
  
  
- TNC_Result TNC_TNCS_GetAttribute(
static TNC_Result TNC_TNCS_GetAttribute(
        TNC_IMVID imvID,
        TNC_ConnectionID connectionID,
        TNC_AttributeID attribureID,
  }
  
  
- TNC_Result TNC_TNCS_SetAttribute(
static TNC_Result TNC_TNCS_SetAttribute(
        TNC_IMVID imvID,
        TNC_ConnectionID connectionID,
        TNC_AttributeID attribureID,
  }
  
  
- TNC_Result TNC_TNCS_BindFunction(
static TNC_Result TNC_TNCS_BindFunction(
        TNC_IMVID imvID,
        char *functionName,
        void **pOutFunctionPointer)
@@@ -866,10 -866,13 +866,13 @@@ eapol_auth_alloc(struct eapol_authentic
                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 +887,9 @@@ void eapol_auth_free(struct eapol_state
        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 +1277,6 @@@ struct eapol_authenticator * eapol_auth
                                             struct eapol_auth_cb *cb)
  {
        struct eapol_authenticator *eapol;
-       struct os_time now;
  
        eapol = os_zalloc(sizeof(*eapol));
        if (eapol == NULL)
        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;
  }
  
@@@ -30,9 -30,6 +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 +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 */
  
        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 */
@@@ -314,6 -314,16 +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;
+       }
  }
  
  
diff --combined libeap/src/fst/fst.c
@@@ -15,6 -15,7 +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 +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 +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);
                                  struct fst_ctrl_handle,
                                  global_ctrls_lentry)))
                fst_global_del_ctrl(h);
+       fst_global_initialized = 0;
  }
  
  
@@@ -160,7 -166,7 +166,7 @@@ void fst_global_del_ctrl(struct fst_ctr
  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,
  
  
  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,
  };
  
@@@ -648,9 -648,9 +648,9 @@@ static int list_groups(const char *cmd
  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 +749,7 @@@ int fst_ctrl_iface_mb_info(const u8 *ad
  
        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);
                        }
@@@ -34,7 -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 +47,7 @@@
  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 +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 */
  
  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 +131,6 @@@ static struct wpabuf * fst_group_create
        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 +196,35 @@@ static const u8 * fst_mbie_get_peer_add
  }
  
  
- 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 u8 *p = wpabuf_head(mbies);
+       size_t s = wpabuf_len(mbies);
+       while (s >= 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;
-               if (mbie->band_id == band_id) {
-                       struct fst_iface *iface;
-                       foreach_fst_group_iface(g, iface) {
-                               const u8 *peer_addr =
-                                       fst_mbie_get_peer_addr(mbie);
-                               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;
+                       (const struct multi_band_ie *) p;
+               if (mbie->eid != WLAN_EID_MULTI_BAND) {
+                       fst_printf(MSG_INFO, "unexpected eid %d", mbie->eid);
+                       return NULL;
+               }
+               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 +261,172 @@@ u32 fst_group_assign_fsts_id(struct fst
  }
  
  
- 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;
  }
  
  
@@@ -48,15 -48,9 +48,9 @@@ Boolean fst_group_delete_if_empty(struc
  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);
  
@@@ -49,12 -49,13 +49,13 @@@ void fst_iface_delete(struct fst_iface 
  }
  
  
- 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;
  
@@@ -123,7 -123,8 +123,8 @@@ static inline const u8 * fst_iface_get_
        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);
  
@@@ -44,7 -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 +181,8 @@@ static void fst_session_timeout_handler
  
  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 +364,6 @@@ static void fst_session_handle_setup_re
        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))  {
                                 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) {
                 * 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 ")",
                        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.
                                           "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 +507,9 @@@ static void fst_session_handle_setup_re
        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 +851,15 @@@ int fst_session_initiate_setup(struct f
                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 +956,8 @@@ int fst_session_respond(struct fst_sess
                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;
        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 +1449,7 @@@ int fst_test_req_send_fst_response(cons
        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 +1498,7 @@@ int fst_test_req_send_ack_request(cons
        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 +1526,7 @@@ int fst_test_req_send_ack_response(cons
        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 +1553,7 @@@ int fst_test_req_send_tear_down(const c
  
        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);
  }
@@@ -30,11 -30,14 +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 +130,6 @@@ static void l2_packet_receive(int sock
        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,
        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];
                                   __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;
        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);
                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(
        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 +317,7 @@@ struct l2_packet_data * l2_packet_init_
        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),
                .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
        }
  
        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 +404,12 @@@ void l2_packet_deinit(struct l2_packet_
                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);
  }
@@@ -312,6 -312,18 +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)
diff --combined libeap/src/p2p/p2p.c
@@@ -10,6 -10,7 +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 +446,9 @@@ static struct p2p_device * p2p_create_d
  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 +638,11 @@@ static void p2p_update_peer_vendor_elem
  
        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 +788,11 @@@ int p2p_add_device(struct p2p_data *p2p
                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 +1222,14 @@@ int p2p_find(struct p2p_data *p2p, unsi
  
        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 +1466,7 @@@ static void p2p_prepare_channel_best(st
  
  
  /**
-  * 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
   * 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 +2035,23 @@@ static void p2p_add_dev_from_probe_req(
  
        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 +2234,58 @@@ struct wpabuf * p2p_build_probe_resp_ie
        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 +2319,8 @@@ p2p_reply_probe(struct p2p_data *p2p, c
  {
        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) {
                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);
  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 +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);
        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);
  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 +3198,18 @@@ int p2p_set_country(struct p2p_data *p2
  
  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 &&
  void p2p_continue_find(struct p2p_data *p2p)
  {
        struct p2p_device *dev;
-       int found;
+       int found, res;
  
        p2p_set_state(p2p, P2P_SEARCH);
  
                }
                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;
        }
  
        /*
         * 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 +3280,17 @@@ static void p2p_sd_cb(struct p2p_data *
        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 +3389,43 @@@ static void p2p_prov_disc_cb(struct p2p
        }
  
        /*
+        * 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 +3499,11 @@@ int p2p_scan_res_handler(struct p2p_dat
                 * 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 +3528,8 @@@ void p2p_scan_res_handled(struct p2p_da
  }
  
  
- 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;
                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 +3800,8 @@@ void p2p_send_action_cb(struct p2p_dat
                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 +5508,34 @@@ void p2p_set_own_pref_freq_list(struct 
                        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;
+ }
diff --combined libeap/src/p2p/p2p.h
@@@ -31,7 -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 +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 +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 +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
         * 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
                                   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
  
        /**
         * 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 +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 +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 +1909,10 @@@ int p2p_assoc_req_ie(struct p2p_data *p
   * @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 +2134,16 @@@ int p2p_client_limit_reached(struct p2p
  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 +2285,7 @@@ struct wpabuf * wifi_display_encaps(str
   * 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 +2384,7 @@@ void p2p_set_own_pref_freq_list(struct 
  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 */
@@@ -202,11 -202,11 +202,11 @@@ void p2p_buf_add_device_info(struct wpa
        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 |
@@@ -38,7 -38,7 +38,7 @@@ int p2p_peer_channels_check(struct p2p_
  {
        const u8 *pos, *end;
        struct p2p_channels *ch;
-       size_t channels;
+       u8 channels;
        struct p2p_channels intersection;
  
        ch = &dev->channels;
        }
        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 +384,7 @@@ void p2p_reselect_channel(struct p2p_da
        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 +901,14 @@@ void p2p_process_go_neg_req(struct p2p_
                        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 +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 +1268,11 @@@ void p2p_process_go_neg_resp(struct p2p
                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 +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);
@@@ -155,7 -155,8 +155,8 @@@ static void p2p_group_add_common_ies(st
                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 +297,14 @@@ static int wifi_display_add_dev_info_de
        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 +850,20 @@@ static struct p2p_group_member * p2p_gr
  }
  
  
+ 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 +1112,7 @@@ int p2p_group_get_common_freqs(struct p
                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);
diff --combined libeap/src/p2p/p2p_i.h
@@@ -308,6 -308,18 +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 +703,8 @@@ int p2p_channel_random_social(struct p2
                              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);
@@@ -284,7 -284,7 +284,7 @@@ void p2p_process_invitation_req(struct 
  
                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 +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");
        }
  
  #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) {
                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 +648,48 @@@ int p2p_group_info_parse(const u8 *gi, 
        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;
diff --combined libeap/src/p2p/p2p_pd.c
@@@ -40,21 -40,31 +40,31 @@@ static void p2p_build_wps_ie_config_met
  }
  
  
- 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 +102,62 @@@ static void p2ps_add_pd_req_attrs(struc
        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 +295,11 @@@ static struct wpabuf * p2p_build_prov_d
                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;
                                       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];
                        }
                }
  
-               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,
                                        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 +440,117 @@@ static u8 p2ps_own_preferred_cpt(const 
  }
  
  
+ /* 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)
  {
        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;
                                   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 */
                                             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;
                                                     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,
                                                     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,
                                             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,
                                             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;
                                             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);
                                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);
                }
                                        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 +1349,9 @@@ void p2p_process_prov_disc_resp(struct 
                        " 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) {
                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 &&
                                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 +1640,10 @@@ int p2p_send_prov_disc_req(struct p2p_d
                        "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);
diff --combined libeap/src/p2p/p2p_sd.c
@@@ -28,11 -28,11 +28,11 @@@ static int wfd_wsd_supported(struct wpa
        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 +288,14 @@@ int p2p_start_sd(struct p2p_data *p2p, 
        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 +363,11 @@@ void p2p_rx_gas_initial_req(struct p2p_
        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) {
  
        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));
  
        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;
        }
        }
        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 +425,16 @@@ void p2p_sd_response(struct p2p_data *p
                     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 +527,11 @@@ void p2p_rx_gas_initial_resp(struct p2p
        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) {
  
        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;
        }
        }
  
        /* 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));
  
        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;
        }
        }
        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 +621,7 @@@ void p2p_rx_gas_comeback_req(struct p2p
  {
        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);
                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 +747,11 @@@ void p2p_rx_gas_comeback_resp(struct p2
        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) {
  
        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;
        }
        }
  
        /* 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));
                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) {
        }
        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);
@@@ -20,7 -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 +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 +71,7 @@@
        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 +97,7 @@@ static void ieee802_1x_cp_transmit_when
  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 +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 +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;
  
  
        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;
  
        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 +514,6 @@@ void ieee802_1x_cp_sm_deinit(struct iee
        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 +600,10 @@@ void ieee802_1x_cp_set_authorizationdat
  /**
   * 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;
  }
  
  
@@@ -16,17 -16,7 +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 +26,7 @@@ void ieee802_1x_cp_connect_secure(void 
  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,
@@@ -29,6 -29,8 +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;
  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))
  
  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 +79,6 @@@ static int is_ki_equal(struct ieee802_1
  }
  
  
- 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 +94,7 @@@ static unsigned int get_mka_param_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 +118,8 @@@ ieee802_1x_mka_dump_basic_body(struct i
        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 +144,7 @@@ ieee802_1x_mka_dump_peer_body(struct ie
        size_t body_len;
        size_t i;
        u8 *mi;
-       u32 mn;
+       be32 mn;
  
        if (body == NULL)
                return;
        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 +183,7 @@@ ieee802_1x_mka_dump_dist_sak_body(struc
        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 +276,7 @@@ ieee802_1x_kay_get_principal_participan
                        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 +296,46 @@@ static struct ieee802_1x_kay_peer * get
  
  
  /**
-  * 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 +348,11 @@@ ieee802_1x_kay_get_peer(struct ieee802_
  {
        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);
  }
  
  
   */
  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 +397,13 @@@ ieee802_1x_kay_get_peer_sci(struct ieee
  
        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 +440,8 @@@ ieee802_1x_kay_init_receive_sa(struct r
  
        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 +454,8 @@@ static void ieee802_1x_kay_deinit_recei
  {
        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 +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;
        }
        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 +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 +613,12 @@@ ieee802_1x_kay_move_live_peer(struct ie
        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));
        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 +662,7 @@@ ieee802_1x_mka_basic_body_length(struc
  
        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 +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);
  }
  
  
+ 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 +751,15 @@@ ieee802_1x_mka_decode_basic_body(struc
  
        /* 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);
                        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 +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 +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 +888,7 @@@ ieee802_1x_mka_get_potential_peer_lengt
                         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 +917,6 @@@ ieee802_1x_mka_encode_potential_peer_bo
                                       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 +931,54 @@@ static Boolea
  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 +995,6 @@@ static int ieee802_1x_mka_decode_live_p
        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;
  
  
        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 +1052,33 @@@ ieee802_1x_mka_decode_potential_peer_bo
        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 +1094,7 @@@ static Boolea
  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 +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 +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);
        }
  
        /* 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;
        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;
  
        /* 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 +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");
  
        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;
        }
  
  
        /* 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);
                }
        }
  
        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;
        }
  
        /* 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;
        }
        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;
        }
        /* 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 +1388,7 @@@ static Boolea
  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 +1399,18 @@@ static in
  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 +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);
        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,
  /**
   * 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 +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;
        }
  
                           "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;
                           "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);
                        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) {
                }
                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);
        }
        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 +1652,7 @@@ ieee802_1x_mka_get_icv_length(struct ie
        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 +1680,9 @@@ ieee802_1x_mka_encode_icv_body(struct i
                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 +1698,7 @@@ ieee802_1x_mka_decode_icv_body(struct i
        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 +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 +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 +1789,87 @@@ static int ieee802_1x_mka_decode_announ
  }
  
  
- 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
        },
  };
  
  /**
   * 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 +1899,13 @@@ static in
  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
                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));
        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);
  
                         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 +2049,6 @@@ ieee802_1x_kay_elect_key_server(struct 
        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;
                        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);
                }
                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);
                }
                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 +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 +2227,10 @@@ ieee802_1x_kay_encode_mkpdu(struct ieee
        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 +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 +2296,16 @@@ static void ieee802_1x_participant_time
        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;
                }
                        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);
        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 +2438,8 @@@ ieee802_1x_kay_init_transmit_sa(struct 
  
        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 +2452,8 @@@ static void ieee802_1x_kay_deinit_trans
  {
        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 +2769,6 @@@ int ieee802_1x_kay_enable_new_info(stru
  
  
  /**
-  * 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 +2796,13 @@@ static int ieee802_1x_kay_mkpdu_sanity_
                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");
        /* 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;
        }
  
                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 +2876,9 @@@ static int ieee802_1x_kay_decode_mkpdu(
        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))
        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);
        }
  
        /*
                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);
  
                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 +2989,10 @@@ static void kay_l2_receive(void *ctx, c
        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;
        }
  
                           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 +3042,7 @@@ ieee802_1x_kay_init(struct ieee802_1x_k
  
        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 */
        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 +3209,7 @@@ ieee802_1x_kay_create_mka(struct ieee80
        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;
        }
        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 +3316,7 @@@ ieee802_1x_kay_delete_mka(struct ieee80
                return;
        }
  
+       eloop_cancel_timeout(ieee802_1x_participant_timer, participant, NULL);
        dl_list_del(&participant->list);
  
        /* remove live peer */
@@@ -3510,14 -3405,15 +3405,15 @@@ ieee802_1x_kay_new_sak(struct ieee802_1
   * 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;
@@@ -14,7 -14,6 +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 +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 +47,6 @@@ struct mka_key_name 
  enum mka_created_mode {
        PSK,
        EAP_EXCHANGE,
-       DISTRIBUTED,
-       CACHED,
  };
  
  struct ieee802_1x_kay_ctx {
@@@ -61,7 -58,7 +58,7 @@@
        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 +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 +168,7 @@@ void ieee802_1x_kay_mka_participate(str
                                    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 +185,5 @@@ int ieee802_1x_kay_enable_tx_sas(struc
  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 */
@@@ -38,7 -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 {
        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 +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 +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*/
  
  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 */
  
  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
  
  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];
@@@ -65,8 -65,7 +65,7 @@@ int secy_cp_control_replay(struct ieee8
  }
  
  
- 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 +81,7 @@@
                return -1;
        }
  
-       return ops->set_current_cipher_suite(ops->ctx, cs, cs_len);
+       return ops->set_current_cipher_suite(ops->ctx, cs);
  }
  
  
@@@ -26,8 -26,7 +26,7 @@@ int secy_cp_control_validate_frames(str
                                    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);
@@@ -1,6 -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 +173,8 @@@ static const struct radius_attr_type ra
        { 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 },
          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 +538,8 @@@ int radius_msg_verify_acct_req(struct r
  
  
  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];
        }
  
        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 +711,7 @@@ struct radius_msg * radius_msg_parse(co
  
                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 +823,9 @@@ int radius_msg_verify_msg_auth(struct r
                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 +868,8 @@@ int radius_msg_verify(struct radius_ms
        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 +901,11 @@@ int radius_msg_copy_attr(struct radius_
  
  /* 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 +1023,10 @@@ static u8 * decrypt_ms_key(const u8 *ke
                        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 +1208,11 @@@ int radius_msg_add_mppe_keys(struct rad
        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 +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;
        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);
                                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 +1716,14 @@@ u8 radius_msg_find_unlisted_attr(struc
  
        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);
+ }
@@@ -1,6 -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 +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 +81,7 @@@
         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,
  };
  
  
+ /* 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 +242,8 @@@ void radius_msg_finish_acct_resp(struc
  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 +257,7 @@@ int radius_msg_verify_msg_auth(struct r
                               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 +280,8 @@@ radius_msg_add_attr_user_password(struc
                                  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 +326,6 @@@ int radius_copy_class(struct radius_cla
  
  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 */
@@@ -226,6 -226,16 +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 +307,25 @@@ int radius_client_register(struct radiu
  }
  
  
+ /**
+  * 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 +337,7 @@@ static int radius_client_handle_send_er
        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 +365,8 @@@ static int radius_client_retransmit(str
        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) {
                        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,
  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;
                               (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 +695,6 @@@ static void radius_client_list_add(stru
  }
  
  
- 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()
   * 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,
        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 +1050,9 @@@ radius_change_server(struct radius_clie
        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,
                       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,
                }
        }
  
+       /* 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 +1636,16 @@@ static int radius_client_dump_acct_serv
  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];
@@@ -241,6 -241,9 +241,9 @@@ int radius_client_register(struct radiu
                            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);
@@@ -23,6 -23,7 +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 +235,11 @@@ static void radius_das_receive(int sock
                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 +365,8 @@@ radius_das_init(struct radius_das_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;
  
@@@ -44,6 -44,7 +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);
@@@ -15,7 -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 +109,7 @@@ static void pmksa_cache_set_expiration(
   * @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
   */
  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)
                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 +347,7 @@@ pmksa_cache_clone_entry(struct rsn_pmks
        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)
@@@ -15,7 -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 +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 +57,7 @@@ struct rsn_pmksa_cache_entry * pmksa_ca
  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 +105,7 @@@ static inline int pmksa_cache_list(stru
  
  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;
@@@ -18,7 -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 +93,7 @@@ static void rsn_preauth_eapol_cb(struc
                        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 +538,4 @@@ int rsn_preauth_in_progress(struct wpa_
        return sm->preauth_eapol != NULL;
  }
  
- #endif /* IEEE8021X_EAPOL */
+ #endif /* IEEE8021X_EAPOL && !CONFIG_NO_WPA */
@@@ -11,7 -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 +27,7 @@@ int rsn_preauth_get_status(struct wpa_s
                           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 +74,6 @@@ static inline int rsn_preauth_in_progre
        return 0;
  }
  
- #endif /* IEEE8021X_EAPOL */
+ #endif /* IEEE8021X_EAPOL && !CONFIG_NO_WPA */
  
  #endif /* PREAUTH_H */
@@@ -627,9 -627,15 +627,15 @@@ static void wpa_tdls_tpk_timeout(void *
         */
  
        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 +2176,14 @@@ static int wpa_tdls_process_tpk_m2(stru
                           "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) {
                    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 +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) {
                /*
  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 +2518,13 @@@ static int wpa_tdls_process_tpk_m3(stru
                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;
@@@ -1,6 -1,7 +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 +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)) {
        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 +131,7 @@@ void wpa_sm_key_request(struct wpa_sm *
                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 +213,21 @@@ static int wpa_supplicant_get_pmk(struc
  #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];
                            !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,
                                 * 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;
                        }
   * @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,
                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,
        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 +510,7 @@@ static void wpa_supplicant_process_1_of
                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;
  #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 +614,12 @@@ static int wpa_supplicant_install_ptk(s
        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");
  
        /* 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 +770,43 @@@ static int wpa_supplicant_gtk_tx_bit_wo
  }
  
  
+ 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
        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 +1041,8 @@@ static int wpa_supplicant_validate_ie_f
        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 +1138,7 @@@ static int wpa_supplicant_validate_ie(s
   * @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,
                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 +1252,7 @@@ static void wpa_supplicant_process_3_of
  #endif /* CONFIG_P2P */
  
        if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
-                                      &sm->ptk)) {
+                                      &sm->ptk) < 0) {
                goto failed;
        }
  
        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 +1487,8 @@@ static int wpa_supplicant_send_2_of_2(s
                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 +1501,7 @@@ static void wpa_supplicant_process_1_of
        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,
        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 +1670,14 @@@ static int wpa_supplicant_decrypt_key_d
                }
                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 +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 +2391,13 @@@ void wpa_sm_notify_disassoc(struct wpa_
   * @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;
  #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 +2496,7 @@@ void wpa_sm_set_config(struct wpa_sm *s
                        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;
                sm->ssid_len = 0;
                sm->wpa_ptk_rekey = 0;
                sm->p2p = 0;
+               sm->wpa_rsc_relaxation = 0;
        }
  }
  
@@@ -2636,6 -2695,17 +2695,17 @@@ int wpa_sm_set_assoc_wpa_ie_default(str
        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 +3045,12 @@@ void wpa_sm_set_ptk_kck_kek(struct wpa_
        }
        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 */
@@@ -104,6 -104,7 +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 +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 +181,8 @@@ static inline void wpa_sm_notify_disass
  }
  
  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 +322,8 @@@ static inline void wpa_sm_set_rx_replay
  }
  
  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 +418,12 @@@ int wpa_tdls_enable_chan_switch(struct 
                                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 */
@@@ -19,11 -19,12 +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 +61,7 @@@
        size_t ssid_len;
        int wpa_ptk_rekey;
        int p2p;
+       int wpa_rsc_relaxation;
  
        u8 own_addr[ETH_ALEN];
        const char *ifname;
  #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 +348,14 @@@ wpa_sm_tdls_disable_channel_switch(stru
  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,
@@@ -378,7 -378,7 +378,7 @@@ static int wpa_parse_generic(const u8 *
                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 +491,13 @@@ int wpa_supplicant_parse_ies(const u8 *
        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));
diff --combined libeap/src/tls/Makefile
@@@ -24,6 -24,7 +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 \
diff --combined libeap/src/tls/asn1.h
@@@ -20,6 -20,7 +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 +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
diff --combined libeap/src/tls/pkcs5.c
@@@ -1,6 -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 +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)
  {
                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 ||
        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);
  }
  
  
+ 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)
  {
        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;
  
@@@ -1,6 -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 +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 +111,6 @@@ int tls_derive_keys(struct tlsv1_clien
                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 +494,7 @@@ void tlsv1_client_deinit(struct tlsv1_c
        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 +692,16 @@@ int tlsv1_client_hello_ext(struct tlsv1
        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 +812,14 @@@ int tlsv1_client_set_cred(struct tlsv1_
  }
  
  
- 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 +832,38 @@@ void tlsv1_client_set_session_ticket_cb
        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;
+ }
@@@ -41,7 -41,7 +41,7 @@@ int tlsv1_client_get_keyblock_size(stru
  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 +51,12 @@@ void tlsv1_client_set_session_ticket_cb
                                        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 */
@@@ -29,11 -29,14 +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;
  
        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 +90,11 @@@ int tlsv1_client_process_handshake(stru
                                   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 */
index 0000000,1d7b68c..1d7b68c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,803 +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;
+ }
@@@ -1,6 -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 +27,54 @@@ static int tls_process_server_hello_don
                                         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)
  {
        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,
        }
        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 +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)
  {
                        return -1;
                }
  
+               tls_peer_cert_event(conn, idx, cert);
                if (last == NULL)
                        chain = cert;
                else
                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;
                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 +727,7 @@@ static int tlsv1_process_diffie_hellman
        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) {
                         */
                        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 +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)
  {
  
        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);
        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 +1223,15 @@@ static int tls_process_server_hello_don
  
        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;
@@@ -1,6 -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 +47,28 @@@ u8 * tls_send_client_hello(struct tlsv1
        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 +81,7 @@@
        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;
        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);
        *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 +266,11 @@@ static int tls_write_client_certificate
        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;
        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 +402,16 @@@ static int tlsv1_key_x_dh(struct tlsv1_
        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 +933,8 @@@ static u8 * tls_send_change_cipher_spec
  
        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;
@@@ -335,7 -335,7 +335,7 @@@ int tls_prf(u16 ver, const u8 *secret, 
  
  
  #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,
  {
        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 +485,21 @@@ int tls_verify_signature(u16 tls_versio
                        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);
@@@ -169,6 -169,8 +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 +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);
@@@ -1,6 -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 +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 +36,8 @@@ void tlsv1_cred_free(struct tlsv1_crede
        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 +195,43 @@@ int tlsv1_set_ca_cert(struct tlsv1_cred
                      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 +330,735 @@@ static struct crypto_private_key * tlsv
  }
  
  
+ #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)
  {
                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;
@@@ -14,11 -14,19 +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;
  };
  
  
@@@ -55,6 -55,9 +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;
@@@ -46,6 -46,78 +46,78 @@@ static int testing_cipher_suite_filter(
  }
  
  
+ 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)
  {
                                                  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;
@@@ -468,6 -545,15 +545,15 @@@ static int tls_process_certificate(stru
                }
                tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
                x509_certificate_chain_free(chain);
+               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;
        }
  
@@@ -42,7 -42,7 +42,7 @@@ static size_t tls_server_cert_chain_der
  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;
  
        /* 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,
                 */
        }
  
+       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 +199,11 @@@ static int tls_write_server_certificate
        }
  
        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;
        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,
  }
  
  
+ 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)
  {
        /* 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,
        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,
        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,
                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);
  
                         *   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 +928,46 @@@ static u8 * tls_send_server_hello(struc
  {
        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) {
  
        /* 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;
  
diff --combined libeap/src/tls/x509v3.c
@@@ -1,6 -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 +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 +55,7 @@@ void x509_certificate_free(struct x509_
        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 +178,9 @@@ int x509_name_compare(struct x509_name 
  }
  
  
- 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;
                           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 +243,7 @@@ static int x509_parse_public_key(const 
        }
        pos = hdr.payload;
  
-       if (pos + hdr.length > end)
+       if (hdr.length > end - pos)
                return -1;
        end = pos + hdr.length;
        *next = end;
  }
  
  
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;
        }
        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 +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 +676,7 @@@ static int x509_parse_validity(const u
        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 +720,15 @@@ static int x509_id_ce_oid(struct asn1_o
  }
  
  
+ 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 +809,7 @@@ static int x509_parse_ext_basic_constra
                }
                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 +1082,112 @@@ static int x509_parse_ext_issuer_alt_na
  }
  
  
+ 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)
         * 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]) {
                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 +1339,7 @@@ static int x509_parse_tbs_certificate(c
        size_t left;
        char sbuf[128];
        unsigned long value;
+       const u8 *subject_dn;
  
        /* tbsCertificate TBSCertificate ::= SEQUENCE */
        if (asn1_get_next(buf, len, &hdr) < 0 ||
  
        /* 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,
                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 +1561,7 @@@ static int x509_digest_oid(struct asn1_
  }
  
  
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 */ &&
  }
  
  
- 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 */ &&
                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 +1647,12 @@@ struct x509_certificate * x509_certific
        }
        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));
  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;
        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);
        }
  
        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;
                }
        }
  
        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;
                }
        }
        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 +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 +2038,7 @@@ int x509_certificate_chain_validate(str
        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);
  
  
                        wpa_printf(MSG_DEBUG, "X509: Trusted certificate "
                                   "found to complete the chain");
+                       cert->issuer_trusted = 1;
                        chain_trusted = 1;
                }
        }
diff --combined libeap/src/tls/x509v3.h
@@@ -45,13 -45,18 +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 +73,7 @@@
  #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 */
  #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.
        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 {
  };
  
  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 +149,9 @@@ x509_certificate_get_subject(struct x50
                             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 */
@@@ -95,7 -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";
                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));
@@@ -86,7 -86,7 +86,7 @@@ int hwaddr_masked_aton(const char *txt
                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 +498,7 @@@ void printf_encode(char *txt, size_t ma
                        *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 +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 +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 +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,0000000..2a185fb
mode 100644,000000..100644
--- /dev/null
@@@ -1,568 -1,0 +1,584 @@@
 +/*
 + * wpa_supplicant/hostapd / common helper functions, etc.
 + * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
 + *
 + * This software may be distributed under the terms of the BSD license.
 + * See README for more details.
 + */
 +
 +#ifndef COMMON_H
 +#define COMMON_H
 +
 +#include "os.h"
 +
 +#if defined(__linux__) || defined(__GLIBC__)
 +#include <endian.h>
 +#include <byteswap.h>
 +#endif /* __linux__ */
 +
 +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
 +    defined(__OpenBSD__)
 +#include <sys/types.h>
 +#include <sys/endian.h>
 +#define __BYTE_ORDER  _BYTE_ORDER
 +#define       __LITTLE_ENDIAN _LITTLE_ENDIAN
 +#define       __BIG_ENDIAN    _BIG_ENDIAN
 +#ifdef __OpenBSD__
 +#define bswap_16 swap16
 +#define bswap_32 swap32
 +#define bswap_64 swap64
 +#else /* __OpenBSD__ */
 +#define bswap_16 bswap16
 +#define bswap_32 bswap32
 +#define bswap_64 bswap64
 +#endif /* __OpenBSD__ */
 +#endif /* defined(__FreeBSD__) || defined(__NetBSD__) ||
 +      * defined(__DragonFly__) || defined(__OpenBSD__) */
 +
 +#ifdef __APPLE__
 +#include <sys/types.h>
 +#include <machine/endian.h>
 +#define __BYTE_ORDER  _BYTE_ORDER
 +#define __LITTLE_ENDIAN       _LITTLE_ENDIAN
 +#define __BIG_ENDIAN  _BIG_ENDIAN
 +static inline unsigned short bswap_16(unsigned short v)
 +{
 +      return ((v & 0xff) << 8) | (v >> 8);
 +}
 +
 +static inline unsigned int bswap_32(unsigned int v)
 +{
 +      return ((v & 0xff) << 24) | ((v & 0xff00) << 8) |
 +              ((v & 0xff0000) >> 8) | (v >> 24);
 +}
 +#endif /* __APPLE__ */
 +
 +#ifdef CONFIG_NATIVE_WINDOWS
 +#ifdef CONFIG_IPV6
 +#include <winsock2.h>
 +#include <ws2tcpip.h>
 +#else
 +#include <winsock.h>
 +#endif
 +
 +typedef int socklen_t;
 +
 +#ifndef MSG_DONTWAIT
 +#define MSG_DONTWAIT 0 /* not supported */
 +#endif
 +
 +#endif /* CONFIG_NATIVE_WINDOWS */
 +
 +#ifdef _MSC_VER
 +#ifndef __cplusplus
 +#define inline __inline
 +#endif
 +
 +#undef vsnprintf
 +#define vsnprintf _vsnprintf
 +#undef close
 +#define close closesocket
 +#endif /* _MSC_VER */
 +
 +
 +/* Define platform specific integer types */
 +
 +#ifdef _MSC_VER
 +typedef UINT64 u64;
 +typedef UINT32 u32;
 +typedef UINT16 u16;
 +typedef UINT8 u8;
 +typedef INT64 s64;
 +typedef INT32 s32;
 +typedef INT16 s16;
 +typedef INT8 s8;
 +#define WPA_TYPES_DEFINED
 +#endif /* _MSC_VER */
 +
 +#ifdef __vxworks
 +typedef unsigned long long u64;
 +typedef UINT32 u32;
 +typedef UINT16 u16;
 +typedef UINT8 u8;
 +typedef long long s64;
 +typedef INT32 s32;
 +typedef INT16 s16;
 +typedef INT8 s8;
 +#define WPA_TYPES_DEFINED
 +#endif /* __vxworks */
 +
 +#ifndef WPA_TYPES_DEFINED
 +#ifdef CONFIG_USE_INTTYPES_H
 +#include <inttypes.h>
 +#else
 +#include <stdint.h>
 +#endif
 +typedef uint64_t u64;
 +typedef uint32_t u32;
 +typedef uint16_t u16;
 +typedef uint8_t u8;
 +typedef int64_t s64;
 +typedef int32_t s32;
 +typedef int16_t s16;
 +typedef int8_t s8;
 +#define WPA_TYPES_DEFINED
 +#endif /* !WPA_TYPES_DEFINED */
 +
 +
 +/* Define platform specific byte swapping macros */
 +
 +#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
 +
 +static inline unsigned short wpa_swap_16(unsigned short v)
 +{
 +      return ((v & 0xff) << 8) | (v >> 8);
 +}
 +
 +static inline unsigned int wpa_swap_32(unsigned int v)
 +{
 +      return ((v & 0xff) << 24) | ((v & 0xff00) << 8) |
 +              ((v & 0xff0000) >> 8) | (v >> 24);
 +}
 +
 +#define le_to_host16(n) (n)
 +#define host_to_le16(n) (n)
 +#define be_to_host16(n) wpa_swap_16(n)
 +#define host_to_be16(n) wpa_swap_16(n)
 +#define le_to_host32(n) (n)
 +#define host_to_le32(n) (n)
 +#define be_to_host32(n) wpa_swap_32(n)
 +#define host_to_be32(n) wpa_swap_32(n)
 +
 +#define WPA_BYTE_SWAP_DEFINED
 +
 +#endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */
 +
 +
 +#ifndef WPA_BYTE_SWAP_DEFINED
 +
 +#ifndef __BYTE_ORDER
 +#ifndef __LITTLE_ENDIAN
 +#ifndef __BIG_ENDIAN
 +#define __LITTLE_ENDIAN 1234
 +#define __BIG_ENDIAN 4321
 +#if defined(sparc)
 +#define __BYTE_ORDER __BIG_ENDIAN
 +#endif
 +#endif /* __BIG_ENDIAN */
 +#endif /* __LITTLE_ENDIAN */
 +#endif /* __BYTE_ORDER */
 +
 +#if __BYTE_ORDER == __LITTLE_ENDIAN
 +#define le_to_host16(n) ((__force u16) (le16) (n))
 +#define host_to_le16(n) ((__force le16) (u16) (n))
 +#define be_to_host16(n) bswap_16((__force u16) (be16) (n))
 +#define host_to_be16(n) ((__force be16) bswap_16((n)))
 +#define le_to_host32(n) ((__force u32) (le32) (n))
 +#define host_to_le32(n) ((__force le32) (u32) (n))
 +#define be_to_host32(n) bswap_32((__force u32) (be32) (n))
 +#define host_to_be32(n) ((__force be32) bswap_32((n)))
 +#define le_to_host64(n) ((__force u64) (le64) (n))
 +#define host_to_le64(n) ((__force le64) (u64) (n))
 +#define be_to_host64(n) bswap_64((__force u64) (be64) (n))
 +#define host_to_be64(n) ((__force be64) bswap_64((n)))
 +#elif __BYTE_ORDER == __BIG_ENDIAN
 +#define le_to_host16(n) bswap_16(n)
 +#define host_to_le16(n) bswap_16(n)
 +#define be_to_host16(n) (n)
 +#define host_to_be16(n) (n)
 +#define le_to_host32(n) bswap_32(n)
 +#define host_to_le32(n) bswap_32(n)
 +#define be_to_host32(n) (n)
 +#define host_to_be32(n) (n)
 +#define le_to_host64(n) bswap_64(n)
 +#define host_to_le64(n) bswap_64(n)
 +#define be_to_host64(n) (n)
 +#define host_to_be64(n) (n)
 +#ifndef WORDS_BIGENDIAN
 +#define WORDS_BIGENDIAN
 +#endif
 +#else
 +#error Could not determine CPU byte order
 +#endif
 +
 +#define WPA_BYTE_SWAP_DEFINED
 +#endif /* !WPA_BYTE_SWAP_DEFINED */
 +
 +
 +/* Macros for handling unaligned memory accesses */
 +
 +static inline u16 WPA_GET_BE16(const u8 *a)
 +{
 +      return (a[0] << 8) | a[1];
 +}
 +
 +static inline void WPA_PUT_BE16(u8 *a, u16 val)
 +{
 +      a[0] = val >> 8;
 +      a[1] = val & 0xff;
 +}
 +
 +static inline u16 WPA_GET_LE16(const u8 *a)
 +{
 +      return (a[1] << 8) | a[0];
 +}
 +
 +static inline void WPA_PUT_LE16(u8 *a, u16 val)
 +{
 +      a[1] = val >> 8;
 +      a[0] = val & 0xff;
 +}
 +
 +static inline u32 WPA_GET_BE24(const u8 *a)
 +{
 +      return (a[0] << 16) | (a[1] << 8) | a[2];
 +}
 +
 +static inline void WPA_PUT_BE24(u8 *a, u32 val)
 +{
 +      a[0] = (val >> 16) & 0xff;
 +      a[1] = (val >> 8) & 0xff;
 +      a[2] = val & 0xff;
 +}
 +
 +static inline u32 WPA_GET_BE32(const u8 *a)
 +{
 +      return ((u32) a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
 +}
 +
 +static inline void WPA_PUT_BE32(u8 *a, u32 val)
 +{
 +      a[0] = (val >> 24) & 0xff;
 +      a[1] = (val >> 16) & 0xff;
 +      a[2] = (val >> 8) & 0xff;
 +      a[3] = val & 0xff;
 +}
 +
 +static inline u32 WPA_GET_LE32(const u8 *a)
 +{
 +      return ((u32) a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0];
 +}
 +
 +static inline void WPA_PUT_LE32(u8 *a, u32 val)
 +{
 +      a[3] = (val >> 24) & 0xff;
 +      a[2] = (val >> 16) & 0xff;
 +      a[1] = (val >> 8) & 0xff;
 +      a[0] = val & 0xff;
 +}
 +
 +static inline u64 WPA_GET_BE64(const u8 *a)
 +{
 +      return (((u64) a[0]) << 56) | (((u64) a[1]) << 48) |
 +              (((u64) a[2]) << 40) | (((u64) a[3]) << 32) |
 +              (((u64) a[4]) << 24) | (((u64) a[5]) << 16) |
 +              (((u64) a[6]) << 8) | ((u64) a[7]);
 +}
 +
 +static inline void WPA_PUT_BE64(u8 *a, u64 val)
 +{
 +      a[0] = val >> 56;
 +      a[1] = val >> 48;
 +      a[2] = val >> 40;
 +      a[3] = val >> 32;
 +      a[4] = val >> 24;
 +      a[5] = val >> 16;
 +      a[6] = val >> 8;
 +      a[7] = val & 0xff;
 +}
 +
 +static inline u64 WPA_GET_LE64(const u8 *a)
 +{
 +      return (((u64) a[7]) << 56) | (((u64) a[6]) << 48) |
 +              (((u64) a[5]) << 40) | (((u64) a[4]) << 32) |
 +              (((u64) a[3]) << 24) | (((u64) a[2]) << 16) |
 +              (((u64) a[1]) << 8) | ((u64) a[0]);
 +}
 +
 +static inline void WPA_PUT_LE64(u8 *a, u64 val)
 +{
 +      a[7] = val >> 56;
 +      a[6] = val >> 48;
 +      a[5] = val >> 40;
 +      a[4] = val >> 32;
 +      a[3] = val >> 24;
 +      a[2] = val >> 16;
 +      a[1] = val >> 8;
 +      a[0] = val & 0xff;
 +}
 +
 +
 +#ifndef ETH_ALEN
 +#define ETH_ALEN 6
 +#endif
 +#ifndef ETH_HLEN
 +#define ETH_HLEN 14
 +#endif
 +#ifndef IFNAMSIZ
 +#define IFNAMSIZ 16
 +#endif
 +#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
 +#ifndef ETH_P_PAE
 +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
 +#endif /* ETH_P_PAE */
 +#ifndef ETH_P_EAPOL
 +#define ETH_P_EAPOL ETH_P_PAE
 +#endif /* ETH_P_EAPOL */
 +#ifndef ETH_P_RSN_PREAUTH
 +#define ETH_P_RSN_PREAUTH 0x88c7
 +#endif /* ETH_P_RSN_PREAUTH */
 +#ifndef ETH_P_RRB
 +#define ETH_P_RRB 0x890D
 +#endif /* ETH_P_RRB */
 +
 +
 +#ifdef __GNUC__
 +#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b))))
 +#define STRUCT_PACKED __attribute__ ((packed))
 +#define UNUSED __attribute__ ((unused))
 +#else
 +#define PRINTF_FORMAT(a,b)
 +#define STRUCT_PACKED
 +#define UNUSED
 +#endif
 +
 +
 +#ifdef CONFIG_ANSI_C_EXTRA
 +
 +#if !defined(_MSC_VER) || _MSC_VER < 1400
 +/* snprintf - used in number of places; sprintf() is _not_ a good replacement
 + * due to possible buffer overflow; see, e.g.,
 + * http://www.ijs.si/software/snprintf/ for portable implementation of
 + * snprintf. */
 +int snprintf(char *str, size_t size, const char *format, ...);
 +
 +/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */
 +int vsnprintf(char *str, size_t size, const char *format, va_list ap);
 +#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */
 +
 +/* getopt - only used in main.c */
 +int getopt(int argc, char *const argv[], const char *optstring);
 +extern char *optarg;
 +extern int optind;
 +
 +#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF
 +#ifndef __socklen_t_defined
 +typedef int socklen_t;
 +#endif
 +#endif
 +
 +/* inline - define as __inline or just define it to be empty, if needed */
 +#ifdef CONFIG_NO_INLINE
 +#define inline
 +#else
 +#define inline __inline
 +#endif
 +
 +#ifndef __func__
 +#define __func__ "__func__ not defined"
 +#endif
 +
 +#ifndef bswap_16
 +#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff))
 +#endif
 +
 +#ifndef bswap_32
 +#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \
 +                   (((u32) (a) << 8) & 0xff0000) | \
 +                   (((u32) (a) >> 8) & 0xff00) | \
 +                   (((u32) (a) >> 24) & 0xff))
 +#endif
 +
 +#ifndef MSG_DONTWAIT
 +#define MSG_DONTWAIT 0
 +#endif
 +
 +#ifdef _WIN32_WCE
 +void perror(const char *s);
 +#endif /* _WIN32_WCE */
 +
 +#endif /* CONFIG_ANSI_C_EXTRA */
 +
 +#ifndef MAC2STR
 +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
 +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
 +
 +/*
 + * Compact form for string representation of MAC address
 + * To be used, e.g., for constructing dbus paths for P2P Devices
 + */
 +#define COMPACT_MACSTR "%02x%02x%02x%02x%02x%02x"
 +#endif
 +
 +#ifndef BIT
 +#define BIT(x) (1U << (x))
 +#endif
 +
 +/*
 + * Definitions for sparse validation
 + * (http://kernel.org/pub/linux/kernel/people/josh/sparse/)
 + */
 +#ifdef __CHECKER__
 +#define __force __attribute__((force))
++#undef __bitwise
 +#define __bitwise __attribute__((bitwise))
 +#else
 +#define __force
 +#define __bitwise
 +#endif
 +
 +typedef u16 __bitwise be16;
 +typedef u16 __bitwise le16;
 +typedef u32 __bitwise be32;
 +typedef u32 __bitwise le32;
 +typedef u64 __bitwise be64;
 +typedef u64 __bitwise le64;
 +
 +#ifndef __must_check
 +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
 +#define __must_check __attribute__((__warn_unused_result__))
 +#else
 +#define __must_check
 +#endif /* __GNUC__ */
 +#endif /* __must_check */
 +
 +#ifndef __maybe_unused
 +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
 +#define __maybe_unused __attribute__((unused))
 +#else
 +#define __maybe_unused
 +#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);
 +int hwaddr_aton2(const char *txt, u8 *addr);
 +int hex2byte(const char *hex);
 +int hexstr2bin(const char *hex, u8 *buf, size_t len);
 +void inc_byte_array(u8 *counter, size_t len);
 +void wpa_get_ntp_timestamp(u8 *buf);
 +int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...);
 +int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len,
 +                       char sep);
 +int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len);
 +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);
 +TCHAR * wpa_strdup_tchar(const char *str);
 +#else /* CONFIG_NATIVE_WINDOWS */
 +#define wpa_unicode2ascii_inplace(s) do { } while (0)
 +#define wpa_strdup_tchar(s) strdup((s))
 +#endif /* CONFIG_NATIVE_WINDOWS */
 +
 +void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len);
 +size_t printf_decode(u8 *buf, size_t maxlen, const char *str);
 +
 +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);
 +char * dup_binstr(const void *src, size_t len);
 +
 +static inline int is_zero_ether_addr(const u8 *a)
 +{
 +      return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]);
 +}
 +
 +static inline int is_broadcast_ether_addr(const u8 *a)
 +{
 +      return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff;
 +}
 +
 +static inline int is_multicast_ether_addr(const u8 *a)
 +{
 +      return a[0] & 0x01;
 +}
 +
 +#define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff"
 +
 +#include "wpa_debug.h"
 +
 +
 +struct wpa_freq_range_list {
 +      struct wpa_freq_range {
 +              unsigned int min;
 +              unsigned int max;
 +      } *range;
 +      unsigned int num;
 +};
 +
 +int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value);
 +int freq_range_list_includes(const struct wpa_freq_range_list *list,
 +                           unsigned int freq);
 +char * freq_range_list_str(const struct wpa_freq_range_list *list);
 +
 +int int_array_len(const int *a);
 +void int_array_concat(int **res, const int *a);
 +void int_array_sort_unique(int *a);
 +void int_array_add_unique(int **res, int a);
 +
 +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 +
 +void str_clear_free(char *str);
 +void bin_clear_free(void *bin, size_t len);
 +
 +int random_mac_addr(u8 *addr);
 +int random_mac_addr_keep_oui(u8 *addr);
 +
 +const char * cstr_token(const char *str, const char *delim, const char **last);
 +char * str_token(char *str, const char *delim, char **context);
 +size_t utf8_escape(const char *inp, size_t in_size,
 +                 char *outp, size_t out_size);
 +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
 + * networking socket uses that do not really result in a real problem and
 + * cannot be easily avoided with union-based type-punning due to struct
 + * definitions including another struct in system header files. To avoid having
 + * to fully disable strict-aliasing warnings, provide a mechanism to hide the
 + * typecast from aliasing for now. A cleaner solution will hopefully be found
 + * in the future to handle these cases.
 + */
 +void * __hide_aliasing_typecast(void *foo);
 +#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a))
 +
 +#ifdef CONFIG_VALGRIND
 +#include <valgrind/memcheck.h>
 +#define WPA_MEM_DEFINED(ptr, len) VALGRIND_MAKE_MEM_DEFINED((ptr), (len))
 +#else /* CONFIG_VALGRIND */
 +#define WPA_MEM_DEFINED(ptr, len) do { } while (0)
 +#endif /* CONFIG_VALGRIND */
 +
 +#endif /* COMMON_H */
@@@ -47,6 -47,12 +47,12 @@@ static void edit_read_char(int sock, vo
                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;
diff --combined libeap/src/utils/eloop.c
  #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 +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 +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 */
  }
  
  
+ #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;
  
                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;
                }
  
                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,
        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;
  }
  
  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)
        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 +611,7 @@@ static void eloop_sock_table_dispatch(s
        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,
  #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 +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;
  
                        _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
                                         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
  #ifdef CONFIG_ELOOP_EPOLL
                                   "epoll"
  #endif /* CONFIG_ELOOP_EPOLL */
+ #ifdef CONFIG_ELOOP_KQUEUE
+                                  "kqueue"
+ #endif /* CONFIG_ELOOP_EKQUEUE */
                                   , strerror(errno));
                        goto out;
                }
  
                eloop_process_pending_signals();
  
                /* check if some registered timeouts have occurred */
                timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
                                        list);
  #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 +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 +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
diff --combined libeap/src/utils/eloop.h
index 00233a0,0000000..ef5fd0a
mode 100644,000000..100644
--- /dev/null
@@@ -1,368 -1,0 +1,376 @@@
 +/*
 + * Event loop
 + * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
 + *
 + * This software may be distributed under the terms of the BSD license.
 + * See README for more details.
 + *
 + * This file defines an event loop interface that supports processing events
 + * from registered timeouts (i.e., do something after N seconds), sockets
 + * (e.g., a new packet available for reading), and signals. eloop.c is an
 + * implementation of this interface using select() and sockets. This is
 + * suitable for most UNIX/POSIX systems. When porting to other operating
 + * systems, it may be necessary to replace that implementation with OS specific
 + * mechanisms.
 + */
 +
 +#ifndef ELOOP_H
 +#define ELOOP_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +
 +/**
 + * ELOOP_ALL_CTX - eloop_cancel_timeout() magic number to match all timeouts
 + */
 +#define ELOOP_ALL_CTX (void *) -1
 +
 +/**
 + * eloop_event_type - eloop socket event type for eloop_register_sock()
 + * @EVENT_TYPE_READ: Socket has data available for reading
 + * @EVENT_TYPE_WRITE: Socket has room for new data to be written
 + * @EVENT_TYPE_EXCEPTION: An exception has been reported
 + */
 +typedef enum {
 +      EVENT_TYPE_READ = 0,
 +      EVENT_TYPE_WRITE,
 +      EVENT_TYPE_EXCEPTION
 +} eloop_event_type;
 +
 +/**
 + * eloop_sock_handler - eloop socket event callback type
 + * @sock: File descriptor number for the socket
 + * @eloop_ctx: Registered callback context data (eloop_data)
 + * @sock_ctx: Registered callback context data (user_data)
 + */
 +typedef void (*eloop_sock_handler)(int sock, void *eloop_ctx, void *sock_ctx);
 +
 +/**
 + * eloop_event_handler - eloop generic event callback type
 + * @eloop_ctx: Registered callback context data (eloop_data)
 + * @sock_ctx: Registered callback context data (user_data)
 + */
 +typedef void (*eloop_event_handler)(void *eloop_data, void *user_ctx);
 +
 +/**
 + * eloop_timeout_handler - eloop timeout event callback type
 + * @eloop_ctx: Registered callback context data (eloop_data)
 + * @sock_ctx: Registered callback context data (user_data)
 + */
 +typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx);
 +
 +/**
 + * eloop_signal_handler - eloop signal event callback type
 + * @sig: Signal number
 + * @signal_ctx: Registered callback context data (user_data from
 + * eloop_register_signal(), eloop_register_signal_terminate(), or
 + * eloop_register_signal_reconfig() call)
 + */
 +typedef void (*eloop_signal_handler)(int sig, void *signal_ctx);
 +
 +/**
 + * eloop_init() - Initialize global event loop data
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function must be called before any other eloop_* function.
 + */
 +int eloop_init(void);
 +
 +/**
 + * eloop_register_read_sock - Register handler for read events
 + * @sock: File descriptor number for the socket
 + * @handler: Callback function to be called when data is available for reading
 + * @eloop_data: Callback context data (eloop_ctx)
 + * @user_data: Callback context data (sock_ctx)
 + * Returns: 0 on success, -1 on failure
 + *
 + * Register a read socket notifier for the given file descriptor. The handler
 + * function will be called whenever data is available for reading from the
 + * socket. The handler function is responsible for clearing the event after
 + * having processed it in order to avoid eloop from calling the handler again
 + * for the same event.
 + */
 +int eloop_register_read_sock(int sock, eloop_sock_handler handler,
 +                           void *eloop_data, void *user_data);
 +
 +/**
 + * eloop_unregister_read_sock - Unregister handler for read events
 + * @sock: File descriptor number for the socket
 + *
 + * Unregister a read socket notifier that was previously registered with
 + * eloop_register_read_sock().
 + */
 +void eloop_unregister_read_sock(int sock);
 +
 +/**
 + * eloop_register_sock - Register handler for socket events
 + * @sock: File descriptor number for the socket
 + * @type: Type of event to wait for
 + * @handler: Callback function to be called when the event is triggered
 + * @eloop_data: Callback context data (eloop_ctx)
 + * @user_data: Callback context data (sock_ctx)
 + * Returns: 0 on success, -1 on failure
 + *
 + * Register an event notifier for the given socket's file descriptor. The
 + * handler function will be called whenever the that event is triggered for the
 + * socket. The handler function is responsible for clearing the event after
 + * having processed it in order to avoid eloop from calling the handler again
 + * for the same event.
 + */
 +int eloop_register_sock(int sock, eloop_event_type type,
 +                      eloop_sock_handler handler,
 +                      void *eloop_data, void *user_data);
 +
 +/**
 + * eloop_unregister_sock - Unregister handler for socket events
 + * @sock: File descriptor number for the socket
 + * @type: Type of event for which sock was registered
 + *
 + * Unregister a socket event notifier that was previously registered with
 + * eloop_register_sock().
 + */
 +void eloop_unregister_sock(int sock, eloop_event_type type);
 +
 +/**
 + * eloop_register_event - Register handler for generic events
 + * @event: Event to wait (eloop implementation specific)
 + * @event_size: Size of event data
 + * @handler: Callback function to be called when event is triggered
 + * @eloop_data: Callback context data (eloop_data)
 + * @user_data: Callback context data (user_data)
 + * Returns: 0 on success, -1 on failure
 + *
 + * Register an event handler for the given event. This function is used to
 + * register eloop implementation specific events which are mainly targeted for
 + * operating system specific code (driver interface and l2_packet) since the
 + * portable code will not be able to use such an OS-specific call. The handler
 + * function will be called whenever the event is triggered. The handler
 + * function is responsible for clearing the event after having processed it in
 + * order to avoid eloop from calling the handler again for the same event.
 + *
 + * In case of Windows implementation (eloop_win.c), event pointer is of HANDLE
 + * type, i.e., void*. The callers are likely to have 'HANDLE h' type variable,
 + * and they would call this function with eloop_register_event(h, sizeof(h),
 + * ...).
 + */
 +int eloop_register_event(void *event, size_t event_size,
 +                       eloop_event_handler handler,
 +                       void *eloop_data, void *user_data);
 +
 +/**
 + * eloop_unregister_event - Unregister handler for a generic event
 + * @event: Event to cancel (eloop implementation specific)
 + * @event_size: Size of event data
 + *
 + * Unregister a generic event notifier that was previously registered with
 + * eloop_register_event().
 + */
 +void eloop_unregister_event(void *event, size_t event_size);
 +
 +/**
 + * eloop_register_timeout - Register timeout
 + * @secs: Number of seconds to the timeout
 + * @usecs: Number of microseconds to the timeout
 + * @handler: Callback function to be called when timeout occurs
 + * @eloop_data: Callback context data (eloop_ctx)
 + * @user_data: Callback context data (sock_ctx)
 + * Returns: 0 on success, -1 on failure
 + *
 + * Register a timeout that will cause the handler function to be called after
 + * given time.
 + */
 +int eloop_register_timeout(unsigned int secs, unsigned int usecs,
 +                         eloop_timeout_handler handler,
 +                         void *eloop_data, void *user_data);
 +
 +/**
 + * eloop_cancel_timeout - Cancel timeouts
 + * @handler: Matching callback function
 + * @eloop_data: Matching eloop_data or %ELOOP_ALL_CTX to match all
 + * @user_data: Matching user_data or %ELOOP_ALL_CTX to match all
 + * Returns: Number of cancelled timeouts
 + *
 + * Cancel matching <handler,eloop_data,user_data> timeouts registered with
 + * eloop_register_timeout(). ELOOP_ALL_CTX can be used as a wildcard for
 + * cancelling all timeouts regardless of eloop_data/user_data.
 + */
 +int eloop_cancel_timeout(eloop_timeout_handler handler,
 +                       void *eloop_data, void *user_data);
 +
 +/**
 + * eloop_cancel_timeout_one - Cancel a single timeout
 + * @handler: Matching callback function
 + * @eloop_data: Matching eloop_data
 + * @user_data: Matching user_data
 + * @remaining: Time left on the cancelled timer
 + * Returns: Number of cancelled timeouts
 + *
 + * Cancel matching <handler,eloop_data,user_data> timeout registered with
 + * eloop_register_timeout() and return the remaining time left.
 + */
 +int eloop_cancel_timeout_one(eloop_timeout_handler handler,
 +                           void *eloop_data, void *user_data,
 +                           struct os_reltime *remaining);
 +
 +/**
 + * eloop_is_timeout_registered - Check if a timeout is already registered
 + * @handler: Matching callback function
 + * @eloop_data: Matching eloop_data
 + * @user_data: Matching user_data
 + * Returns: 1 if the timeout is registered, 0 if the timeout is not registered
 + *
 + * Determine if a matching <handler,eloop_data,user_data> timeout is registered
 + * with eloop_register_timeout().
 + */
 +int eloop_is_timeout_registered(eloop_timeout_handler handler,
 +                              void *eloop_data, void *user_data);
 +
 +/**
 + * eloop_deplete_timeout - Deplete a timeout that is already registered
 + * @req_secs: Requested number of seconds to the timeout
 + * @req_usecs: Requested number of microseconds to the timeout
 + * @handler: Matching callback function
 + * @eloop_data: Matching eloop_data
 + * @user_data: Matching user_data
 + * Returns: 1 if the timeout is depleted, 0 if no change is made, -1 if no
 + * timeout matched
 + *
 + * Find a registered matching <handler,eloop_data,user_data> timeout. If found,
 + * deplete the timeout if remaining time is more than the requested time.
 + */
 +int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
 +                        eloop_timeout_handler handler, void *eloop_data,
 +                        void *user_data);
 +
 +/**
 + * eloop_replenish_timeout - Replenish a timeout that is already registered
 + * @req_secs: Requested number of seconds to the timeout
 + * @req_usecs: Requested number of microseconds to the timeout
 + * @handler: Matching callback function
 + * @eloop_data: Matching eloop_data
 + * @user_data: Matching user_data
 + * Returns: 1 if the timeout is replenished, 0 if no change is made, -1 if no
 + * timeout matched
 + *
 + * Find a registered matching <handler,eloop_data,user_data> timeout. If found,
 + * replenish the timeout if remaining time is less than the requested time.
 + */
 +int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
 +                          eloop_timeout_handler handler, void *eloop_data,
 +                          void *user_data);
 +
 +/**
 + * eloop_register_signal - Register handler for signals
 + * @sig: Signal number (e.g., SIGHUP)
 + * @handler: Callback function to be called when the signal is received
 + * @user_data: Callback context data (signal_ctx)
 + * Returns: 0 on success, -1 on failure
 + *
 + * Register a callback function that will be called when a signal is received.
 + * The callback function is actually called only after the system signal
 + * handler has returned. This means that the normal limits for sighandlers
 + * (i.e., only "safe functions" allowed) do not apply for the registered
 + * callback.
 + */
 +int eloop_register_signal(int sig, eloop_signal_handler handler,
 +                        void *user_data);
 +
 +/**
 + * eloop_register_signal_terminate - Register handler for terminate signals
 + * @handler: Callback function to be called when the signal is received
 + * @user_data: Callback context data (signal_ctx)
 + * Returns: 0 on success, -1 on failure
 + *
 + * Register a callback function that will be called when a process termination
 + * signal is received. The callback function is actually called only after the
 + * system signal handler has returned. This means that the normal limits for
 + * sighandlers (i.e., only "safe functions" allowed) do not apply for the
 + * registered callback.
 + *
 + * This function is a more portable version of eloop_register_signal() since
 + * the knowledge of exact details of the signals is hidden in eloop
 + * implementation. In case of operating systems using signal(), this function
 + * registers handlers for SIGINT and SIGTERM.
 + */
 +int eloop_register_signal_terminate(eloop_signal_handler handler,
 +                                  void *user_data);
 +
 +/**
 + * eloop_register_signal_reconfig - Register handler for reconfig signals
 + * @handler: Callback function to be called when the signal is received
 + * @user_data: Callback context data (signal_ctx)
 + * Returns: 0 on success, -1 on failure
 + *
 + * Register a callback function that will be called when a reconfiguration /
 + * hangup signal is received. The callback function is actually called only
 + * after the system signal handler has returned. This means that the normal
 + * limits for sighandlers (i.e., only "safe functions" allowed) do not apply
 + * for the registered callback.
 + *
 + * This function is a more portable version of eloop_register_signal() since
 + * the knowledge of exact details of the signals is hidden in eloop
 + * implementation. In case of operating systems using signal(), this function
 + * registers a handler for SIGHUP.
 + */
 +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
 + * registered event handlers. This function is run after event loop has been
 + * initialized with event_init() and one or more events have been registered.
 + */
 +void eloop_run(void);
 +
 +/**
 + * eloop_terminate - Terminate event loop
 + *
 + * Terminate event loop even if there are registered events. This can be used
 + * to request the program to be terminated cleanly.
 + */
 +void eloop_terminate(void);
 +
 +/**
 + * eloop_destroy - Free any resources allocated for the event loop
 + *
 + * After calling eloop_destroy(), other eloop_* functions must not be called
 + * before re-running eloop_init().
 + */
 +void eloop_destroy(void);
 +
 +/**
 + * eloop_terminated - Check whether event loop has been terminated
 + * Returns: 1 = event loop terminate, 0 = event loop still running
 + *
 + * This function can be used to check whether eloop_terminate() has been called
 + * to request termination of the event loop. This is normally used to abort
 + * operations that may still be queued to be run when eloop_terminate() was
 + * called.
 + */
 +int eloop_terminated(void);
 +
 +/**
 + * eloop_wait_for_read_sock - Wait for a single reader
 + * @sock: File descriptor number for the socket
 + *
 + * Do a blocking wait for a single read socket.
 + */
 +void eloop_wait_for_read_sock(int sock);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* ELOOP_H */
@@@ -692,3 -692,9 +692,9 @@@ void eloop_wait_for_read_sock(int sock
        WSAEventSelect(sock, event, 0);
        WSACloseEvent(event);
  }
+ int eloop_sock_requeue(void)
+ {
+       return 0;
+ }
  #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,
@@@ -20,4 -20,10 +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 */
@@@ -26,6 -26,9 +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 +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))
  #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 +644,25 @@@ static void i2r_LogotypeImageInfo(Logot
        } 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 +1019,26 @@@ static int curl_cb_ssl_verify(int preve
        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 +1214,7 @@@ static int ocsp_resp_cb(SSL *s, void *a
                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)
                        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 +1333,16 @@@ static CURL * setup_curl_post(struct ht
  #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);
index 0000000,3bfe4ad..3bfe4ad
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,20 +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 */
diff --combined libeap/src/utils/os.h
@@@ -657,6 -657,10 +657,10 @@@ int os_exec(const char *program, const 
  #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
@@@ -372,6 -372,7 +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 +435,23 @@@ char * os_readfile(const char *name, si
  
  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;
   */
  
  #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 +114,11 @@@ typedef enum { SCARD_GSM_SIM, SCARD_USI
  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 +283,7 @@@ static int scard_parse_fsp_templ(unsign
        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 +512,12 @@@ static int scard_get_aid(struct scard_d
  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;
        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 +777,11 @@@ static long scard_transmit(struct 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 +1402,7 @@@ int scard_umts_auth(struct scard_data *
                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;
                }
                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;
                }
                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;
                }
@@@ -15,7 -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 */
@@@ -13,8 -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 */
  
@@@ -65,12 -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.
@@@ -67,7 -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
diff --combined libeap/src/utils/trace.c
@@@ -366,4 -366,13 +366,13 @@@ void wpa_trace_check_ref(const void *ad
        }
  }
  
+ void wpa_trace_deinit(void)
+ {
+ #ifdef WPA_TRACE_BFD
+       free(syms);
+       syms = NULL;
+ #endif /* WPA_TRACE_BFD */
+ }
  #endif /* WPA_TRACE */
diff --combined libeap/src/utils/trace.h
@@@ -66,4 -66,6 +66,6 @@@ void wpa_trace_dump_funcname(const cha
  
  #endif /* WPA_TRACE_BFD */
  
+ void wpa_trace_deinit(void);
  #endif /* TRACE_H */
@@@ -16,6 -16,7 +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,0000000..2983ad3
mode 100644,000000..100644
--- /dev/null
@@@ -1,860 -1,0 +1,862 @@@
-               if (strcmp(fstype, "debugfs") == 0) {
 +/*
 + * wpa_supplicant/hostapd / Debug prints
 + * Copyright (c) 2002-2013, 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"
 +
 +#ifdef CONFIG_DEBUG_SYSLOG
 +#include <syslog.h>
 +
 +static int wpa_debug_syslog = 0;
 +#endif /* CONFIG_DEBUG_SYSLOG */
 +
 +#ifdef CONFIG_DEBUG_LINUX_TRACING
 +#include <sys/types.h>
 +#include <sys/stat.h>
 +#include <fcntl.h>
 +#include <string.h>
 +#include <stdio.h>
 +
 +static FILE *wpa_debug_tracing_file = NULL;
 +
 +#define WPAS_TRACE_PFX "wpas <%d>: "
 +#endif /* CONFIG_DEBUG_LINUX_TRACING */
 +
 +
 +int wpa_debug_level = MSG_INFO;
 +int wpa_debug_show_keys = 0;
 +int wpa_debug_timestamp = 0;
 +
 +
 +#ifdef CONFIG_ANDROID_LOG
 +
 +#include <android/log.h>
 +
 +#ifndef ANDROID_LOG_NAME
 +#define ANDROID_LOG_NAME      "wpa_supplicant"
 +#endif /* ANDROID_LOG_NAME */
 +
 +static int wpa_to_android_level(int level)
 +{
 +      if (level == MSG_ERROR)
 +              return ANDROID_LOG_ERROR;
 +      if (level == MSG_WARNING)
 +              return ANDROID_LOG_WARN;
 +      if (level == MSG_INFO)
 +              return ANDROID_LOG_INFO;
 +      return ANDROID_LOG_DEBUG;
 +}
 +
 +#endif /* CONFIG_ANDROID_LOG */
 +
 +#ifndef CONFIG_NO_STDOUT_DEBUG
 +
 +#ifdef CONFIG_DEBUG_FILE
 +static FILE *out_file = NULL;
 +#endif /* CONFIG_DEBUG_FILE */
 +
 +
 +void wpa_debug_print_timestamp(void)
 +{
 +#ifndef CONFIG_ANDROID_LOG
 +      struct os_time tv;
 +
 +      if (!wpa_debug_timestamp)
 +              return;
 +
 +      os_get_time(&tv);
 +#ifdef CONFIG_DEBUG_FILE
 +      if (out_file) {
 +              fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
 +                      (unsigned int) tv.usec);
 +      } else
 +#endif /* CONFIG_DEBUG_FILE */
 +      printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
 +#endif /* CONFIG_ANDROID_LOG */
 +}
 +
 +
 +#ifdef CONFIG_DEBUG_SYSLOG
 +#ifndef LOG_HOSTAPD
 +#define LOG_HOSTAPD LOG_DAEMON
 +#endif /* LOG_HOSTAPD */
 +
 +void wpa_debug_open_syslog(void)
 +{
 +      openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_HOSTAPD);
 +      wpa_debug_syslog++;
 +}
 +
 +
 +void wpa_debug_close_syslog(void)
 +{
 +      if (wpa_debug_syslog)
 +              closelog();
 +}
 +
 +
 +static int syslog_priority(int level)
 +{
 +      switch (level) {
 +      case MSG_MSGDUMP:
 +      case MSG_DEBUG:
 +              return LOG_DEBUG;
 +      case MSG_INFO:
 +              return LOG_NOTICE;
 +      case MSG_WARNING:
 +              return LOG_WARNING;
 +      case MSG_ERROR:
 +              return LOG_ERR;
 +      }
 +      return LOG_INFO;
 +}
 +#endif /* CONFIG_DEBUG_SYSLOG */
 +
 +
 +#ifdef CONFIG_DEBUG_LINUX_TRACING
 +
 +int wpa_debug_open_linux_tracing(void)
 +{
 +      int mounts, trace_fd;
 +      char buf[4096] = {};
 +      ssize_t buflen;
 +      char *line, *tmp1, *path = NULL;
 +
 +      mounts = open("/proc/mounts", O_RDONLY);
 +      if (mounts < 0) {
 +              printf("no /proc/mounts\n");
 +              return -1;
 +      }
 +
 +      buflen = read(mounts, buf, sizeof(buf) - 1);
 +      close(mounts);
 +      if (buflen < 0) {
 +              printf("failed to read /proc/mounts\n");
 +              return -1;
 +      }
 +
 +      line = strtok_r(buf, "\n", &tmp1);
 +      while (line) {
 +              char *tmp2, *tmp_path, *fstype;
 +              /* "<dev> <mountpoint> <fs type> ..." */
 +              strtok_r(line, " ", &tmp2);
 +              tmp_path = strtok_r(NULL, " ", &tmp2);
 +              fstype = strtok_r(NULL, " ", &tmp2);
-       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;
-       }
++              if (fstype && strcmp(fstype, "debugfs") == 0) {
 +                      path = tmp_path;
 +                      break;
 +              }
 +
 +              line = strtok_r(NULL, "\n", &tmp1);
 +      }
 +
 +      if (path == NULL) {
 +              printf("debugfs mountpoint not found\n");
 +              return -1;
 +      }
 +
 +      snprintf(buf, sizeof(buf) - 1, "%s/tracing/trace_marker", path);
 +
 +      trace_fd = open(buf, O_WRONLY);
 +      if (trace_fd < 0) {
 +              printf("failed to open trace_marker file\n");
 +              return -1;
 +      }
 +      wpa_debug_tracing_file = fdopen(trace_fd, "w");
 +      if (wpa_debug_tracing_file == NULL) {
 +              close(trace_fd);
 +              printf("failed to fdopen()\n");
 +              return -1;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +void wpa_debug_close_linux_tracing(void)
 +{
 +      if (wpa_debug_tracing_file == NULL)
 +              return;
 +      fclose(wpa_debug_tracing_file);
 +      wpa_debug_tracing_file = NULL;
 +}
 +
 +#endif /* CONFIG_DEBUG_LINUX_TRACING */
 +
 +
 +/**
 + * wpa_printf - conditional printf
 + * @level: priority level (MSG_*) of the message
 + * @fmt: printf format string, followed by optional arguments
 + *
 + * This function is used to print conditional debugging and error messages. The
 + * output may be directed to stdout, stderr, and/or syslog based on
 + * configuration.
 + *
 + * Note: New line '\n' is added to the end of the text when printing to stdout.
 + */
 +void wpa_printf(int level, const char *fmt, ...)
 +{
 +      va_list ap;
 +
 +      va_start(ap, fmt);
 +      if (level >= wpa_debug_level) {
 +#ifdef CONFIG_ANDROID_LOG
 +              __android_log_vprint(wpa_to_android_level(level),
 +                                   ANDROID_LOG_NAME, fmt, ap);
 +#else /* CONFIG_ANDROID_LOG */
 +#ifdef CONFIG_DEBUG_SYSLOG
 +              if (wpa_debug_syslog) {
 +                      vsyslog(syslog_priority(level), fmt, ap);
 +              } else {
 +#endif /* CONFIG_DEBUG_SYSLOG */
 +              wpa_debug_print_timestamp();
 +#ifdef CONFIG_DEBUG_FILE
 +              if (out_file) {
 +                      vfprintf(out_file, fmt, ap);
 +                      fprintf(out_file, "\n");
 +              } else {
 +#endif /* CONFIG_DEBUG_FILE */
 +              vprintf(fmt, ap);
 +              printf("\n");
 +#ifdef CONFIG_DEBUG_FILE
 +              }
 +#endif /* CONFIG_DEBUG_FILE */
 +#ifdef CONFIG_DEBUG_SYSLOG
 +              }
 +#endif /* CONFIG_DEBUG_SYSLOG */
 +#endif /* CONFIG_ANDROID_LOG */
 +      }
 +      va_end(ap);
 +
 +#ifdef CONFIG_DEBUG_LINUX_TRACING
 +      if (wpa_debug_tracing_file != NULL) {
 +              va_start(ap, fmt);
 +              fprintf(wpa_debug_tracing_file, WPAS_TRACE_PFX, level);
 +              vfprintf(wpa_debug_tracing_file, fmt, ap);
 +              fprintf(wpa_debug_tracing_file, "\n");
 +              fflush(wpa_debug_tracing_file);
 +              va_end(ap);
 +      }
 +#endif /* CONFIG_DEBUG_LINUX_TRACING */
 +}
 +
 +
 +static void _wpa_hexdump(int level, const char *title, const u8 *buf,
 +                       size_t len, int show)
 +{
 +      size_t i;
 +
 +#ifdef CONFIG_DEBUG_LINUX_TRACING
 +      if (wpa_debug_tracing_file != NULL) {
 +              fprintf(wpa_debug_tracing_file,
 +                      WPAS_TRACE_PFX "%s - hexdump(len=%lu):",
 +                      level, title, (unsigned long) len);
 +              if (buf == NULL) {
 +                      fprintf(wpa_debug_tracing_file, " [NULL]\n");
 +              } else if (!show) {
 +                      fprintf(wpa_debug_tracing_file, " [REMOVED]\n");
 +              } else {
 +                      for (i = 0; i < len; i++)
 +                              fprintf(wpa_debug_tracing_file,
 +                                      " %02x", buf[i]);
 +              }
 +              fflush(wpa_debug_tracing_file);
 +      }
 +#endif /* CONFIG_DEBUG_LINUX_TRACING */
 +
 +      if (level < wpa_debug_level)
 +              return;
 +#ifdef CONFIG_ANDROID_LOG
 +      {
 +              const char *display;
 +              char *strbuf = NULL;
 +              size_t slen = len;
 +              if (buf == NULL) {
 +                      display = " [NULL]";
 +              } else if (len == 0) {
 +                      display = "";
 +              } else if (show && len) {
 +                      /* Limit debug message length for Android log */
 +                      if (slen > 32)
 +                              slen = 32;
 +                      strbuf = os_malloc(1 + 3 * slen);
 +                      if (strbuf == NULL) {
 +                              wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to "
 +                                         "allocate message buffer");
 +                              return;
 +                      }
 +
 +                      for (i = 0; i < slen; i++)
 +                              os_snprintf(&strbuf[i * 3], 4, " %02x",
 +                                          buf[i]);
 +
 +                      display = strbuf;
 +              } else {
 +                      display = " [REMOVED]";
 +              }
 +
 +              __android_log_print(wpa_to_android_level(level),
 +                                  ANDROID_LOG_NAME,
 +                                  "%s - hexdump(len=%lu):%s%s",
 +                                  title, (long unsigned int) len, display,
 +                                  len > slen ? " ..." : "");
 +              bin_clear_free(strbuf, 1 + 3 * slen);
 +              return;
 +      }
 +#else /* CONFIG_ANDROID_LOG */
 +#ifdef CONFIG_DEBUG_SYSLOG
 +      if (wpa_debug_syslog) {
 +              const char *display;
 +              char *strbuf = NULL;
 +
 +              if (buf == NULL) {
 +                      display = " [NULL]";
 +              } else if (len == 0) {
 +                      display = "";
 +              } else if (show && len) {
 +                      strbuf = os_malloc(1 + 3 * len);
 +                      if (strbuf == NULL) {
 +                              wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to "
 +                                         "allocate message buffer");
 +                              return;
 +                      }
 +
 +                      for (i = 0; i < len; i++)
 +                              os_snprintf(&strbuf[i * 3], 4, " %02x",
 +                                          buf[i]);
 +
 +                      display = strbuf;
 +              } else {
 +                      display = " [REMOVED]";
 +              }
 +
 +              syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s",
 +                     title, (unsigned long) len, display);
 +              bin_clear_free(strbuf, 1 + 3 * len);
 +              return;
 +      }
 +#endif /* CONFIG_DEBUG_SYSLOG */
 +      wpa_debug_print_timestamp();
 +#ifdef CONFIG_DEBUG_FILE
 +      if (out_file) {
 +              fprintf(out_file, "%s - hexdump(len=%lu):",
 +                      title, (unsigned long) len);
 +              if (buf == NULL) {
 +                      fprintf(out_file, " [NULL]");
 +              } else if (show) {
 +                      for (i = 0; i < len; i++)
 +                              fprintf(out_file, " %02x", buf[i]);
 +              } else {
 +                      fprintf(out_file, " [REMOVED]");
 +              }
 +              fprintf(out_file, "\n");
 +      } else {
 +#endif /* CONFIG_DEBUG_FILE */
 +      printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
 +      if (buf == NULL) {
 +              printf(" [NULL]");
 +      } else if (show) {
 +              for (i = 0; i < len; i++)
 +                      printf(" %02x", buf[i]);
 +      } else {
 +              printf(" [REMOVED]");
 +      }
 +      printf("\n");
 +#ifdef CONFIG_DEBUG_FILE
 +      }
 +#endif /* CONFIG_DEBUG_FILE */
 +#endif /* CONFIG_ANDROID_LOG */
 +}
 +
 +void wpa_hexdump(int level, const char *title, const void *buf, size_t len)
 +{
 +      _wpa_hexdump(level, title, buf, len, 1);
 +}
 +
 +
 +void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len)
 +{
 +      _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
 +}
 +
 +
 +static void _wpa_hexdump_ascii(int level, const char *title, const void *buf,
 +                             size_t len, int show)
 +{
 +      size_t i, llen;
 +      const u8 *pos = buf;
 +      const size_t line_len = 16;
 +
 +#ifdef CONFIG_DEBUG_LINUX_TRACING
 +      if (wpa_debug_tracing_file != NULL) {
 +              fprintf(wpa_debug_tracing_file,
 +                      WPAS_TRACE_PFX "%s - hexdump_ascii(len=%lu):",
 +                      level, title, (unsigned long) len);
 +              if (buf == NULL) {
 +                      fprintf(wpa_debug_tracing_file, " [NULL]\n");
 +              } else if (!show) {
 +                      fprintf(wpa_debug_tracing_file, " [REMOVED]\n");
 +              } else {
 +                      /* can do ascii processing in userspace */
 +                      for (i = 0; i < len; i++)
 +                              fprintf(wpa_debug_tracing_file,
 +                                      " %02x", pos[i]);
 +              }
 +              fflush(wpa_debug_tracing_file);
 +      }
 +#endif /* CONFIG_DEBUG_LINUX_TRACING */
 +
 +      if (level < wpa_debug_level)
 +              return;
 +#ifdef CONFIG_ANDROID_LOG
 +      _wpa_hexdump(level, title, buf, len, show);
 +#else /* CONFIG_ANDROID_LOG */
 +      wpa_debug_print_timestamp();
 +#ifdef CONFIG_DEBUG_FILE
 +      if (out_file) {
 +              if (!show) {
 +                      fprintf(out_file,
 +                              "%s - hexdump_ascii(len=%lu): [REMOVED]\n",
 +                              title, (unsigned long) len);
 +                      return;
 +              }
 +              if (buf == NULL) {
 +                      fprintf(out_file,
 +                              "%s - hexdump_ascii(len=%lu): [NULL]\n",
 +                              title, (unsigned long) len);
 +                      return;
 +              }
 +              fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
 +                      title, (unsigned long) len);
 +              while (len) {
 +                      llen = len > line_len ? line_len : len;
 +                      fprintf(out_file, "    ");
 +                      for (i = 0; i < llen; i++)
 +                              fprintf(out_file, " %02x", pos[i]);
 +                      for (i = llen; i < line_len; i++)
 +                              fprintf(out_file, "   ");
 +                      fprintf(out_file, "   ");
 +                      for (i = 0; i < llen; i++) {
 +                              if (isprint(pos[i]))
 +                                      fprintf(out_file, "%c", pos[i]);
 +                              else
 +                                      fprintf(out_file, "_");
 +                      }
 +                      for (i = llen; i < line_len; i++)
 +                              fprintf(out_file, " ");
 +                      fprintf(out_file, "\n");
 +                      pos += llen;
 +                      len -= llen;
 +              }
 +      } else {
 +#endif /* CONFIG_DEBUG_FILE */
 +      if (!show) {
 +              printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
 +                     title, (unsigned long) len);
 +              return;
 +      }
 +      if (buf == NULL) {
 +              printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
 +                     title, (unsigned long) len);
 +              return;
 +      }
 +      printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
 +      while (len) {
 +              llen = len > line_len ? line_len : len;
 +              printf("    ");
 +              for (i = 0; i < llen; i++)
 +                      printf(" %02x", pos[i]);
 +              for (i = llen; i < line_len; i++)
 +                      printf("   ");
 +              printf("   ");
 +              for (i = 0; i < llen; i++) {
 +                      if (isprint(pos[i]))
 +                              printf("%c", pos[i]);
 +                      else
 +                              printf("_");
 +              }
 +              for (i = llen; i < line_len; i++)
 +                      printf(" ");
 +              printf("\n");
 +              pos += llen;
 +              len -= llen;
 +      }
 +#ifdef CONFIG_DEBUG_FILE
 +      }
 +#endif /* CONFIG_DEBUG_FILE */
 +#endif /* CONFIG_ANDROID_LOG */
 +}
 +
 +
 +void wpa_hexdump_ascii(int level, const char *title, const void *buf,
 +                     size_t len)
 +{
 +      _wpa_hexdump_ascii(level, title, buf, len, 1);
 +}
 +
 +
 +void wpa_hexdump_ascii_key(int level, const char *title, const void *buf,
 +                         size_t len)
 +{
 +      _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
 +}
 +
 +
 +#ifdef CONFIG_DEBUG_FILE
 +static char *last_path = NULL;
 +#endif /* CONFIG_DEBUG_FILE */
 +
 +int wpa_debug_reopen_file(void)
 +{
 +#ifdef CONFIG_DEBUG_FILE
 +      int rv;
++      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;
 +#endif /* CONFIG_DEBUG_FILE */
 +}
 +
 +
 +int wpa_debug_open_file(const char *path)
 +{
 +#ifdef CONFIG_DEBUG_FILE
 +      if (!path)
 +              return 0;
 +
 +      if (last_path == NULL || os_strcmp(last_path, path) != 0) {
 +              /* Save our path to enable re-open */
 +              os_free(last_path);
 +              last_path = os_strdup(path);
 +      }
 +
 +      out_file = fopen(path, "a");
 +      if (out_file == NULL) {
 +              wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open "
 +                   "output file %s, using standard output", path);
 +              return -1;
 +      }
 +#ifndef _WIN32
 +      setvbuf(out_file, NULL, _IOLBF, 0);
 +#endif /* _WIN32 */
 +#else /* CONFIG_DEBUG_FILE */
 +      (void)path;
 +#endif /* CONFIG_DEBUG_FILE */
 +      return 0;
 +}
 +
 +
 +void wpa_debug_close_file(void)
 +{
 +#ifdef CONFIG_DEBUG_FILE
 +      if (!out_file)
 +              return;
 +      fclose(out_file);
 +      out_file = NULL;
 +      os_free(last_path);
 +      last_path = NULL;
 +#endif /* CONFIG_DEBUG_FILE */
 +}
 +
 +
 +void wpa_debug_setup_stdout(void)
 +{
 +#ifndef _WIN32
 +      setvbuf(stdout, NULL, _IOLBF, 0);
 +#endif /* _WIN32 */
 +}
 +
 +#endif /* CONFIG_NO_STDOUT_DEBUG */
 +
 +
 +#ifndef CONFIG_NO_WPA_MSG
 +static wpa_msg_cb_func wpa_msg_cb = NULL;
 +
 +void wpa_msg_register_cb(wpa_msg_cb_func func)
 +{
 +      wpa_msg_cb = func;
 +}
 +
 +
 +static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL;
 +
 +void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func)
 +{
 +      wpa_msg_ifname_cb = func;
 +}
 +
 +
 +void wpa_msg(void *ctx, int level, const char *fmt, ...)
 +{
 +      va_list ap;
 +      char *buf;
 +      int buflen;
 +      int len;
 +      char prefix[130];
 +
 +      va_start(ap, fmt);
 +      buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
 +      va_end(ap);
 +
 +      buf = os_malloc(buflen);
 +      if (buf == NULL) {
 +              wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message "
 +                         "buffer");
 +              return;
 +      }
 +      va_start(ap, fmt);
 +      prefix[0] = '\0';
 +      if (wpa_msg_ifname_cb) {
 +              const char *ifname = wpa_msg_ifname_cb(ctx);
 +              if (ifname) {
 +                      int res = os_snprintf(prefix, sizeof(prefix), "%s: ",
 +                                            ifname);
 +                      if (os_snprintf_error(sizeof(prefix), res))
 +                              prefix[0] = '\0';
 +              }
 +      }
 +      len = vsnprintf(buf, buflen, fmt, ap);
 +      va_end(ap);
 +      wpa_printf(level, "%s%s", prefix, buf);
 +      if (wpa_msg_cb)
 +              wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len);
 +      bin_clear_free(buf, buflen);
 +}
 +
 +
 +void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
 +{
 +      va_list ap;
 +      char *buf;
 +      int buflen;
 +      int len;
 +
 +      if (!wpa_msg_cb)
 +              return;
 +
 +      va_start(ap, fmt);
 +      buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
 +      va_end(ap);
 +
 +      buf = os_malloc(buflen);
 +      if (buf == NULL) {
 +              wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate "
 +                         "message buffer");
 +              return;
 +      }
 +      va_start(ap, fmt);
 +      len = vsnprintf(buf, buflen, fmt, ap);
 +      va_end(ap);
 +      wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len);
 +      bin_clear_free(buf, buflen);
 +}
 +
 +
 +void wpa_msg_global(void *ctx, int level, const char *fmt, ...)
 +{
 +      va_list ap;
 +      char *buf;
 +      int buflen;
 +      int len;
 +
 +      va_start(ap, fmt);
 +      buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
 +      va_end(ap);
 +
 +      buf = os_malloc(buflen);
 +      if (buf == NULL) {
 +              wpa_printf(MSG_ERROR, "wpa_msg_global: Failed to allocate "
 +                         "message buffer");
 +              return;
 +      }
 +      va_start(ap, fmt);
 +      len = vsnprintf(buf, buflen, fmt, ap);
 +      va_end(ap);
 +      wpa_printf(level, "%s", buf);
 +      if (wpa_msg_cb)
 +              wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len);
 +      bin_clear_free(buf, buflen);
 +}
 +
 +
 +void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...)
 +{
 +      va_list ap;
 +      char *buf;
 +      int buflen;
 +      int len;
 +
 +      if (!wpa_msg_cb)
 +              return;
 +
 +      va_start(ap, fmt);
 +      buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
 +      va_end(ap);
 +
 +      buf = os_malloc(buflen);
 +      if (buf == NULL) {
 +              wpa_printf(MSG_ERROR,
 +                         "wpa_msg_global_ctrl: Failed to allocate message buffer");
 +              return;
 +      }
 +      va_start(ap, fmt);
 +      len = vsnprintf(buf, buflen, fmt, ap);
 +      va_end(ap);
 +      wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len);
 +      bin_clear_free(buf, buflen);
 +}
 +
 +
 +void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...)
 +{
 +      va_list ap;
 +      char *buf;
 +      int buflen;
 +      int len;
 +
 +      va_start(ap, fmt);
 +      buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
 +      va_end(ap);
 +
 +      buf = os_malloc(buflen);
 +      if (buf == NULL) {
 +              wpa_printf(MSG_ERROR, "wpa_msg_no_global: Failed to allocate "
 +                         "message buffer");
 +              return;
 +      }
 +      va_start(ap, fmt);
 +      len = vsnprintf(buf, buflen, fmt, ap);
 +      va_end(ap);
 +      wpa_printf(level, "%s", buf);
 +      if (wpa_msg_cb)
 +              wpa_msg_cb(ctx, level, WPA_MSG_NO_GLOBAL, buf, len);
 +      bin_clear_free(buf, buflen);
 +}
 +
 +
 +void wpa_msg_global_only(void *ctx, int level, const char *fmt, ...)
 +{
 +      va_list ap;
 +      char *buf;
 +      int buflen;
 +      int len;
 +
 +      va_start(ap, fmt);
 +      buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
 +      va_end(ap);
 +
 +      buf = os_malloc(buflen);
 +      if (buf == NULL) {
 +              wpa_printf(MSG_ERROR, "%s: Failed to allocate message buffer",
 +                         __func__);
 +              return;
 +      }
 +      va_start(ap, fmt);
 +      len = vsnprintf(buf, buflen, fmt, ap);
 +      va_end(ap);
 +      wpa_printf(level, "%s", buf);
 +      if (wpa_msg_cb)
 +              wpa_msg_cb(ctx, level, WPA_MSG_ONLY_GLOBAL, buf, len);
 +      os_free(buf);
 +}
 +
 +#endif /* CONFIG_NO_WPA_MSG */
 +
 +
 +#ifndef CONFIG_NO_HOSTAPD_LOGGER
 +static hostapd_logger_cb_func hostapd_logger_cb = NULL;
 +
 +void hostapd_logger_register_cb(hostapd_logger_cb_func func)
 +{
 +      hostapd_logger_cb = func;
 +}
 +
 +
 +void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
 +                  const char *fmt, ...)
 +{
 +      va_list ap;
 +      char *buf;
 +      int buflen;
 +      int len;
 +
 +      va_start(ap, fmt);
 +      buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
 +      va_end(ap);
 +
 +      buf = os_malloc(buflen);
 +      if (buf == NULL) {
 +              wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate "
 +                         "message buffer");
 +              return;
 +      }
 +      va_start(ap, fmt);
 +      len = vsnprintf(buf, buflen, fmt, ap);
 +      va_end(ap);
 +      if (hostapd_logger_cb)
 +              hostapd_logger_cb(ctx, addr, module, level, buf, len);
 +      else if (addr)
 +              wpa_printf(MSG_DEBUG, "hostapd_logger: STA " MACSTR " - %s",
 +                         MAC2STR(addr), buf);
 +      else
 +              wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf);
 +      bin_clear_free(buf, buflen);
 +}
 +#endif /* CONFIG_NO_HOSTAPD_LOGGER */
 +
 +
 +const char * debug_level_str(int level)
 +{
 +      switch (level) {
 +      case MSG_EXCESSIVE:
 +              return "EXCESSIVE";
 +      case MSG_MSGDUMP:
 +              return "MSGDUMP";
 +      case MSG_DEBUG:
 +              return "DEBUG";
 +      case MSG_INFO:
 +              return "INFO";
 +      case MSG_WARNING:
 +              return "WARNING";
 +      case MSG_ERROR:
 +              return "ERROR";
 +      default:
 +              return "?";
 +      }
 +}
 +
 +
 +int str_to_debug_level(const char *s)
 +{
 +      if (os_strcasecmp(s, "EXCESSIVE") == 0)
 +              return MSG_EXCESSIVE;
 +      if (os_strcasecmp(s, "MSGDUMP") == 0)
 +              return MSG_MSGDUMP;
 +      if (os_strcasecmp(s, "DEBUG") == 0)
 +              return MSG_DEBUG;
 +      if (os_strcasecmp(s, "INFO") == 0)
 +              return MSG_INFO;
 +      if (os_strcasecmp(s, "WARNING") == 0)
 +              return MSG_WARNING;
 +      if (os_strcasecmp(s, "ERROR") == 0)
 +              return MSG_ERROR;
 +      return -1;
 +}
@@@ -310,3 -310,33 +310,33 @@@ void wpabuf_printf(struct wpabuf *buf, 
                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,0000000..0458e3f
mode 100644,000000..100644
--- /dev/null
@@@ -1,171 -1,0 +1,172 @@@
-       return (const u8 *)wpabuf_head(buf);
 +/*
 + * Dynamic data buffer
 + * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
 + *
 + * This software may be distributed under the terms of the BSD license.
 + * See README for more details.
 + */
 +
 +#ifndef WPABUF_H
 +#define WPABUF_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +/* wpabuf::buf is a pointer to external data */
 +#define WPABUF_FLAG_EXT_DATA BIT(0)
 +
 +/*
 + * Internal data structure for wpabuf. Please do not touch this directly from
 + * elsewhere. This is only defined in header file to allow inline functions
 + * from this file to access data.
 + */
 +struct wpabuf {
 +      size_t size; /* total size of the allocated buffer */
 +      size_t used; /* length of data in the buffer */
 +      u8 *buf; /* pointer to the head of the buffer */
 +      unsigned int flags;
 +      /* optionally followed by the allocated buffer */
 +};
 +
 +
 +int wpabuf_resize(struct wpabuf **buf, size_t add_len);
 +struct wpabuf * wpabuf_alloc(size_t len);
 +struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len);
 +struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len);
 +struct wpabuf * wpabuf_dup(const struct wpabuf *src);
 +void wpabuf_free(struct wpabuf *buf);
 +void wpabuf_clear_free(struct wpabuf *buf);
 +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);
 +
 +
 +/**
 + * wpabuf_size - Get the currently allocated size of a wpabuf buffer
 + * @buf: wpabuf buffer
 + * Returns: Currently allocated size of the buffer
 + */
 +static inline size_t wpabuf_size(const struct wpabuf *buf)
 +{
 +      return buf->size;
 +}
 +
 +/**
 + * wpabuf_len - Get the current length of a wpabuf buffer data
 + * @buf: wpabuf buffer
 + * Returns: Currently used length of the buffer
 + */
 +static inline size_t wpabuf_len(const struct wpabuf *buf)
 +{
 +      return buf->used;
 +}
 +
 +/**
 + * wpabuf_tailroom - Get size of available tail room in the end of the buffer
 + * @buf: wpabuf buffer
 + * Returns: Tail room (in bytes) of available space in the end of the buffer
 + */
 +static inline size_t wpabuf_tailroom(const struct wpabuf *buf)
 +{
 +      return buf->size - buf->used;
 +}
 +
 +/**
 + * wpabuf_head - Get pointer to the head of the buffer data
 + * @buf: wpabuf buffer
 + * Returns: Pointer to the head of the buffer data
 + */
 +static inline const void * wpabuf_head(const struct wpabuf *buf)
 +{
 +      return buf->buf;
 +}
 +
 +static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)
 +{
-       return (u8 *)wpabuf_mhead(buf);
++      return (const u8 *) wpabuf_head(buf);
 +}
 +
 +/**
 + * wpabuf_mhead - Get modifiable pointer to the head of the buffer data
 + * @buf: wpabuf buffer
 + * Returns: Pointer to the head of the buffer data
 + */
 +static inline void * wpabuf_mhead(struct wpabuf *buf)
 +{
 +      return buf->buf;
 +}
 +
 +static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf)
 +{
-       u8 *pos = (u8 *)wpabuf_put(buf, 1);
++      return (u8 *) wpabuf_mhead(buf);
 +}
 +
 +static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data)
 +{
-       u8 *pos = (u8 *)wpabuf_put(buf, 2);
++      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, 4);
++      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, 2);
++      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, 3);
++      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, 4);
++      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);
 +      WPA_PUT_BE32(pos, data);
 +}
 +
 +static inline void wpabuf_put_data(struct wpabuf *buf, const void *data,
 +                                 size_t len)
 +{
 +      if (data)
 +              os_memcpy(wpabuf_put(buf, len), data, len);
 +}
 +
 +static inline void wpabuf_put_buf(struct wpabuf *dst,
 +                                const struct wpabuf *src)
 +{
 +      wpabuf_put_data(dst, wpabuf_head(src), wpabuf_len(src));
 +}
 +
 +static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len)
 +{
 +      buf->buf = (u8 *) data;
 +      buf->flags = WPABUF_FLAG_EXT_DATA;
 +      buf->size = buf->used = len;
 +}
 +
 +static inline void wpabuf_put_str(struct wpabuf *dst, const char *str)
 +{
 +      wpabuf_put_data(dst, str, os_strlen(str));
 +}
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* WPABUF_H */
@@@ -212,6 -212,8 +212,8 @@@ char * xml_node_to_str(struct xml_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, '>');
diff --combined libeap/src/wps/wps.c
  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 +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);
diff --combined libeap/src/wps/wps.h
@@@ -1,6 -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 +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 +837,7 @@@ int wps_build_credential_wrap(struct wp
  
  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);
  
@@@ -1,6 -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 +298,16 @@@ int wps_build_auth_type_flags(struct wp
        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 +319,16 @@@ int wps_build_encr_type_flags(struct wp
  {
        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 +413,8 @@@ int wps_build_oob_dev_pw(struct wpabuf 
                   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",
@@@ -83,10 -83,10 +83,10 @@@ static int wps_parse_vendor_ext_wfa(str
        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;
@@@ -229,6 -229,16 +229,16 @@@ static int wps_workaround_cred_key(stru
                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;
  }
  
@@@ -90,7 -90,7 +90,7 @@@ int wps_derive_keys(struct wps_data *wp
        }
  
        /* 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);
        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;
  }
  
  
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 +176,7 @@@ struct wpabuf * wps_decrypt_encr_settin
        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;
        }
  
        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 +238,18 @@@ unsigned int wps_pin_valid(unsigned in
   * 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 +376,7 @@@ struct wpabuf * wps_get_oob_cred(struc
            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 +424,7 @@@ struct wpabuf * wps_build_nfc_pw_token(
            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 +661,7 @@@ int wps_nfc_gen_dh(struct wpabuf **pubk
  
        wpabuf_free(*pubkey);
        *pubkey = pub;
-       wpabuf_free(*privkey);
+       wpabuf_clear_free(*privkey);
        *privkey = priv;
  
        return 0;
@@@ -691,7 -692,7 +692,7 @@@ struct wpabuf * wps_nfc_token_gen(int n
        }
  
        *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);
  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 */
@@@ -173,7 -173,8 +173,8 @@@ static struct wpabuf * wps_build_m3(str
                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 +225,11 @@@ static struct wpabuf * wps_build_m5(str
            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 +395,11 @@@ static struct wpabuf * wps_build_m7(str
            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 +1008,11 @@@ static enum wps_process_res wps_process
                                              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 +1113,7 @@@ static enum wps_process_res wps_process
        }
  
        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;
        }
        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 +1166,7 @@@ static enum wps_process_res wps_process
        }
  
        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;
        }
        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 +1237,7 @@@ static enum wps_process_res wps_process
  
        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;
        }
                              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;
diff --combined libeap/src/wps/wps_i.h
@@@ -132,8 -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,
@@@ -9,6 -9,7 +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 +18,7 @@@
        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 */
@@@ -1,6 -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 +703,7 @@@ void wps_registrar_deinit(struct wps_re
        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 +1577,13 @@@ int wps_build_credential_wrap(struct wp
        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 +1606,9 @@@ int wps_build_cred(struct wps_data *wps
        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)
        }
        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 +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 +1796,7 @@@ static struct wpabuf * wps_build_ap_cre
        }
  
        if (wps_build_ap_settings(wps, plain)) {
-               wpabuf_free(plain);
+               wpabuf_clear_free(plain);
                wpabuf_free(msg);
                return NULL;
        }
        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 +1864,10 @@@ static struct wpabuf * wps_build_m2(str
                    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 +1928,8 @@@ static struct wpabuf * wps_build_m4(str
  
        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)
            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 +1985,11 @@@ static struct wpabuf * wps_build_m6(str
            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 +2022,11 @@@ static struct wpabuf * wps_build_m8(str
            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 +2355,23 @@@ static int wps_process_auth_type_flags(
  
        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 +2786,7 @@@ static enum wps_process_res wps_process
        }
  
        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;
        }
        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 +2938,7 @@@ static enum wps_process_res wps_process
  
        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;
        }
            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;
@@@ -1082,6 -1082,7 +1082,7 @@@ upnp_wps_get_iface(struct upnp_wps_devi
  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;
                                            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 +1147,7 @@@ upnp_wps_device_init(struct upnp_wps_de
        }
        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;
  #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;
  };
  
@@@ -109,8 -109,7 +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 */
  };
  
  /*
@@@ -100,12 -100,6 +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.
@@@ -300,7 -300,8 +300,8 @@@ static void http_put_empty(struct wpabu
   * 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 +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)
        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
         * 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;
                *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 +495,8 @@@ web_process_put_message(struct upnp_wps
        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);
        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;
@@@ -12,6 -12,7 +12,7 @@@ ca_cert=auth_serv/ca.pe
  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
@@@ -12,6 -12,7 +12,7 @@@ ca_cert=auth_serv/ca.pe
  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
@@@ -11,6 -11,9 +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 +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 +41,18 @@@ radius_accept_attr=64:d:1
  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 +63,8 @@@ radius_accept_attr=25:x:001122334455667
  "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 +75,8 @@@ radius_accept_attr=89:s:macacl-cui-tes
  "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
  "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]
@@@ -2,3 -2,6 +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
@@@ -31,7 -31,7 +31,7 @@@ cert_opt      = ca_defaul
  
  copy_extensions = copy
  
- default_days  = 365
+ default_days  = 3650
  default_crl_days= 30
  default_md    = default
  preserve      = no
@@@ -1,13 -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-----
@@@ -2,7 -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-----
@@@ -1,30 -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
              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-----
@@@ -2,7 -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-----
@@@ -1,30 -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
              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-----
@@@ -1,15 -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-----
@@@ -2,8 -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-----
@@@ -1,32 -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
              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-----
@@@ -2,8 -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-----
@@@ -1,32 -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
              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-----
@@@ -8,6 -8,9 +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
@@@ -4,5 -4,5 +4,5 @@@ V        140102000000Z           D8D3E3A6CBE3CCCA        unkno
  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
@@@ -4,5 -4,5 +4,5 @@@ V        140102000000Z           D8D3E3A6CBE3CCCA        unkno
  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..974ed1e
Binary files differ
@@@ -1,12 -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
              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..4b2fd1f
Binary files differ
@@@ -1,12 -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
  
              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 +55,8 @@@ Vjgm36k6lRWTphbt0h60tcCoYY6uEAT95ibKSg2
  AaOBpDCBoTAJBgNVHRMEAjAAMB0GA1UdDgQWBBTHxu/1YdKgCIFqa0Qs9XL32t5b
  uTAfBgNVHSMEGDAWgBS4kt79ihizMMOfVfMzXbTIKYpBFDA1BggrBgEFBQcBAQQp
  MCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9zZXJ2ZXIudzEuZmk6ODg4OC8wHQYDVR0l
- BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA0GCSqGSIb3DQEBBQUAA4GBALg1jLYY
- rOn2yyzf2FCISFAzUPqSIZS3ggQMwsQWvN0vdfidGtUaUNx8l3gQJTO6AW1HuChP
- fNjEpoUN9YRfMWgeRBMW/c6LmDlGA96qYhburqoVJ0rynZwfWmEE7zp7xFo9odAu
- 9jHqkn5fa03TBtLuqUpWaDh2JVjgB/vV2Pqw
+ BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4GBACOR99oq
+ faQsgeEOP0P7zGc9EfJLuCwsQdCQEzhqWhLqp/FStEteupi5tDb8/ohTLUr3CI9A
+ SaqQYKfuXzivZhH4MStIuX6YHO04aICyGH7pTwdIfqWr++RGpiznZmeTvUF/SdjB
+ 5RwIxe0XDPTZOti7FUpExsdCOr/FD9+OoQV/
  -----END CERTIFICATE-----
@@@ -1,12 -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
  
              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 +55,8 @@@ hFN4dk0Wt7jfCXLnhyZ0LATKxc4p9bTO2yjrRUd
  AaOBmjCBlzAJBgNVHRMEAjAAMB0GA1UdDgQWBBQzFp07FxWCKzRuOOjMIr9Jp14q
  KzAfBgNVHSMEGDAWgBS4kt79ihizMMOfVfMzXbTIKYpBFDA1BggrBgEFBQcBAQQp
  MCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9zZXJ2ZXIudzEuZmk6ODg4OC8wEwYDVR0l
- BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADgYEASYjdBCOGIknLc1ea99hx
- zzNizCSo6a7NIpEWLxeG/AmPecCTIuZ3JSGMRTijTQdu0MPKSYo+hh9O3XKT80d9
- w1uV8ZhQpU427XGUOlXuriHjJz2Q30q+9ZOl4gsaPX3HApjBF2eem6IdZfyBWXIr
ialHMa0wwII5R6LS6w5x1jw=
+ BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADgYEAoB6np8753w1r2OvN+GFp
+ VjcMFZEHo+i6xJ2/EB+yIUhZt56AMIBW6/rn9geJqwS+nLCWgJ0SkCMgtvM8Pwgc
+ AGctn7G9cs7tZHTVzIblJqXxP5+NlrWmbpQQhMuMRcOGx3lIiWr8GwAjrIS6vhNz
gnMAwfvhirx61tAZP0MRgiY=
  -----END CERTIFICATE-----
@@@ -1,12 -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
  
              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 +55,8 @@@ ZmXkgwfKajal5iD2XJkn22PlhtgrfB2QRIEiIXc
  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-----
@@@ -1,12 -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
              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 +58,7 @@@ o4GzMIGwMAkGA1UdEwQCMAAwHQYDVR0OBBYEFDF
  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..a2f360a
Binary files differ
@@@ -1,12 -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
              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 +55,8 @@@
  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..a1d6366
Binary files differ
index eb17d9c,67ef81c..67ef81c
Binary files differ
index 953d7cb,c9ed0b4..c9ed0b4
Binary files differ
@@@ -43,6 -43,7 +43,7 @@@ CONFIG_TLSV11=
  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 +100,7 @@@ CONFIG_SUITEB=
  #LIBS_h += -fsanitize=undefined
  #LIBS_n += -fsanitize=undefined
  #LIBS_c += -fsanitize=undefined
+ CONFIG_MBO=y
+ CONFIG_IAPP=y
+ CONFIG_TAXONOMY=y
@@@ -32,7 -32,10 +32,10 @@@ Install Ubuntu Server 14.04.1 in the vi
  
  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,
@@@ -60,6 -60,7 +60,7 @@@ CONFIG_PEERKEY=
  CONFIG_IEEE80211W=y
  CONFIG_IEEE80211R=y
  CONFIG_IEEE80211N=y
+ CONFIG_IEEE80211AC=y
  
  CONFIG_DEBUG_FILE=y
  
@@@ -83,6 -84,8 +84,8 @@@ CONFIG_MESH=
  CONFIG_P2P=y
  CONFIG_WIFI_DISPLAY=y
  
+ CONFIG_ACS=y
  CONFIG_BGSCAN_SIMPLE=y
  CONFIG_BGSCAN_LEARN=y
  
@@@ -142,3 -145,4 +145,4 @@@ CONFIG_SUITEB=
  ##LIBS += -fno-sanitize-recover
  #LIBS_c += -fsanitize=undefined
  #LIBS_p += -fsanitize=undefined
+ CONFIG_MBO=y
@@@ -5,7 -5,6 +5,6 @@@
  # See README for more details.
  
  import logging
- import subprocess
  import os
  import signal
  import time
@@@ -256,11 -255,13 +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):
          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"):
              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
          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)
                  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 +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
      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 +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
          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):
              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):
          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:
              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
  
  
          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()
@@@ -10,6 -10,9 +10,9 @@@ import loggin
  import binascii
  import struct
  import wpaspy
+ import remotehost
+ import utils
+ import subprocess
  
  logger = logging.getLogger()
  hapd_ctrl = '/var/run/hostapd'
@@@ -19,20 -22,50 +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
                  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):
      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
                  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()
              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 +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)
@@@ -5,7 -5,6 +5,6 @@@
  # See README for more details.
  
  import os
- import subprocess
  import time
  import logging
  logger = logging.getLogger()
@@@ -25,6 -24,11 +24,11 @@@ def run_connectivity_test(dev1, dev2, t
      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"
              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:
              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 +173,8 @@@ def test_connectivity_sta(dev1, dev2, d
  
  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")
@@@ -346,7 -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")
@@@ -252,13 -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:
              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)
              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"
                      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")
                  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])
                  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)
@@@ -103,7 -103,7 +103,7 @@@ f
  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 +136,19 @@@ if [ ! -r $LOGDIR/ocsp-server-cache.de
      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 \
        -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 &
  
@@@ -6,7 -6,6 +6,6 @@@
  
  import logging
  logger = logging.getLogger()
- import subprocess
  import time
  
  import hostapd
@@@ -16,19 -15,17 +15,17 @@@ from test_ap_ht import clear_scan_cach
  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 +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 +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")
  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)
  
  
  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 +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:
          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):
          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:
          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):
          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:
          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):
      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")
@@@ -4,6 -4,7 +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 +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",
                 "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")
      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",
                 "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:
      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])
                 "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:
      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 +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])
                 "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()
      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")
@@@ -4,65 -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 +74,7 @@@
      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])
@@@ -4,6 -4,7 +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 +13,12 @@@ import hwsim_util
  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):
          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 +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])
  
      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])
  
      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 +79,7 @@@
      # 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 +93,7 @@@
      # 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])
      # 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])
      # 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])
  
      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)
@@@ -4,6 -4,7 +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 +13,20 @@@ import o
  
  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 +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:
          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)
  
  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 +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)
  
  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)
              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")
          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):
  
  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'
      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)
  
      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()
      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()
@@@ -12,12 -12,22 +12,22 @@@ import subproces
  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 +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"):
  
  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:
                  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",
  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",
  
      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 +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):
      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")
      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()
      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()
  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",
          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 +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",
      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"),
                (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 +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):
      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")
      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()
      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()
  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 +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",
      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)
      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",
          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'")
  
      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 +1104,8 @@@ def test_ap_wpa2_eap_aka_prime_sql(dev
      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")
      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()
      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()
      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 +1200,8 @@@ def test_ap_wpa2_eap_ttls_pap_subject_m
      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",
  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 +1225,8 @@@ def test_ap_wpa2_eap_ttls_chap(dev, apd
      """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 +1237,8 @@@ def test_ap_wpa2_eap_ttls_chap_altsubje
      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 +1248,12 @@@ def test_ap_wpa2_eap_ttls_chap_incorrec
      """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)
  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")
  
      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")
  
  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 +1384,12 @@@ def test_ap_wpa2_eap_ttls_mschapv2_inco
      """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 +1398,31 @@@ def test_ap_wpa2_eap_ttls_mschapv2_utf8
      """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)
  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)
  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)
  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)
              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 +1504,8 @@@ def test_ap_wpa2_eap_ttls_eap_md5_incor
      """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 +1514,8 @@@ def test_ap_wpa2_eap_ttls_eap_md5_no_pa
      """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 +1524,9 @@@ def test_ap_wpa2_eap_ttls_eap_md5_serve
      """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 +1549,8 @@@ def test_ap_wpa2_eap_ttls_eap_mschapv2(
      """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)
  
      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 +1567,8 @@@ def test_ap_wpa2_eap_ttls_eap_mschapv2_
      """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 +1577,9 @@@ def test_ap_wpa2_eap_ttls_eap_mschapv2_
      """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)
  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")
  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 +1649,8 @@@ def test_ap_wpa2_eap_fast_eap_aka(dev, 
      """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 +1661,28 @@@ def test_ap_wpa2_eap_peap_eap_mschapv2(
      """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 +1691,8 @@@ def test_ap_wpa2_eap_peap_eap_mschapv2_
      """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 +1702,8 @@@ def test_ap_wpa2_eap_peap_eap_mschapv2_
      """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 +1712,19 @@@ def test_ap_wpa2_eap_peap_crypto_bindin
      """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 +1733,9 @@@ def test_ap_wpa2_eap_peap_crypto_bindin
      """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 +1745,30 @@@ def test_ap_wpa2_eap_peap_params(dev, a
      """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")
      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",
  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")
      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")
      # 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")
  
  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 +1954,7 @@@ def test_ap_wpa2_eap_tls_neg_incorrect_
      """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")
                     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")
  
  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",
  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",
  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",
  
  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",
                     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")
  
  
  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",
                     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")
  
  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",
                     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")
  
  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 +2276,7 @@@ def _test_ap_wpa2_eap_tls_neg_altsubjec
                     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")
  
  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 +2339,13 @@@ def test_ap_wpa2_eap_ttls_server_cert_h
      """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)
                     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)
      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")
  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",
                     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 +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 +2437,11 @@@ def test_ap_wpa2_eap_pwd_nthash(dev, ap
      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 +2452,27 @@@ def test_ap_wpa2_eap_pwd_groups(dev, ap
      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 +2483,7 @@@ def test_ap_wpa2_eap_pwd_invalid_group(
                 "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 +2499,14 @@@ def test_ap_wpa2_eap_pwd_as_frag(dev, a
                 "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")
  
  
      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")
  
      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"),
                          (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 +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"""
                 "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 +2718,7 @@@ def test_ap_wpa2_eap_ikev2_oom(dev, apd
      """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"),
  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 +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"),
  
      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 +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",
              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",
              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 +2873,7 @@@ def test_ap_wpa2_eap_interactive(dev, a
      """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 +2914,7 @@@ def test_ap_wpa2_eap_ext_enable_network
      """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)
  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 +2986,10 @@@ def test_ap_wpa2_eap_fast_pac_file(dev
      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)
              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 +3030,8 @@@ def test_ap_wpa2_eap_fast_binary_pac(de
      """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",
      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",
      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 +3378,8 @@@ def test_ap_wpa2_eap_fast_gtc_identity_
      """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",
  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 +3430,10 @@@ def test_ap_wpa2_eap_fast_server_oom(de
      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",
  
      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 +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 +3679,7 @@@ def test_ap_wpa2_eap_tls_ocsp_invalid(d
      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 +3705,7 @@@ def test_ap_wpa2_eap_tls_ocsp_unknown_s
      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 +3734,7 @@@ def test_ap_wpa2_eap_ttls_ocsp_revoked(
          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 +3765,7 @@@ def test_ap_wpa2_eap_ttls_ocsp_unknown(
          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",
      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",
  
  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 +4116,7 @@@ def test_ap_wpa2_eap_tls_domain_suffix_
      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",
  
  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",
  
  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 +4186,7 @@@ def test_ap_wpa2_eap_ttls_expired_cert(
      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 +4207,7 @@@ def test_ap_wpa2_eap_ttls_ignore_expire
      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 +4220,7 @@@ def test_ap_wpa2_eap_ttls_long_duration
      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 +4232,7 @@@ def test_ap_wpa2_eap_ttls_server_cert_e
      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 +4248,7 @@@ def test_ap_wpa2_eap_ttls_server_cert_e
      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 +4260,20 @@@ def test_ap_wpa2_eap_ttls_server_pkcs12
      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",
  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 +4302,7 @@@ def test_ap_wpa2_eap_ttls_dh_params_not
      """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 +4318,7 @@@ def test_ap_wpa2_eap_ttls_dh_params_inv
      """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",
  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 +4346,8 @@@ def test_ap_wpa2_eap_ttls_dh_params_ser
      """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 +4355,8 @@@ def test_ap_wpa2_eap_ttls_dh_params_dsa
      """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 +4364,7 @@@ def test_ap_wpa2_eap_ttls_dh_params_not
      """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 +4372,7 @@@ def test_ap_wpa2_eap_ttls_dh_params_inv
      """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 +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 +4402,8 @@@ def test_ap_wpa2_eap_request_identity_m
      """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):
      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",
  
      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 +4508,19 @@@ def test_ap_wpa2_eap_sql(dev, apdev, pa
      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:
  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)
  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 +4564,12 @@@ def test_openssl_cipher_suite_config_wp
      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 +4592,42 @@@ def test_openssl_cipher_suite_config_ha
          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")
      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")
  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 +4758,7 @@@ def test_ap_wpa2_eap_in_bridge(dev, apd
  
  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'
      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")
  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 +4816,10 @@@ def test_ap_wpa2_eap_tls_check_crl(dev
      """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")
      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")
      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 +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 +4880,15 @@@ def test_ap_wpa2_eap_tls_macacl(dev, ap
      """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"):
                         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)
  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):
      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",
          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 +4977,9 @@@ def test_eap_ttls_pap_session_resumptio
      """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 +5000,9 @@@ def test_eap_ttls_chap_session_resumpti
      """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':
  
  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")
  
  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 +5071,9 @@@ def test_eap_ttls_eap_gtc_session_resum
      """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 +5093,8 @@@ def test_eap_ttls_no_session_resumption
      """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 +5115,33 @@@ def test_eap_peap_session_resumption(de
      """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")
  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 +5180,9 @@@ def test_eap_tls_session_resumption(dev
      """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 +5212,9 @@@ def test_eap_tls_session_resumption_exp
      """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':
  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 +5268,13 @@@ def test_eap_tls_session_resumption_rad
                 "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 +5301,12 @@@ def test_eap_tls_no_session_resumption_
                 "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':
          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")
@@@ -4,10 -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 +93,15 @@@ def ft_params2_r0kh_mismatch(rsn=True, 
  
  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"
              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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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)
      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"):
      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"
      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)
      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"
  
      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"
      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"
  
      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 +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")
  
      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 +599,19 @@@ def test_ft_psk_key_lifetime_in_memory(
      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)
  
      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")
      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 +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 +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")
      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")
  
      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()
      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")
      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']
      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")
      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)
@@@ -4,10 -4,11 +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 +17,13 @@@ import socke
  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 +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 +73,7 @@@
      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 +85,7 @@@
          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 +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",
      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")
      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")
      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 +385,7 @@@ def _test_ap_interworking_scan_filterin
      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()
      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 +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",
                                    '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")
      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 +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 +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 +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 +596,13 @@@ def test_ap_hs20_ext_sim_roaming(dev, a
      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 +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 +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 +673,7 @@@ def test_ap_hs20_auto_interworking(dev
      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",
      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",
          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 +758,7 @@@ def eap_test(dev, ap, eap_params, metho
      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",
      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 +794,13 @@@ def test_ap_hs20_eap_peap_gtc(dev, apde
      """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 +816,47 @@@ def test_ap_hs20_eap_ttls_mschap(dev, a
      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 +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",
      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",
                               '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",
                               '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 +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 +956,7 @@@ def test_ap_hs20_roaming_consortium(dev
      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" ]:
              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")
                              "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 +1249,7 @@@ def test_ap_hs20_username_unknown(dev, 
      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 +1267,7 @@@ def test_ap_hs20_username_unknown2(dev
      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 +1285,7 @@@ def test_ap_hs20_gas_while_associated(d
      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",
          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 +1353,13 @@@ def _test_ap_hs20_gas_while_associated_
      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")
          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 +1454,7 @@@ def test_ap_hs20_multiple_connects(dev
      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 +1494,7 @@@ def test_ap_hs20_disallow_aps(dev, apde
      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 +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 +1608,12 @@@ def test_ap_hs20_req_roaming_consortium
      """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"
          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 +1700,7 @@@ def test_ap_hs20_roam_to_higher_prio(de
      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",
      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")
  
  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 +1770,7 @@@ def test_ap_hs20_domain_suffix_match(de
      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 +1788,12 @@@ def test_ap_hs20_roaming_partner_prefer
      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 +1813,12 @@@ def test_ap_hs20_max_bss_load(dev, apde
      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 +1849,11 @@@ def test_ap_hs20_max_bss_load2(dev, apd
      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()
      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 +1900,7 @@@ def _test_ap_hs20_multi_cred_sp_prio(de
      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 +1945,7 @@@ def _test_ap_hs20_multi_cred_sp_prio2(d
      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()
      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")
      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 +2042,7 @@@ def test_ap_hs20_req_conn_capab(dev, ap
      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")
      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")
      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")
      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 +2137,7 @@@ def check_bandwidth_selection(dev, type
      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 +2163,7 @@@ def test_ap_hs20_min_bandwidth_home(dev
      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")
      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")
      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 +2273,7 @@@ def test_ap_hs20_min_bandwidth_roaming(
      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")
      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 +2311,12 @@@ def test_ap_hs20_min_bandwidth_and_roam
      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 +2334,7 @@@ def test_ap_hs20_min_bandwidth_no_wan_m
      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 +2418,7 @@@ def _test_ap_hs20_deauth_req_from_radiu
      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()
          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 +2459,7 @@@ def _test_ap_hs20_remediation_required(
      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 +2487,7 @@@ def _test_ap_hs20_remediation_required_
      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 +2528,7 @@@ def _test_ap_hs20_session_info(dev, apd
      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 +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 +2591,7 @@@ def test_ap_hs20_network_preference(dev
      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",
  
      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 +2632,7 @@@ def test_ap_hs20_network_preference2(de
      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",
  
      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 +2673,12 @@@ def test_ap_hs20_network_preference3(de
      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 +2714,14 @@@ def test_ap_hs20_network_preference4(de
      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 +2757,7 @@@ def test_ap_hs20_interworking_select_bl
      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 +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")
      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()
              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",
      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']
      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"
          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"):
              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):
                     "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 +3561,7 @@@ def test_ap_hs20_external_selection(dev
      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 +3578,7 @@@ def test_ap_hs20_random_mac_addr(dev, a
      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 +3613,7 @@@ def test_ap_hs20_multi_network_and_cred
      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 +3649,7 @@@ def test_ap_hs20_interworking_add_netwo
      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 +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 +3749,17 @@@ def test_ap_hs20_hidden_ssid_in_scan_re
      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 +3797,7 @@@ def _test_ap_hs20_proxyarp_dgaf(dev, ap
      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 +3992,7 @@@ def send_ns(dev, src_ll=None, target=No
      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'
      _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 +4187,7 @@@ def _test_proxyarp_open(dev, apdev, par
      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()
          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 +4656,7 @@@ def test_ap_hs20_connect_deinit(dev, ap
      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="")
      # 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")
@@@ -4,30 -4,40 +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":
  
      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":
  
      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":
  
  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":
  
      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":
  
      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":
  
  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":
  
  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":
  
  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
                     "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":
              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
                     "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":
              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
                     "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")
                     "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":
              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):
                 "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 +591,12 @@@ def test_obss_scan_40_intolerant(dev, a
                 "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")
  
  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")
  
  
  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 +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")
                 "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 +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 +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")
                     "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)
              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:
                     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":
  
  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")
  
      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 +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)
          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):
                     "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)
          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):
                     "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)
          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 +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)
      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)
      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)
@@@ -24,7 -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")
@@@ -4,6 -4,7 +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 +15,16 @@@ import o
  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 +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 +68,7 @@@
  
  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)
      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",
      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)
      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",
      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()
  
      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 +200,16 @@@ def hapd_out_of_mem(hapd, apdev, count
      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):
  
      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 +284,7 @@@ def test_ap_open_wpas_in_bridge(dev, ap
          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'
  
      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()
      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()
      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)")
      # 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)
  
  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)
          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",
      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 +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)
      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")
@@@ -4,13 -4,17 +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"
      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 +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")
      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:
          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):
      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 +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")
      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"
      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")
      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"
      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")
      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):
      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:
      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"
      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)
@@@ -4,27 -4,29 +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 +40,6 @@@
                     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'])
                            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")
      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")
      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")
          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")
                            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"):
                            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()
      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")
          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")
      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)
  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",
                     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)
          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:
  
  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")
      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")
  
      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")
@@@ -4,6 -4,7 +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 +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 +36,7 @@@
      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 +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 +70,7 @@@
          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 +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")
      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"])
      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"
      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"])
      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")
          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])
      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 +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")
          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])
      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"
      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)
              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")
          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:
          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']
      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']
      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)
          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']
          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"""
      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)
          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 +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)
      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])
      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])
      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])
      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])
      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])
      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])
      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],
      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 +1391,7 @@@ def test_ap_wpa2_psk_supp_proto_unexpec
          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 +1699,7 @@@ def test_ap_wpa2_psk_supp_proto_gtk_not
  
  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
  
  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():
                  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 +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 +1774,7 @@@ def test_wpa2_psk_key_lifetime_in_memor
      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])
  
      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)
  
      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")
      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 +1897,7 @@@ def _test_ap_wpa2_psk_wpas_in_bridge(de
      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'
      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 +1944,7 @@@ def test_ap_wpa2_psk_drop_first_msg_4(d
      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)
          # 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"
      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):
          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)
  
      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)
  
              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 *")
  
              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"
      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)
          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']
      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")
          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')
          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")
@@@ -4,8 -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 +21,8 @@@ def check_qos_map(ap, hapd, dev, sta, d
      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 +34,7 @@@
          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")
      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)
      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"
                 "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
      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 "):
  # 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")
      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']:
      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)
@@@ -4,6 -4,7 +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 +16,11 @@@ from hostapd import Hostap
  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 +57,8 @@@ def connect_2sta_open(dev, hapd, scan_f
      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 +88,7 @@@ def tdls_check_dl(sta0, sta1, bssid, ad
  
  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 +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:
      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:
          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 +164,97 @@@ def check_tdls_link(sta0, sta1, connect
          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()
  
  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()
  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"""
          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",
  
  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"""
                 "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 +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()):
  
  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")
@@@ -25,7 -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 +34,7 @@@
                 "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 +94,7 @@@ def _test_ap_track_sta_no_probe_resp(de
                 "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",
                 "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 +127,7 @@@ def _test_ap_track_sta_no_auth(dev, apd
                 "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",
                 "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 +174,7 @@@ def _test_ap_track_sta_no_auth_passive(
                 "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",
                 "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 +230,7 @@@ def _test_ap_track_sta_force_5ghz(dev, 
                 "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",
                 "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 +263,7 @@@ def _test_ap_track_sta_force_2ghz(dev, 
                 "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",
                 "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)
      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")
@@@ -15,6 -15,7 +15,7 @@@ import hostap
  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 +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 +75,7 @@@
          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 +87,7 @@@
                     "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 +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)
          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]
                     "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 +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 +288,7 @@@ def test_ap_vht_capab_not_supported(dev
                     "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 +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:
                     "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:
          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:
                     "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
                     "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:
          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])
                     "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 +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 +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",
                     "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)
              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()
@@@ -6,6 -6,7 +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 +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 +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 +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 +71,8 @@@
  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",
      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",
                    "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")
  
      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)
      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 +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 +302,9 @@@ def ap_vlan_iface_test_and_prepare_envi
  
  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.
                        "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()
  
          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")
@@@ -4,6 -4,7 +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 +30,21 @@@ import hwsim_util
  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 +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 +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)
      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)
      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)
      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 +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 +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")
          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")
      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()
      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")
          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)
      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")
      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"
      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 +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 +555,7 @@@ def test_ap_wps_reg_connect_mixed_mode(
      """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 +590,12 @@@ def test_ap_wps_reg_override_ap_setting
          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 +618,16 @@@ def test_ap_wps_random_ap_pin(dev, apde
      """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")
      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 +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 +719,7 @@@ def test_ap_wps_reg_config_ext_processi
      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 +743,7 @@@ def test_ap_wps_reg_config_tkip(dev, ap
      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 +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"
  
          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")
      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 +839,11 @@@ def test_ap_wps_setup_locked_timeout(de
      """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"
  
          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 +881,7 @@@ def test_ap_wps_setup_locked_2(dev, apd
                 "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"
  
      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)
      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")
      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 +1026,7 @@@ def _test_ap_wps_er_add_enrollee(dev, a
      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 +1159,7 @@@ def _test_ap_wps_er_add_enrollee_uuid(d
      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 +1244,14 @@@ def test_ap_wps_er_multi_add_enrollee(d
      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",
      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 +1311,7 @@@ def _test_ap_wps_er_add_enrollee_pbc(de
      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 +1382,7 @@@ def _test_ap_wps_er_pbc_overlap(dev, ap
      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 +1457,7 @@@ def _test_ap_wps_er_v10_add_enrollee_pi
      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",
      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 +1512,7 @@@ def _test_ap_wps_er_config_ap(dev, apde
      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",
      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 +1576,7 @@@ def _test_ap_wps_er_cache_ap_settings(d
                 "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'])
          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 +1655,7 @@@ def _test_ap_wps_er_cache_ap_settings_o
                 "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'])
              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 +1717,7 @@@ def _test_ap_wps_er_cache_ap_settings_o
                 "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'])
              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 +1779,7 @@@ def _test_ap_wps_er_subscribe_oom(dev, 
                 "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 +1818,7 @@@ def _test_ap_wps_er_set_sel_reg_oom(dev
                 "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)
  
  
      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 +1870,7 @@@ def _test_ap_wps_er_learn_oom(dev, apde
                 "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 +1904,12 @@@ def test_ap_wps_fragmentation(dev, apde
      """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)
      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")
      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")
      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 +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)
  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'])
      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"
                 "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 +2114,7 @@@ def test_ap_wps_per_station_psk(dev, ap
      except:
          pass
  
+     hapd = None
      try:
          with open(pskfile, "w") as f:
              f.write("# WPA PSKs\n")
                     "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")
              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)"""
                     "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 +2230,11 @@@ def test_ap_wps_pin_request_file(dev, a
      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 +2276,7 @@@ def test_ap_wps_auto_setup_with_config_
              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 +2306,7 @@@ def test_ap_wps_pbc_timeout(dev, apdev
      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 +2410,7 @@@ VFi5hrL
      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",
                 "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 +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',
      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',
  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)
  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 +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}'
      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)
      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')
  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")
  
  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)
  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)
  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)
  
  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)
  
          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"):
  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'])
      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")
      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")
      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"})
  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"})
  
      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")
  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"})
  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",
      # 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",
          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)
      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 +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()
      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 +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",
          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 +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 +3824,10 @@@ def test_ap_wps_wpa_cli_action(dev, apd
               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 +4418,7 @@@ RGV2aWNlIEEQSQAGADcqAAE
      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")
      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 +4608,7 @@@ def _test_ap_wps_er_http_proto_subscrib
      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 +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 +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"):
  
      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 +4924,7 @@@ def test_ap_wps_pbc_pin_mismatch(dev, a
      """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")
      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))
          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 +4976,7 @@@ def test_ap_wps_probe_req_ie_oom(dev, a
      """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")
          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))
          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 +5019,7 @@@ def test_ap_wps_assoc_resp_ie_oom(dev, 
      """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")
              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 +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])
          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])
              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])
              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 +5208,7 @@@ def test_ap_wps_random_psk_fail(dev, ap
                     "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 +5263,7 @@@ def wps_start_ext(apdev, dev, pbc=False
      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 +5846,7 @@@ def test_ap_wps_m4_msg_type_m2d(dev, ap
      """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"
                 "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)
  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 +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 +7784,12 @@@ def test_wps_ext_ap_settings_success(de
      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')
      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')
      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')
      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 +7859,7 @@@ def wps_wait_ap_nack(hapd, dev, e_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"
  
      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"
  
      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"
  
      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 +8141,7 @@@ def test_wps_ext_m7_missing_e_snonce2(d
  
      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"
  
      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 +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"
  
      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"
  
      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"
  
      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"
  
      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"
  
      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"
  
      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"
  
      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"
  
      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"
  
      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"
  
      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"
  
      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"
  
      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"
  
      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"
  
      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"
  
      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"
  
      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 +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)
  
      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)
  
      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)
  
      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 +9096,7 @@@ def test_wps_ext_wsc_done_no_r_nonce(de
  
      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"
  
      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"
      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")
@@@ -4,6 -4,7 +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 +14,7 @@@ import hostap
  
  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"):
      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"):
@@@ -13,8 -13,8 +13,8 @@@ import hostap
  
  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 +70,8 @@@
  
  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")
@@@ -4,17 -4,18 +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],
          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 +67,12 @@@ def nl80211_remain_on_channel(dev, ifin
  
  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)
  
      #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:
          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"',
      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")
  
@@@ -11,83 -11,98 +11,98 @@@ import tim
  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")
                                             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")
          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")
      # 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()
@@@ -20,7 -20,9 +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 +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"""
      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()
      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 +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 +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 +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",
      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 +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 +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 +1228,7 @@@ def test_dbus_connect_psk_mem(dev, apde
      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 +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):
          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])
  
  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)
  
      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 +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 +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 +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 +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 +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
  
              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,
                      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 +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 +4211,7 @@@ def test_dbus_p2p_go_neg_auth(dev, apde
              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 +4300,7 @@@ def test_dbus_p2p_go_neg_init(dev, apde
              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 +4390,7 @@@ def test_dbus_p2p_group_termination_by_
              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 +4453,7 @@@ def _test_dbus_p2p_group_idle_timeout(d
          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
  
              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
  
          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')
              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 +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 +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 +4966,7 @@@ def test_dbus_connect_wpa_eap(dev, apde
      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 +5063,191 @@@ def _test_dbus_ap_scan_2_ap_mode_scan(d
      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")
@@@ -111,11 -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 +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 +570,7 @@@ def test_dbus_old_connect_eap(dev, apde
  
      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):
@@@ -4,6 -4,7 +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 +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 +55,8 @@@
          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 +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 +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 +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()
@@@ -4,22 -4,34 +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 +57,23 @@@ EAP_TYPE_AKA_PRIME = 5
  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 +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:
              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 +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):
      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",
      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 +482,9 @@@ EAP_SAKE_AT_MSK_LIFE = 13
  
  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'],
          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,
                                 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,
                                 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,
                                 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,
                                 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,
                                 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,
                                 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,
                                 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,
                                 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,
                                 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",
      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")
      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",
      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)
  
      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",
      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
              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
              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")
  
          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")
  
          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")
  
          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")
  
          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")
  
          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")
  
          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")
  
          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
              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")
  
          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")
  
          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")
  
          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")
  
          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")
  
          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)
@@@ -11,7 -11,7 +11,7 @@@ import o
  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 +25,7 @@@ def test_erp_initiate_reauth_start(dev
      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 +39,7 @@@ def test_erp_enabled_on_server(dev, apd
      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 +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 +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 +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"""
      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 +187,7 @@@ def test_erp_radius_eap_methods(dev, ap
      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 +235,7 @@@ def test_erp_key_lifetime_in_memory(dev
      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])
                     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")
      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")
      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()
@@@ -4,6 -4,7 +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 +15,18 @@@ from test_ap_hs20 import hs20_ap_param
  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 +58,7 @@@
  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 +70,7 @@@ def test_ext_password_interworking(dev
      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")
@@@ -147,7 -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)
  
                             '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]
                             '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)):
          """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):
@@@ -188,7 -188,7 +188,7 @@@ def fst_start_session(apdev, test_param
                          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
                  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):
                  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):
                  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 +528,7 @@@ def fst_remove_session(apdev, test_para
                  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 +612,7 @@@ def fst_send_unexpected_frame(apdev, te
                  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 +733,7 @@@ def fst_bad_transfer(apdev, test_params
              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"""
              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 +839,9 @@@ def test_fst_second_sta_connect_to_non_
              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 +868,11 @@@ def test_fst_second_sta_connect_to_fst_
              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 +900,11 @@@ def test_fst_disconnect_1_of_2_stas_fro
              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 +932,11 @@@ def test_fst_disconnect_1_of_2_stas_fro
              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 +966,11 @@@ def test_fst_disconnect_2_of_2_stas_fro
              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 +1065,7 @@@ def test_fst_disconnect_non_fst_sta(dev
  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 +1527,12 @@@ def test_fst_ap_start_session_oom(dev, 
                                 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:
              except:
                  pass
          finally:
-             ap1.stop()
              try:
                  ap2.stop()
              except:
@@@ -2339,7 -2344,7 +2344,7 @@@ def fst_start_and_connect(apdev, group
  
      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)
  
  
      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 +2539,20 @@@ def _test_fst_setup_mbie_diff(dev, apde
      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"""
@@@ -5,16 -5,20 +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 +55,7 @@@
  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 +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 +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 +182,7 @@@ def test_gas_concurrent_connect(dev, ap
      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)
  
      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])
          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 +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",
               "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")
               "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 +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])
      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")
      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)")
                                    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 +859,7 @@@ def test_gas_unknown_adv_proto(dev, apd
      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")
      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 +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 +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])
  
      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 +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")
          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")
@@@ -4,15 -4,18 +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 +33,7 @@@
      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 +41,7 @@@
      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"):
      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):
      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()
  
      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"):
      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"):
      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"):
      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"):
      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 +232,7 @@@ def test_hapd_ctrl_set_deny_mac_file(de
      """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 +246,7 @@@ def test_hapd_ctrl_set_accept_mac_file(
      """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")
      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  ",
                 "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",
                 "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",
          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 +484,11 @@@ def test_hapd_dup_network_global_wpa2(d
  
      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 +513,11 @@@ def test_hapd_dup_network_global_wpa(de
      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()
  
      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)
          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)
@@@ -4,6 -4,7 +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 +13,16 @@@ import hostap
  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 +38,7 @@@
          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 +50,7 @@@ def test_hostapd_oom_wpa2_psk(dev, apde
      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 +59,7 @@@
      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 +71,7 @@@
  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 +117,7 @@@ def test_hostapd_oom_wpa2_eap_connect(d
      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
@@@ -4,6 -4,7 +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 +12,7 @@@ import r
  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 +50,12 @@@ def wait_4way_handshake2(dev1, dev2, de
  
  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)
          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 +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"
      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 +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 +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 +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)
@@@ -4,14 -4,17 +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 +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 +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 +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 +81,7 @@@ def test_ieee8021x_static_wep40(dev, ap
      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 +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")
          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 +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 +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 +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",
      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 +403,7 @@@ def test_ieee8021x_auth_awhile(dev, apd
      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()
  
      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",
      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)
@@@ -4,6 -4,7 +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 +46,12 @@@ def test_monitor_iface_wpa2_psk(dev, ap
  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 +60,7 @@@
      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()
@@@ -4,8 -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 +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")
  
  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")
  
  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 +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])
  
      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])
  
  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")
  
  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")
  
  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")
  
  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 +582,13 @@@ def test_nfc_p2p_static_handover_join_t
  
  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 +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")
  
  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")
      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():
      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")
@@@ -4,6 -4,7 +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 +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 +62,7 @@@ def test_nfc_wps_config_token(dev, apde
      """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 +82,8 @@@
  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:
      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:
      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:
  
  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:
          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 +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:
  
  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:
  
  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 +306,7 @@@ def test_nfc_wps_handover_with_pw_token
      """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 +337,7 @@@ def test_nfc_wps_handover_pk_hash_misma
      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 +362,7 @@@ def test_nfc_wps_handover_pk_hash_misma
      """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")
  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")
  
      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()
      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 +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 +509,11 @@@ def test_nfc_wps_er_handover_pk_hash_mi
          _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 +543,11 @@@ def test_nfc_wps_er_handover_pk_hash_mi
          _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")
      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",
@@@ -11,9 -11,7 +11,7 @@@ import hostap
  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"""
@@@ -4,6 -4,7 +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 +15,8 @@@ import util
  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 +84,7 @@@
  
  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")
  
  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']:
  
  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 +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 +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()
      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)
      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 +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 +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 +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:
              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")
          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 +479,7 @@@ def test_autogo_join_auto_go_not_found(
      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)
      # 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
          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"""
      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")
  
      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 +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 +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()
@@@ -4,6 -4,7 +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 +13,10 @@@ import tim
  
  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 +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)
          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)
          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)
          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):
          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)
                  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):
          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])
          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
  
      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 +260,22 @@@ def test_autogo_with_bss_on_disallowed_
          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"""
          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],
              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"""
          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"""
          # 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' })
          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"""
          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)
         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)
         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:
          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 = []
      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'])
              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 +592,7 @@@ def test_p2p_listen_chan_optimize(dev, 
      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):
          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")
  
          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")
          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:
          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"""
      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")
          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:
          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")
  
              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")
  
              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':
          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)
          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':
          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,
          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")
  
              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':
      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()
@@@ -4,6 -4,7 +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 +12,21 @@@ import tim
  
  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 +41,7 @@@
  
  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
                     "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)
  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")
          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)
      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)
      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)
      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)
      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)
      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)
      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 +276,7 @@@ def test_concurrent_invitation_channel_
      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")
@@@ -9,11 -9,10 +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 +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 +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 +120,18 @@@ def test_p2p_device_concurrent_scan(dev
              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")
          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")
          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)
          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 +238,13 @@@ def test_p2p_device_incorrect_command_i
          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")
  
          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:
  
          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"""
          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])
@@@ -4,13 -4,19 +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 +99,7 @@@
      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 +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")
  
          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 +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")
          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():
      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 +496,7 @@@ def test_p2p_listen_and_offchannel_tx(d
      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 +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()
@@@ -4,13 -4,15 +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 +73,7 @@@
      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 +336,15 @@@ def test_p2p_ext_vendor_elem_assoc(dev
  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()
                       "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"),
@@@ -4,11 -4,12 +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 +17,10 @@@ import hwsim_util
  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 +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 +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 +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 +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()
      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)
          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 +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()
      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 +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,
          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,
          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,
          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()
      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()
          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 +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()
      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)
  
      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")
          # 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 +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()
          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()
      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"):
      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 +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")
@@@ -4,11 -4,13 +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 +55,7 @@@
      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()
      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 +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()
@@@ -1,9 -1,10 +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 +12,8 @@@ import loggin
  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 +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 +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 +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)
      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 +839,7 @@@ def test_p2p_msg_invitation_req_to_go(d
      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)
      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 +999,7 @@@ def test_p2p_msg_invitation_resp(dev, a
      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 +1031,11 @@@ def test_p2p_msg_invitation_resend(dev
      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:
      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 +1076,7 @@@ def test_p2p_msg_invitation_resend_dupl
      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:
  
      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)
      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 +1296,10 @@@ def test_p2p_msg_go_neg_both_start(dev
      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 +1894,198 @@@ def test_p2p_msg_unexpected_go_neg_resp
      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")
  # 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])
      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 +263,7 @@@ def test_persistent_group_invite_remove
  
      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)
          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 +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()
      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])
  
      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()
  
      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()
      [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])
          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 +549,15 @@@ def test_persistent_group_missed_inv_re
  
      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()
  
      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)
@@@ -4,6 -4,7 +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 +88,7 @@@ def run_sd(dev, dst, query, exp_query=N
  
      return ev
  
+ @remote_compatible
  def test_p2p_service_discovery(dev):
      """P2P service discovery"""
      addr0 = dev[0].p2p_dev_addr()
@@@ -132,6 -134,7 +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 +164,7 @@@ def test_p2p_service_discovery_fragment
              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")
      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")
      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")
      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")
      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")
      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")
      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")
      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")
      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"):
      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 +400,7 @@@ def _test_p2p_service_discovery_externa
          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:
      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 +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()
      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()
@@@ -4,6 -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
  def test_p2p_set(dev):
      """P2P_SET commands"""
      for cmd in [ "",
@@@ -102,6 -104,7 +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()
@@@ -4,6 -4,7 +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 +13,7 @@@ import Queu
  
  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 +299,7 @@@ def test_wifi_display_persistent_group(
          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()
      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()
@@@ -4,6 -4,7 +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 +13,10 @@@ import r
  
  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 +93,7 @@@ def p2ps_exact_seek(i_dev, r_dev, svc_n
          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):
          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):
          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
          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)
                  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:
              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
  
      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())
  
      # 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)
              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")
  
                  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:
  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',
      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',
      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',
      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',
      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',
          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',
          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',
          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',
          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',
          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',
          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',
          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)
          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 +622,12 @@@ def p2ps_connect_adv_go_pin_method(dev
              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 +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 +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"""
      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 +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 +1068,509 @@@ def p2ps_test_feature_capability_cpt(de
      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])
@@@ -4,6 -4,7 +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 +14,14 @@@ import hostap
  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 +40,7 @@@ def test_peerkey_unknown_peer(dev, apde
      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)
      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")
@@@ -10,6 -10,7 +10,7 @@@ import subproces
  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 +18,7 @@@
  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 +30,7 @@@
      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()
      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",
      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 +181,7 @@@ def test_pmksa_cache_opportunistic(dev
      """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",
      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 +231,7 @@@ def test_pmksa_cache_opportunistic_conn
      """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")
      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)
  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",
  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 +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",
      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
          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'))
                          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()
  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",
  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",
  
      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 +661,20 @@@ def test_pmksa_cache_opportunistic_mult
      """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")
          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 +711,17 @@@ def test_pmksa_cache_preauth_oom(dev, a
      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'])
  
      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 +767,7 @@@ def test_pmksa_cache_size_limit(dev, ap
          _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:
          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")
          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)
          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 +816,8 @@@ def test_pmksa_cache_preauth_timeout(de
  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"):
  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):
                  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")
@@@ -7,7 -7,6 +7,6 @@@
  import time
  import logging
  logger = logging.getLogger()
- import subprocess
  
  import hostapd
  from wpasupplicant import WpaSupplicant
@@@ -71,9 -70,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 +81,7 @@@
  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")
@@@ -1,9 -1,11 +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 +18,9 @@@ import threadin
  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",
                  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 +54,7 @@@ def test_radius_auth_unreachable2(dev, 
      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 +73,7 @@@ def test_radius_auth_unreachable3(dev, 
      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 +92,7 @@@ def test_radius_acct_unreachable(dev, a
      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 +111,7 @@@ def test_radius_acct_unreachable2(dev, 
      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 +132,7 @@@ def test_radius_acct_unreachable3(dev, 
      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 +153,7 @@@ def test_radius_acct_unreachable4(dev, 
      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 +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",
      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")
      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 +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 +285,7 @@@ def test_radius_acct_interim_unreachabl
      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")
      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")
              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:
      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 +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 +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"
      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):
      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):
      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 +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 +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))
      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 +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))
          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")
          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 +1245,7 @@@ def test_ap_vlan_wpa2_psk_radius_requir
                          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))
          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",
      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")
@@@ -14,6 -14,7 +14,7 @@@ import hwsim_util
  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 +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 +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 +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)
  
          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)")
@@@ -1,21 -1,22 +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 +24,7 @@@
      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 +40,7 @@@
      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 +48,7 @@@
      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 +60,7 @@@
          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 +69,7 @@@
                                   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 +81,7 @@@
          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 +89,7 @@@
      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",
      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"):
                                   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 +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)
          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"):
                                   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",
      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"):
      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 +224,7 @@@ def test_sae_forced_anti_clogging(dev, 
      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 +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):
          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"):
      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 +272,7 @@@ def test_sae_key_lifetime_in_memory(dev
      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])
  
      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")
      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)")
      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"):
      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")
                         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"):
      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")
          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"):
      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")
          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 +643,7 @@@ def sae_reflection_attack(apdev, dev, g
      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)
          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"):
      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)
          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"),
                             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")
@@@ -4,6 -4,7 +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 +13,7 @@@ import subproces
  
  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 +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")
      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 = []
      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")
      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):
          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"):
      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:
              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")
      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"):
      finally:
          dev[0].request("SET filter_ssids 0")
  
+ @remote_compatible
  def test_scan_int(dev, apdev):
      """scan interval configuration"""
      try:
  
  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")
      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:
      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
                     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:
  
      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
      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:
          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")
                     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:
  
      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")
      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)
  
  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')
      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 +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"):
          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:
              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:
          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 +744,7 @@@ def test_scan_random_mac(dev, apdev, pa
          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 = [ "",
          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"):
          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)
      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 +914,12 @@@ def _test_scan_ap_scan_2_ap_mode(dev, a
  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")
          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)
@@@ -5,20 -5,22 +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",
          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")
      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)
@@@ -16,7 -16,7 +16,7 @@@ from wpasupplicant import WpaSupplican
  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 +26,7 @@@
  
  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 +48,7 @@@
  
  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 +80,7 @@@
  
  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")
  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')
  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')
  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")
  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")
  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")
  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")
@@@ -9,7 -9,7 +9,7 @@@ import loggin
  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 +23,7 @@@
  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:
      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",
                 "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 +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",
                 '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 +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",
                 "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 +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",
                 '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",
                     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()
@@@ -8,21 -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 +30,7 @@@
                     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",
                     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 +87,7 @@@
                     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 +96,7 @@@
      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")
                     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")
      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")
                     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)
@@@ -4,12 -4,18 +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()
      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" })
                     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 +62,7 @@@
  
  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"',
      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()
@@@ -31,7 -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 +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 +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 +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 +97,7 @@@
      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 +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 +163,7 @@@ def test_wext_wep_shared_key_auth(dev, 
      """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 +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 +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 +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")
@@@ -4,6 -4,7 +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 +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",
                 "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 +38,7 @@@
                 "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 +52,7 @@@
      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 +60,7 @@@
                 "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()
      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 +152,7 @@@ def check_wnm_sleep_mode_enter_exit(hap
      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",
                 "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)
          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")
      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)
          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 +239,24 @@@ MGMT_SUBTYPE_ACTION = 1
  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 +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")
  
      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 +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", "")
                     "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()
              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 +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 +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()
@@@ -4,12 -4,14 +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 +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 +96,7 @@@
      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()
      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()
      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 +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()
      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 +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()
      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()
@@@ -9,6 -9,7 +9,7 @@@ logger = logging.getLogger(
  import os
  
  from wpasupplicant import WpaSupplicant
+ import hostapd
  
  def check_config(config):
      with open(config, "r") as f:
          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):
          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")
              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"):
          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"):
              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
@@@ -4,6 -4,7 +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 +16,10 @@@ import hostap
  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()
      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"),
               ("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:
          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:
          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")
          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()
              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):
      # 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)
      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 +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])
      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")
      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 +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"):
      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 "):
      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 "):
      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 "):
      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' ]:
          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 "):
      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"):
      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"):
      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()
  
  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 +799,8 @@@ def test_wpas_ctrl_bssid_filter(dev, ap
          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'])
      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")
          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"):
      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"):
      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 +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)
          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"):
      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",
          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",
          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" ]
  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"):
      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 +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 +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 +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"):
      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-"):
          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",
          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",
      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",
          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")
      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 +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()
  
  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)
  
      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:
              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):
          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"""
          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 +1634,7 @@@ def test_wpas_ctrl_wait(dev, apdev, tes
          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 +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',
                 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',
                 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',
                 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'),
              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():
      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")
@@@ -1,5 -1,3 +1,3 @@@
- #!/usr/bin/python
- #
  # wpa_supplicant mesh mode tests
  # Copyright (c) 2014, cozybit Inc.
  #
@@@ -8,11 -6,16 +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 +105,20 @@@ def test_wpas_add_set_remove_support(de
      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 +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])
      # 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])
      # 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")
      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):
      # 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)
      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 +515,67 @@@ def test_wpas_mesh_secure_no_auto(dev, 
      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 +669,7 @@@ def test_wpas_mesh_dynamic_interface(de
          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:
      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 +771,104 @@@ def _test_wpas_mesh_open_5ghz(dev, apde
      # 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 +971,996 @@@ def test_mesh_wpa_auth_init_oom(dev, ap
          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")
@@@ -4,6 -4,7 +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 +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 +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:
      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"])
      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"])
@@@ -21,7 -21,7 +21,7 @@@ def run_tshark(filename, filter, displa
      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,
@@@ -5,6 -5,8 +5,8 @@@
  # See README for more details.
  
  import os
+ import time
+ import remotehost
  
  def get_ifnames():
      ifnames = []
@@@ -50,6 -52,14 +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 +81,24 @@@ def skip_with_fips(dev, reason="Not sup
      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
@@@ -12,6 -12,8 +12,8 @@@ mount sysfs -t sysfs /sy
  # 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
  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 +78,10 @@@ ip link set lo u
  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 +111,7 @@@ els
        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 ...
@@@ -50,6 -50,7 +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 +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:
          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])
      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)
          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']:
@@@ -9,7 -9,11 +9,11 @@@ if [ -z "$NUM" ]; the
  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)
  
@@@ -1,5 -1,8 +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
@@@ -6,7 -6,11 +6,11 @@@ if [ -z "$TESTDIR" ] ; the
        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
  
  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 \
        -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"
@@@ -4,7 -4,9 +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 +15,133 @@@ import wpasp
  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:
          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)
              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)
@@@ -10,29 -10,66 +10,66 @@@ import loggin
  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()
              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):
              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
                  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'
          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)
  
          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()
          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")
              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")
          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])
              if field in params:
                  self.set_cred(id, field, params[field])
  
-         return id;
+         return id
  
      def select_network(self, id, freq=None):
          if freq:
              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)
          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")
      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"
              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)
          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")
  
          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()
              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):
      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
          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()
              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:
              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",
          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
              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
              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
              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:
      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:
              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")
                         "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])
          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)
          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
  
              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)
          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)
              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
  
diff --combined libeap/wlantest/bip.c
@@@ -23,7 -23,7 +23,7 @@@ u8 * bip_protect(const u8 *igtk, size_
        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;
diff --combined libeap/wlantest/ccmp.c
@@@ -77,6 -77,64 +77,64 @@@ static void ccmp_aad_nonce(const struc
  }
  
  
+ 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 +235,48 @@@ u8 * ccmp_encrypt(const u8 *tk, u8 *fra
  }
  
  
+ 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)
  {
@@@ -102,6 -102,8 +102,8 @@@ int read_cap_file(struct wlantest *wt, 
                                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 "
@@@ -7,7 -7,6 +7,6 @@@
   */
  
  #include "utils/includes.h"
- #include <linux/if_ether.h>
  
  #include "utils/common.h"
  #include "common/defs.h"
@@@ -10,6 -10,7 +10,7 @@@
  
  #include "utils/common.h"
  #include "utils/eloop.h"
+ #include "common/ieee802_11_defs.h"
  #include "wlantest.h"
  
  
@@@ -136,6 -137,212 +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 +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();
@@@ -21,7 -21,7 +21,7 @@@ static void wlantest_terminate(int sig
  
  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 +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) {
                case 'n':
                        wt.pcapng_file = optarg;
                        break;
+               case 'N':
+                       wt.pcap_no_buffer = 1;
+                       break;
                case 'p':
                        add_passphrase(&wt, optarg);
                        break;
@@@ -202,6 -202,7 +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 +274,10 @@@ u8 * ccmp_decrypt(const u8 *tk, const s
                  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);
@@@ -59,6 -59,8 +59,8 @@@ void write_pcap_captured(struct wlantes
        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 +104,8 @@@ void write_pcap_decrypted(struct wlante
        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 +185,8 @@@ int write_pcapng_init(struct wlantest *
        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 +269,8 @@@ static void write_pcapng_decrypted(stru
        *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 +345,8 @@@ void write_pcapng_write_read(struct wla
        *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);
  
@@@ -49,6 -49,12 +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 +71,6 @@@ INCLUDES += $(LOCAL_PATH)/src/rsn_sup
  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 +100,7 @@@ OBJS_p += src/utils/wpabuf.
  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 +276,7 @@@ endi
  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 +393,6 @@@ EAPDYN += src/eap_peer/eap_tls.s
  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 +403,6 @@@ ifdef CONFIG_EAP_UNAUTH_TL
  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 +417,6 @@@ els
  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 +430,6 @@@ EAPDYN += src/eap_peer/eap_ttls.s
  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 +447,6 @@@ EAPDYN += src/eap_peer/eap_md5.s
  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 +469,6 @@@ els
  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 +482,6 @@@ EAPDYN += src/eap_peer/eap_gtc.s
  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 +506,6 @@@ EAPDYN += src/eap_peer/eap_sim.s
  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 +533,6 @@@ EAPDYN += src/eap_peer/eap_psk.s
  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 +549,6 @@@ EAPDYN += src/eap_peer/eap_aka.s
  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 +574,6 @@@ endi
  
  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 +588,6 @@@ els
  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 +602,6 @@@ EAPDYN += src/eap_peer/eap_pax.s
  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 +614,6 @@@ EAPDYN += src/eap_peer/eap_sake.s
  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 +626,6 @@@ EAPDYN += src/eap_peer/eap_gpsk.s
  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 +638,6 @@@ endi
  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 +650,6 @@@ EAPDYN += src/eap_peer/eap_eke.s
  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 +672,6 @@@ OBJS += src/wps/wps_attr_process.
  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 +734,6 @@@ els
  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 +749,6 @@@ EAPDYN += src/eap_peer/eap_vendor_test.
  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 +758,6 @@@ ifdef CONFIG_EAP_TN
  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 +804,8 @@@ OBJS += src/ap/ap_drv_ops.
  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 +815,9 @@@ endi
  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 +834,11 @@@ L_CFLAGS += -DCONFIG_IEEE80211A
  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 +874,10 @@@ OBJS += src/ap/peerkey_auth.
  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 +931,6 @@@ ifdef TLS_FUNC
  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 +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 +1004,7 @@@ OBJS += src/tls/tlsv1_cred.
  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 +1058,8 @@@ CONFIG_INTERNAL_SHA1=
  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 +1246,19 @@@ SHA256OBJS += src/crypto/sha256-prf.
  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 +1301,7 @@@ endi
  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 +1325,6 @@@ ifdef CONFIG_WP
  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 +1340,6 @@@ endi
  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 +1354,11 @@@ endi
  
  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 +1504,6 @@@ endi
  
  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 +1577,13 @@@ endi
  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 +1594,13 @@@ endi
  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 +1639,42 @@@ LOCAL_COPY_HEADERS_TO := libwpa_clien
  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
  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)
@@@ -6,6 -6,17 +6,17 @@@ ifndef CFLAG
  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 +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 +110,7 @@@ OBJS_p += ../src/utils/wpabuf.
  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 +171,10 @@@ ifdef CONFIG_ELOOP_EPOL
  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 +304,23 @@@ NEED_MD5=
  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 +421,6 @@@ EAPDYN += ../src/eap_peer/eap_tls.s
  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 +431,6 @@@ ifdef CONFIG_EAP_UNAUTH_TL
  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 +445,6 @@@ els
  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 +458,6 @@@ EAPDYN += ../src/eap_peer/eap_ttls.s
  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 +475,6 @@@ EAPDYN += ../src/eap_peer/eap_md5.s
  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 +497,6 @@@ els
  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 +510,6 @@@ EAPDYN += ../src/eap_peer/eap_gtc.s
  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 +534,6 @@@ EAPDYN += ../src/eap_peer/eap_sim.s
  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 +561,6 @@@ EAPDYN += ../src/eap_peer/eap_psk.s
  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 +577,6 @@@ EAPDYN += ../src/eap_peer/eap_aka.s
  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 +602,6 @@@ endi
  
  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 +616,6 @@@ els
  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 +630,6 @@@ EAPDYN += ../src/eap_peer/eap_pax.s
  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 +642,6 @@@ EAPDYN += ../src/eap_peer/eap_sake.s
  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 +654,6 @@@ EAPDYN += ../src/eap_peer/eap_gpsk.s
  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 +666,6 @@@ endi
  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 +678,6 @@@ EAPDYN += ../src/eap_peer/eap_eke.s
  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 +700,6 @@@ OBJS += ../src/wps/wps_attr_process.
  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 +762,6 @@@ els
  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 +777,6 @@@ EAPDYN += ../src/eap_peer/eap_vendor_te
  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 +786,6 @@@ ifdef CONFIG_EAP_TN
  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 +845,8 @@@ OBJS += ../src/ap/ap_drv_ops.
  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 +856,9 @@@ endi
  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 +875,11 @@@ CFLAGS += -DCONFIG_IEEE80211A
  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 +915,10 @@@ OBJS += ../src/ap/peerkey_auth.
  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 +931,13 @@@ ifdef CONFIG_NATIVE_WINDOW
  #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 +976,6 @@@ ifdef TLS_FUNC
  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 +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 +1051,7 @@@ OBJS += ../src/tls/tlsv1_cred.
  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 +1105,8 @@@ CONFIG_INTERNAL_SHA1=
  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 +1292,19 @@@ SHA256OBJS += ../src/crypto/sha256-prf.
  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 +1347,7 @@@ endi
  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 +1389,7 @@@ ifndef DBUS_INCLUD
  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 +1415,7 @@@ DBUS_OBJS += dbus/dbus_new_introspect.
  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 +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 +1460,10 @@@ ifdef CONFIG_IPV
  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 +1590,6 @@@ endi
  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 +1651,7 @@@ endi
  OBJS += $(FST_OBJS)
  OBJS_t += $(FST_OBJS)
  OBJS_t2 += $(FST_OBJS)
+ OBJS_nfc += $(FST_OBJS)
  endif
  
  ifndef LDO
@@@ -1691,9 -1707,11 +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 +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)
  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 +1815,6 @@@ wpa_gui-qt4/lang/wpa_gui_de.qm: wpa_gui
  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 +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)
@@@ -1,7 -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 +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 +165,12 @@@ systems. In case of Windows builds, Win
  
  
  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 +304,7 @@@ Following build time configuration opti
  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 +316,17 @@@ CONFIG_EAP_GTC=
  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 +407,10 @@@ Command line option
  --------------------
  
  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:
    -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 +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 +514,7 @@@ reloading can be triggered with 'wpa_cl
  
  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 +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 +1022,8 @@@ event message is indicated that the ext
  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.
  
@@@ -229,7 -229,7 +229,7 @@@ Credentials can be pre-configured for a
  #
  # 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.
  #
  <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
@@@ -151,6 -151,7 +151,7 @@@ join-a-group style PD instead of GO Neg
  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 +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 +288,7 @@@ group interface is used as a parameter 
  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 +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 +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
@@@ -32,6 -32,9 +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 +95,7 @@@ CONFIG_EAP_TTLS=
  # 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 +324,10 @@@ CONFIG_IEEE80211W=
  # 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 +486,7 @@@ CONFIG_WIFI_DISPLAY=
  # Enable Fast Session Transfer (FST)
  #CONFIG_FST=y
  
+ # Support Multi Band Operation
+ #CONFIG_MBO=y
  include $(wildcard $(LOCAL_PATH)/android_config_*.inc)
@@@ -56,12 -56,32 +56,32 @@@ static void wpas_conf_ap_vht(struct wpa
        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 +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 */
  
                }
        }
  #endif /* CONFIG_IEEE80211N */
+       return 0;
  }
  
  
@@@ -179,15 -211,23 +211,23 @@@ static int wpa_supplicant_conf_ap(struc
  
        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;
        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 */
  
        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));
                        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] ||
                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 */
  
             !(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)
                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 */
  
                        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 +503,14 @@@ static void ap_wps_event_cb(void *ctx, 
        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 +585,11 @@@ static void wpas_ap_configured_cb(void 
  {
        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 +655,8 @@@ int wpa_supplicant_create_ap(struct wpa
                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
        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;
                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));
                }
  
                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 +936,10 @@@ int wpa_supplicant_ap_wps_pin(struct wp
                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 +1005,8 @@@ const char * wpas_wps_ap_pin_random(str
        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 +1341,8 @@@ int wpas_ap_wps_add_nfc_pw(struct wpa_s
        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;
        }
        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 +1384,58 @@@ int wpas_ap_stop_ap(struct wpa_supplica
        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 */
  
  
@@@ -76,12 -76,16 +76,16 @@@ int wpas_ap_wps_add_nfc_pw(struct wpa_s
                           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,
@@@ -1,6 -1,7 +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 +44,11 @@@ int autoscan_init(struct wpa_supplican
        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;
                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 +127,10 @@@ void autoscan_deinit(struct wpa_supplic
                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 +148,7 @@@ int autoscan_notify_scan(struct wpa_sup
                        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);
        }
@@@ -27,6 -27,16 +27,16 @@@ void autoscan_deinit(struct wpa_supplic
  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)
  #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
@@@ -39,6 -39,15 +39,15 @@@ void bgscan_notify_signal_change(struc
                                 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,
@@@ -12,6 -12,7 +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 +61,9 @@@ struct wpa_bss_anqp * wpa_bss_anqp_allo
        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 +84,7 @@@ static struct wpa_bss_anqp * wpa_bss_an
  
  #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 +146,10 @@@ int wpa_bss_anqp_unshare_alloc(struct w
   */
  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;
  
        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 +214,8 @@@ static void wpa_bss_update_pending_conn
  }
  
  
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 +304,47 @@@ static void wpa_bss_copy_res(struct wpa
  }
  
  
+ 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 +383,8 @@@ static int wpa_bss_remove_oldest_unknow
        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 +842,7 @@@ void wpa_bss_update_end(struct wpa_supp
        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 +1062,7 @@@ struct wpa_bss * wpa_bss_get_id_range(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 +1082,8 @@@ const u8 * wpa_bss_get_vendor_ie(const 
        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 +1119,8 @@@ const u8 * wpa_bss_get_vendor_ie_beacon
        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 +1155,8 @@@ struct wpabuf * wpa_bss_get_vendor_ie_m
        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 +1200,8 @@@ struct wpabuf * wpa_bss_get_vendor_ie_m
        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]))
@@@ -19,6 -19,12 +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 +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 +113,8 @@@ void wpa_bss_update_start(struct wpa_su
  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 +150,17 @@@ static inline int bss_is_dmg(const stru
        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)
@@@ -32,7 -32,11 +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 +63,7 @@@ static int wpa_config_parse_str(const s
                                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) {
  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 +209,9 @@@ static int wpa_config_parse_int(const s
                           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 +478,17 @@@ static int wpa_config_parse_psk(const s
                }
                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 +599,8 @@@ static int wpa_config_parse_proto(cons
                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 +737,8 @@@ static int wpa_config_parse_key_mgmt(co
                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 +933,9 @@@ static char * wpa_config_write_key_mgmt
  
  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'.",
                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;
        }
  
        return buf;
+ #endif /* CONFIG_NO_WPA */
  }
  #endif /* NO_CONFIG_WRITE */
  
@@@ -945,6 -987,8 +987,8 @@@ static int wpa_config_parse_pairwise(co
                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 +1025,8 @@@ static int wpa_config_parse_group(cons
                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 +1088,8 @@@ static int wpa_config_parse_auth_alg(co
                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 +1344,32 @@@ static int wpa_config_parse_eap(const s
        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 +1422,8 @@@ static int wpa_config_parse_password(co
        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;
  
        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 +1919,8 @@@ static const struct parse_data ssid_fie
        { 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) },
        { 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) },
        { INT(dot11MeshHoldingTimeout) },
  #endif /* CONFIG_MESH */
        { INT(wpa_ptk_rekey) },
+       { INT(group_rekey) },
        { STR(bgscan) },
        { INT_RANGE(ignore_broadcast_ssid, 0, 2) },
  #ifdef CONFIG_P2P
        { 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 +2361,11 @@@ void wpa_config_free(struct wpa_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 +2548,8 @@@ void wpa_config_set_network_defaults(st
   * @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 +2570,8 @@@ int wpa_config_set(struct wpa_ssid *ssi
                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 +2670,8 @@@ char ** wpa_config_get_all(struct wpa_s
        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 +2700,19 @@@ char * wpa_config_get(struct wpa_ssid *
  
        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 +2897,8 @@@ int wpa_config_set_cred(struct wpa_cre
  
        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;
        }
  
        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 +3654,11 @@@ struct wpa_config * wpa_config_alloc_em
        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 +3765,12 @@@ static int wpa_global_config_parse_str(
                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 +3809,12 @@@ static int wpa_global_config_parse_bin(
                                       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 +4361,16 @@@ static const struct global_parse_data g
        { 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 +4429,23 @@@ int wpa_config_get_value(const char *na
  }
  
  
+ 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;
@@@ -39,6 -39,8 +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 +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 +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
         *
         * 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;
  
         * 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 +1386,9 @@@ void wpa_config_debug_dump_networks(str
  /* 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 */
  
@@@ -747,10 -747,16 +747,16 @@@ static void wpa_config_write_network(FI
        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);
        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 +1143,22 @@@ static void wpa_config_write_global(FIL
        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",
  
        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 */
@@@ -360,6 -360,19 +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).
         */
        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
         *
  
        int vht;
  
+       u8 max_oper_chwidth;
+       unsigned int vht_center_freq2;
        /**
         * wpa_ptk_rekey - Maximum lifetime for PTK in seconds
         *
        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
         * 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 */
@@@ -933,6 -933,7 +933,7 @@@ static int wpa_config_write_network(HKE
  #ifdef CONFIG_HS20
        INT(update_identifier);
  #endif /* CONFIG_HS20 */
+       INT(group_rekey);
  
  #undef STR
  #undef INT
@@@ -15,6 -15,7 +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 +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 +312,33 @@@ static int wpas_ctrl_set_band(struct wp
  }
  
  
+ 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)
  {
                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)
  #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 */
                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) {
  #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 +998,8 @@@ static int wpa_supplicant_ctrl_iface_wp
        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 +1892,10 @@@ static int wpa_supplicant_ctrl_iface_st
                                                  "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 +2766,40 @@@ static int wpa_supplicant_ctrl_iface_me
        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 +2929,10 @@@ static int wpa_supplicant_ctrl_iface_ad
  
        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 +2945,7 @@@ static int wpa_supplicant_ctrl_iface_re
  {
        int id;
        struct wpa_ssid *ssid;
-       int was_disabled;
+       int result;
  
        /* cmd: "<network id>" or "all" */
        if (os_strcmp(cmd, "all") == 0) {
        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 +3000,29 @@@ static int wpa_supplicant_ctrl_iface_up
        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 +3997,15 @@@ static int wpa_supplicant_ctrl_iface_ge
        }
  #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 +4266,10 @@@ static int print_bss_info(struct wpa_su
        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 */
  
  #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",
                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 */
  
        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 +4760,7 @@@ static int p2ps_ctrl_parse_cpt_priority
                        return -1;
                }
  
-               if (isblank(*last)) {
+               if (isblank((unsigned char) *last)) {
                        i++;
                        break;
                }
@@@ -4848,6 -4932,30 +4932,30 @@@ static int p2p_ctrl_asp_provision(struc
  }
  
  
+ 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)
  {
        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;
        /* <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;
                        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, ' ');
                        *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);
  
        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 +5644,7 @@@ static int p2p_ctrl_invite_persistent(s
        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=");
        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 +5742,8 @@@ static int p2p_ctrl_invite(struct wpa_s
  
  
  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;
  
                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 +5766,14 @@@ static int p2p_ctrl_group_add(struct wp
        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;
                }
        }
  
+       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 +5982,15 @@@ static int p2p_ctrl_set(struct wpa_supp
        }
  
        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 +6251,21 @@@ static int p2p_ctrl_remove_client(struc
        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 +6383,7 @@@ static int get_anqp(struct wpa_supplica
        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)
  #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])
        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 +6596,7 @@@ static int get_hs20_anqp(struct wpa_sup
        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 +6619,7 @@@ static int hs20_nai_home_realm_list(str
  
        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 +6665,59 @@@ static int hs20_get_nai_home_realm_list
  
        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;
  
        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 +6823,27 @@@ static int wpas_ctrl_iface_wnm_sleep(st
  
  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 +6908,28 @@@ static int wpa_supplicant_signal_poll(s
  }
  
  
+ 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)
  {
  }
  
  
+ 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 +7062,13 @@@ static int wpa_supplicant_vendor_cmd(st
  
        /* 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 +7116,20 @@@ static void wpa_supplicant_ctrl_iface_f
  
        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;
        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;
  
  #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);
        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;
  #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;
        }
  
        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 +7298,13 @@@ static void wpas_ctrl_radio_work_cb(str
                        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 +7754,76 @@@ static void wpas_ctrl_iface_mgmt_tx_don
  }
  
  
+ 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 +7923,8 @@@ static u16 ipv4_hdr_checksum(const voi
  #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 +7958,8 @@@ static int wpas_ctrl_iface_data_test_co
                                            char *cmd)
  {
        int enabled = atoi(cmd);
+       char *pos;
+       const char *ifname;
  
        if (!enabled) {
                if (wpa_s->l2_test) {
        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 +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 +8122,6 @@@ static int wpas_ctrl_get_alloc_fail(str
                                    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 */
  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 +8155,6 @@@ static int wpas_ctrl_get_fail(struct wp
                                    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 */
  #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)
  {
        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)
  
        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;
        }
  
  
        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 +8287,7 @@@ static int wpas_ctrl_vendor_elem_get(st
  
        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 +8305,12 @@@ static int wpas_ctrl_vendor_elem_remove
        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)
        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;
        }
  
                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 +8575,7 @@@ static int wpas_ctrl_iface_mac_rand_sca
                        }
                } 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;
        }
                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) {
  }
  
  
+ 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 +8712,9 @@@ char * wpa_supplicant_ctrl_iface_proces
                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;
                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) {
        } 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;
        } 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) {
                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);
                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) {
        } 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;
        } 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);
        } 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);
                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,
                        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;
                        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)
                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 +9376,11 @@@ static int wpa_supplicant_global_iface_
        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);
  
                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);
                           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 +9585,31 @@@ static int wpa_supplicant_global_iface_
  
  
  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 +9675,7 @@@ static char * wpas_global_ctrl_iface_re
                "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 +9999,9 @@@ char * wpa_supplicant_global_ctrl_iface
        } 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,
                                                          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 */
@@@ -1,6 -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 +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 +93,8 @@@
        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)),
  }
  
  
- 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 */
        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 &&
                                   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 +302,16 @@@ static void wpa_supplicant_ctrl_iface_r
                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 +349,28 @@@ static void wpa_supplicant_ctrl_iface_m
                                             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 +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;
        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 +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 +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) {
                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;
        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);
                                   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,
                                dst->errors++;
                                if (dst->errors > 10) {
                                        wpa_supplicant_ctrl_iface_detach(
-                                               priv, &dst->addr,
+                                               head, &dst->addr,
                                                dst->addrlen);
                                }
                        } else
@@@ -513,12 -575,6 +575,6 @@@ void wpa_supplicant_ctrl_iface_wait(str
  
  /* 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 +602,13 @@@ static void wpa_supplicant_global_ctrl_
        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];
  
        }
  
  #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
                           "source %s", inet_ntoa(from.sin_addr));
                return;
        }
+ #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
  #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
  
        buf[res] = '\0';
        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 +702,7 @@@ wpa_supplicant_global_ctrl_iface_init(s
  {
        struct ctrl_iface_global_priv *priv;
        struct sockaddr_in addr;
+       char *pos;
        int port = WPA_GLOBAL_CTRL_IFACE_PORT;
  
        priv = os_zalloc(sizeof(*priv));
        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 +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;
        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 +778,7 @@@ wpa_supplicant_global_ctrl_iface_deinit
                eloop_unregister_read_sock(priv->sock);
                close(priv->sock);
        }
+       wpas_ctrl_iface_free_dst(priv->ctrl_dst);
        os_free(priv);
  }
@@@ -15,7 -15,6 +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 +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 +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 +89,7 @@@ static void wpas_ctrl_sock_debug(const 
        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,
  
  
  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 +133,7 @@@ static void wpa_supplicant_ctrl_iface_r
        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 +279,209 @@@ static char * wpa_supplicant_ctrl_iface
  }
  
  
+ 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 +699,7 @@@ wpa_supplicant_ctrl_iface_init(struct w
        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 +793,8 @@@ static int wpas_ctrl_iface_reinit(struc
  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;
  
  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 +927,31 @@@ static void wpa_supplicant_ctrl_iface_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 +985,12 @@@ void wpa_supplicant_ctrl_iface_wait(str
  {
        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 +1048,7 @@@ static void wpa_supplicant_global_ctrl_
        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 +1298,7 @@@ wpa_supplicant_global_ctrl_iface_init(s
        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 +1348,7 @@@ voi
  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);
        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);
  }
          <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>
@@@ -13,6 -13,8 +13,8 @@@
  
  #include <dbus/dbus.h>
  
+ struct wpa_dbus_property_desc;
  struct wpas_dbus_priv {
        DBusConnection *con;
        int should_dispatch;
        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 */
@@@ -205,24 -205,6 +205,6 @@@ dbus_bool_t wpa_dbus_dict_append_string
  
  
  /**
-  * 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 +299,6 @@@ dbus_bool_t wpa_dbus_dict_append_uint32
  
  
  /**
-  * 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
@@@ -26,9 -26,6 +26,6 @@@ const char * wpa_dbus_type_as_string(co
  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 +46,6 @@@ dbus_bool_t wpa_dbus_dict_append_uint32
                                        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);
@@@ -1207,7 -1207,7 +1207,7 @@@ static int match_group_where_peer_is_cl
                                         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 +1224,7 @@@ static void signal_peer_groups_changed(
        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 +1254,11 @@@ static void peer_groups_changed(struct 
   * 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;
                                              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 +1948,7 @@@ void wpas_dbus_signal_p2p_invitation_re
        }
  
        dbus_connection_send(iface->con, msg, NULL);
+       dbus_message_unref(msg);
  }
  
  
@@@ -2000,6 -1999,10 +1999,10 @@@ void wpas_dbus_signal_prop_changed(stru
                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 +2175,54 @@@ static const struct wpa_dbus_method_des
                  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[] = {
  };
  
  
+ 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)
        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,
        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 +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 +2514,65 @@@ int wpas_dbus_unregister_network(struc
  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 +3072,202 @@@ static const struct wpa_dbus_method_des
          }
        },
  #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[] = {
                  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 },
  };
  
  
+ 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
   */
  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;
        }
  
        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 +3717,80 @@@ int wpas_dbus_unregister_interface(stru
  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[] = {
   *    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;
        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 +3870,11 @@@ void wpas_dbus_signal_peer_device_found
  {
        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 +3889,7 @@@ void wpas_dbus_signal_peer_device_lost(
  {
        wpas_dbus_signal_peer(wpa_s, dev_addr,
                              WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-                             "DeviceLost");
+                             "DeviceLost", FALSE);
  }
  
  /**
@@@ -3805,41 -4056,50 +4056,50 @@@ void wpas_dbus_signal_peer_groups_chang
  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 +4226,10 @@@ static const struct wpa_dbus_property_d
        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 */
@@@ -29,6 -29,7 +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 +190,7 @@@ void wpas_dbus_signal_p2p_go_neg_req(st
                                     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 +400,7 @@@ static inline void wpas_dbus_signal_p2p
  
  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)
  {
  }
  
@@@ -435,7 -435,8 +435,8 @@@ dbus_bool_t wpas_dbus_simple_array_prop
  
        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 +712,9 @@@ DBusMessage * wpas_dbus_handler_get_int
   *
   * 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;
   *
   * 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);
   *
   * 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);
   *
   * 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;
   *
   * 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;
   *
   * 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;
   * 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;
   * 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;
   * 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 +1475,7 @@@ DBusMessage * wpas_dbus_handler_disconn
                                           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 +1504,7 @@@ DBusMessage * wpas_dbus_handler_add_net
        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__);
                        "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 +1577,27 @@@ DBusMessage * wpas_dbus_handler_reassoc
  
  
  /**
+  * 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 +1659,7 @@@ DBusMessage * wpas_dbus_handler_remove_
        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);
                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 +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 +2273,35 @@@ DBusMessage * wpas_dbus_handler_tdls_te
  #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 +2369,9 @@@ DBusMessage * wpas_dbus_handler_set_pkc
   *
   * 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;
                                              &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 +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;
   *
   * 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;
   *
   * 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;
   *
   * 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;
   *
   * 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;
   *
   * 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;
   * 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;
  
  
  /**
+  * 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
   *
   * 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;
   *
   * 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;
   *
   * 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;
   *
   * 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;
   *
   * 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];
   *
   * 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;
   *
   * 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;
   *
   * 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;
   *
   * 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;
   *
   * 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;
   *
   * 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;
   *
   * 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;
   *
   * 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;
                            "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,
   *
   * 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;
  
  
  /**
+  * 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
   *
   * 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 +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 +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;
   *
   * 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;
   *
   * 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;
  }
  
  
+ 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)
  {
   *
   * 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;
   *
   * 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;
   *
   * 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;
   *
   * 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;
   *
   * 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;
   *
   * 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 +3778,9 @@@ static int cmp_u8s_desc(const void *a, 
   *
   * 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;
  }
  
  
- 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 +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;
                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);
  }
  
  
   *
   * 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;
                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);
  }
  
  
   *
   * 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 +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;
   *
   * 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;
   *
   * 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;
   *
   * 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;
   *
   * 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 +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;
  }
  
  #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");
+ }
@@@ -10,6 -10,8 +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 +52,20 @@@ DBusMessage * wpas_dbus_handler_remove_
  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 +129,52 @@@ DBusMessage * wpas_dbus_handler_eap_log
  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);
  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 +196,16 @@@ DBusMessage * wpas_dbus_handler_tdls_st
  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,
@@@ -364,13 -364,14 +364,14 @@@ DBusMessage * wpas_dbus_handler_p2p_gro
                        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 +583,7 @@@ DBusMessage * wpas_dbus_handler_p2p_con
  
        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 +734,8 @@@ DBusMessage * wpas_dbus_handler_p2p_inv
                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 +808,9 @@@ DBusMessage * wpas_dbus_handler_p2p_pro
   * 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 +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;
                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);
  }
  
  
- 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 +1204,9 @@@ static enum wpas_p2p_role wpas_get_p2p_
  }
  
  
- 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;
  }
  
  
- 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];
  }
  
  
- 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;
   * 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;
  }
  
  
- 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;
  }
  
  
- 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;
  }
  
  
- 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;
  }
  
  
- 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;
  
  
  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;
  }
  
  
- 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;
  }
  
  
- 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;
  }
  
  
- 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;
  }
  
  
- 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;
  
  
  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;
  }
  
  
- 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;
  }
  
  
- 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;
  }
  
  
- 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 +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 +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;
   *
   * 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);
  }
  
  
   *
   * 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 +2151,9 @@@ DBusMessage * wpas_dbus_handler_remove_
   * 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 +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;
  
  }
  
  
- 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);
  }
  
  
- 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;
  }
  
  
- 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;
  }
  
  
- 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;
  }
  
  
- 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;
  }
  
  
- 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 +2887,9 @@@ DBusMessage * wpas_dbus_handler_p2p_ser
  
  #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;
  }
  
  
- 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;
@@@ -89,139 -89,50 +89,50 @@@ DBusMessage *wpas_dbus_handler_p2p_serv
  /*
   * 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 +144,8 @@@ DBusMessage * wpas_dbus_handler_remove_
        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 */
@@@ -325,7 -325,7 +325,7 @@@ DBusMessage * wpas_dbus_handler_wps_sta
   * @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,
   * 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;
   * 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;
   * 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;
   * 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;
@@@ -46,7 -46,7 +46,7 @@@ static dbus_bool_t fill_dict_with_prope
                        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 +176,7 @@@ static DBusMessage * properties_get(DBu
        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 +213,7 @@@ static DBusMessage * properties_set(DBu
  
        /* 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 +627,8 @@@ static dbus_bool_t put_changed_properti
                        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",
@@@ -16,9 -16,13 +16,13 @@@ typedef DBusMessage * (*WPADBusMethodHa
                                              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 +93,8 @@@ struct wpa_dbus_property_desc 
        WPADBusPropertyAccessor getter;
        /* property setter function */
        WPADBusPropertyAccessor setter;
+       /* other data */
+       const char *data;
  };
  
  
@@@ -38,7 -38,7 +38,7 @@@ static struct interfaces * add_interfac
        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 +257,7 @@@ DBusMessage * wpa_dbus_introspect(DBusM
        DBusMessage *reply;
        struct wpabuf *xml;
  
-       xml = wpabuf_alloc(15000);
+       xml = wpabuf_alloc(20000);
        if (xml == NULL)
                return NULL;
  
@@@ -717,16 -717,13 +717,13 @@@ DBusMessage * wpas_dbus_iface_add_netwo
        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 +755,7 @@@ DBusMessage * wpas_dbus_iface_remove_ne
        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,
        }
  
        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 +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);
  }
@@@ -31,6 -31,9 +31,9 @@@ CONFIG_DRIVER_WEXT=
  # 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 +270,9 @@@ CONFIG_BACKEND=fil
  # 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
  # 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
  
  # 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
  
  
  # 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
@@@ -194,7 -194,7 +194,7 @@@ eapol_test -ctest.conf -a127.0.0.1 -p18
    </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>
@@@ -90,7 -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>
@@@ -345,7 -345,7 +345,7 @@@ CTRL-REQ-OTP-2:Challenge 1235663 neede
    </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>
@@@ -91,7 -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>
@@@ -62,7 -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>
@@@ -137,7 -137,7 +137,7 @@@ wpa_supplicant -i ath0 -c wpa_supplican
    </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>
        </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 +729,7 @@@ f
    </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>
@@@ -100,12 -100,10 +100,10 @@@ static inline int wpa_drv_scan(struct w
  }
  
  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 +158,15 @@@ static inline int wpa_drv_set_key(struc
        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 +299,7 @@@ static inline int wpa_drv_send_mlme(str
        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 +408,7 @@@ static inline int wpa_drv_if_add(struc
        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 +733,11 @@@ static inline int wpa_drv_set_replay_pr
  }
  
  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 +918,62 @@@ static inline int wpa_drv_set_prob_oper
        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 */
@@@ -14,6 -14,7 +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 +193,7 @@@ static void ieee802_1x_encapsulate_radi
                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);
                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 +1247,7 @@@ static void eapol_test_terminate(int si
  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"
               "  -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 +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) {
                        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;
@@@ -72,6 -72,7 +72,7 @@@ static int wpas_temp_disabled(struct wp
  }
  
  
+ #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 +108,7 @@@ static int wpas_reenabled_network_time(
  
        return res;
  }
+ #endif /* CONFIG_NO_SCAN_PROCESSING */
  
  
  void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx)
@@@ -279,6 -281,11 +281,11 @@@ void wpa_supplicant_mark_disassoc(struc
        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;
  
        wpa_s->key_mgmt = 0;
  
        wpas_rrm_reset(wpa_s);
+       wpa_s->wnmsleep_used = 0;
  }
  
  
@@@ -564,11 -572,36 +572,36 @@@ static int wpa_supplicant_ssid_bss_matc
                        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 +839,10 @@@ static int addr_in_list(const u8 *addr
  }
  
  
- 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;
        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;
                        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;
                }
  
                        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");
                                (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 +1376,7 @@@ static int wpa_supplicant_need_to_roam(
        struct wpa_bss *current_bss = NULL;
  #ifndef CONFIG_NO_ROAMING
        int min_diff;
+       int to_5ghz;
  #endif /* CONFIG_NO_ROAMING */
  
        if (wpa_s->reassociate)
                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;
                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 +1503,8 @@@ static int _wpa_supplicant_event_scan_r
                        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);
  #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);
  
        }
  
        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;
  
        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;
  
        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);
  
  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 +1641,14 @@@ static int wpas_select_network_from_las
  
        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);
                        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;
                 */
                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 +1932,50 @@@ static void interworking_process_assoc_
  #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)
  {
                }
                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;
        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 +2198,50 @@@ static int wpa_supplicant_assoc_update_
  }
  
  
+ 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
                                "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;
        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
         * 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);
            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 +2518,7 @@@ static void wpa_supplicant_event_disass
        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);
                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");
        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,
        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;
            !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 +2820,13 @@@ wpa_supplicant_event_interface_status(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 +3212,16 @@@ static void wpa_supplicant_update_chann
  {
        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 : "");
                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 +3336,14 @@@ static void wpas_event_rx_mgmt_action(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 +3433,7 @@@ void wpa_supplicant_event(void *ctx, en
        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",
  
        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;
                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",
                }
                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);
                }
                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 */
        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 {
  #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 ?
                                       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:
  #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,
                }
  
                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,
                                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);
                                         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.
                 */
                                     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);
+ }
@@@ -17,6 -17,7 +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 +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 +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 +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 +117,6 @@@ static const char * gas_result_txt(enu
                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 +158,7 @@@ static void gas_query_done(struct gas_q
                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 +243,13 @@@ static void gas_query_tx_status(struct 
                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 +269,13 @@@ static int pmf_in_use(struct wpa_suppli
  
  
  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),
                *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 +309,7 @@@ static void gas_query_tx_comeback_req(s
                                      struct gas_query_pending *query)
  {
        struct wpabuf *req;
+       unsigned int wait_time;
  
        req = gas_build_comeback_req(query->dialog_token);
        if (req == NULL) {
                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);
  }
  
  
+ 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 +376,11 @@@ static void gas_query_tx_comeback_req_d
  {
        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 +433,7 @@@ static void gas_query_rx_comeback(struc
                   "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 +510,16 @@@ int gas_query_rx(struct gas_query *gas
        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;
                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 +683,18 @@@ static void gas_query_start_cb(struct w
        }
  
        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;
                   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 +745,13 @@@ int gas_query_req(struct gas_query *gas
  {
        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)
  
        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);
- }
@@@ -29,7 -29,6 +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 +39,6 @@@ int gas_query_req(struct gas_query *gas
                             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 */
  
@@@ -25,6 -25,7 +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 +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 +205,8 @@@ void hs20_put_anqp_req(u32 stypes, cons
  }
  
  
- 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;
  
  
  
  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) {
        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)
  {
        }
  }
  
+ 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) {
        }
        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 +549,7 @@@ static void hs20_osu_icon_fetch_result(
  
  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;
  
        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) {
                }
                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) {
                                "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));
                }
                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) {
                }
                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) {
                }
                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) {
                }
                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 +703,10 @@@ static void hs20_osu_fetch_done(struct 
                 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 +774,8 @@@ void hs20_next_osu_icon(struct wpa_supp
                        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 +813,7 @@@ static void hs20_osu_add_prov(struct wp
        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;
        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;
                }
        }
  
        /* 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;
        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;
        }
  
        /* 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;
                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;
                }
                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;
        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 +1012,9 @@@ void hs20_osu_icon_fetch(struct wpa_sup
                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;
                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;
                           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 +1078,7 @@@ static void hs20_osu_scan_res_handler(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 - "
        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 +1207,16 @@@ void hs20_rx_deauth_imminent_notice(str
  }
  
  
+ 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);
  }
@@@ -8,17 -8,16 +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 +31,16 @@@ void hs20_rx_deauth_imminent_notice(str
  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 */
@@@ -221,6 -221,7 +221,7 @@@ static int ibss_rsn_supp_init(struct ib
        peer->supp = wpa_sm_init(ctx);
        if (peer->supp == NULL) {
                wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
+               os_free(ctx);
                return -1;
        }
  
        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 +405,7 @@@ static void auth_set_eapol(void *ctx, c
  
  
  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;
        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 +666,8 @@@ void ibss_rsn_stop(struct ibss_rsn *ibs
  }
  
  
- 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;
  
                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;
        }
@@@ -51,7 -51,8 +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);
@@@ -362,13 -362,13 +362,13 @@@ static const u8 * nai_realm_parse_eap(s
        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;
        }
        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 +468,7 @@@ static const u8 * nai_realm_parse_realm
  
        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));
  
        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));
                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 +751,7 @@@ static int plmn_id_match(struct wpabuf 
                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);
        }
        pos++;
        udhl = *pos++;
-       if (pos + udhl > end) {
+       if (udhl > end - pos) {
                wpa_printf(MSG_DEBUG, "Invalid UDHL");
                return 0;
        }
                   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;
  
                                    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 +950,9 @@@ static int interworking_set_hs20_params
        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 +1085,12 @@@ static int roaming_consortium_element_m
         * 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 +1124,7 @@@ static int roaming_consortium_anqp_matc
        /* 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 +1185,7 @@@ static int cred_excluded_ssid(struct wp
  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;
                if (cred->min_ul_bandwidth_roaming > ul_bandwidth)
                        return 1;
        }
+ #endif /* CONFIG_HS20 */
  
        return 0;
  }
@@@ -1260,9 -1265,11 +1265,11 @@@ static int cred_over_max_bss_load(struc
  }
  
  
+ #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;
  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;
        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;
                        }
                }
        }
+ #endif /* CONFIG_HS20 */
  
        return 0;
  }
@@@ -1438,7 -1449,24 +1449,24 @@@ static int interworking_set_eap_params(
                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 +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;
        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)
        }
  
        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)) {
                /*
                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;
        }
  
                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;
        }
  
                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;
        }
  
                        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;
                }
  
                        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;
                }
  
                        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 +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 +2145,27 @@@ int domain_name_list_contains(struct wp
        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 +2588,13 @@@ static void interworking_next_anqp_fetc
                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))
        }
  
        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 &&
                        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 +2692,11 @@@ void interworking_stop_fetch_anqp(struc
  
  
  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;
  
  #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;
  
  }
  
  
+ 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;
  
        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);
                }
                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) {
                }
                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 "
                }
                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);
                }
                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",
                }
                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) {
                }
                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);
                }
                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) {
                        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,
        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 +2954,10 @@@ void anqp_resp_cb(void *ctx, const u8 *
                   " 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;
        }
            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;
        }
                        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);
@@@ -12,7 -12,8 +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,
@@@ -65,41 -65,44 +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 +156,28 @@@ static void wpa_supplicant_fd_workaroun
  }
  
  
+ #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;
  
        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) {
                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,
                     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();
                }
        }
  
+ #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);
  
  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();
@@@ -66,9 -66,11 +66,11 @@@ void wpa_supplicant_mesh_iface_deinit(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)
                        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 +178,7 @@@ static int wpa_supplicant_mesh_init(str
        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;
                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 +365,47 @@@ int wpa_supplicant_join_mesh(struct wpa
  
        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;
  
        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;
  
                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 +624,22 @@@ int wpas_mesh_add_interface(struct wpa_
        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);
+ }
@@@ -18,6 -18,9 +18,9 @@@ int wpas_mesh_scan_result_text(const u
                               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
  
  #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 +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 +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 +70,10 @@@ static int mesh_mpm_parse_peer_mgmt(str
  {
        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) ||
                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 +191,13 @@@ static void mesh_mpm_init_link(struct w
  
        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 +211,6 @@@ static void mesh_mpm_send_plink_action(
        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;
                           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 */
  
  
                /* 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);
                /* 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);
  
  #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,
                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 +383,17 @@@ void wpa_mesh_set_plink_state(struct wp
        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 +419,11 @@@ static void plink_timer(void *eloop_ctx
        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(
                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 +480,8 @@@ mesh_mpm_plink_open(struct wpa_supplica
  }
  
  
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;
  }
  
  
+ 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];
  
        hapd->num_plinks = 0;
        hostapd_free_stas(hapd);
+       eloop_cancel_timeout(peer_add_timer, wpa_s, NULL);
  }
  
  
@@@ -522,7 -629,7 +629,7 @@@ void mesh_mpm_auth_peer(struct wpa_supp
        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 +648,14 @@@ static struct sta_info * mesh_mpm_add_p
        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);
                        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 +737,9 @@@ void wpa_mesh_new_mesh_peer(struct wpa_
        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) {
                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 +801,85 @@@ static void mesh_mpm_plink_estab(struc
                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);
                        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,
                        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);
                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);
                                                   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);
                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,
                                " 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 +1040,14 @@@ void mesh_mpm_action_rx(struct wpa_supp
        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;
                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;
        }
                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);
  
        /*
         * 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) {
        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) {
        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;
                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;
                         * 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:
                /*
                 */
                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);
  }
@@@ -14,10 -14,13 +14,13 @@@ void wpa_mesh_new_mesh_peer(struct wpa_
                            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
  
  
  #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
                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 +136,8 @@@ static int auth_start_ampe(void *ctx, c
  }
  
  
- 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;
        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;
        }
  
        /* 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;
  }
  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 +229,12 @@@ struct mesh_rsn *mesh_rsn_auth_init(str
        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 +317,7 @@@ int mesh_rsn_auth_sae_sta(struct wpa_su
  {
        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;
  
                        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;
  
                "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;
  
  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 +386,27 @@@ mesh_rsn_derive_aek(struct mesh_rsn *rs
  {
        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 +418,44 @@@ int mesh_rsn_derive_mtk(struct wpa_supp
  {
        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;
                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 +498,94 @@@ int mesh_rsn_protect_frame(struct mesh_
  {
        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;
  }
  
  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");
                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;
        }
        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;
        }
  
        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;
  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 +38,7 @@@ int mesh_rsn_protect_frame(struct mesh_
                           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);
  
@@@ -13,6 -13,7 +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 +35,12 @@@ int wpas_notify_supplicant_initialized(
        }
  #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 +51,11 @@@ void wpas_notify_supplicant_deinitializ
        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 +140,15 @@@ void wpas_notify_disconnect_reason(stru
  }
  
  
+ 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 +668,13 @@@ void wpas_notify_p2p_provision_discover
  
  
  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);
  }
  
  
@@@ -23,6 -23,7 +23,7 @@@ void wpas_notify_state_changed(struct w
                               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 +113,7 @@@ void wpas_notify_p2p_provision_discover
                                         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);
@@@ -23,8 -23,29 +23,29 @@@ wpas_get_tx_interface(struct wpa_suppli
  {
        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 +139,9 @@@ static void wpas_send_action_cb(void *e
        }
  
        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 +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 +276,11 @@@ int offchannel_send_action(struct wpa_s
  
        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;
        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 +463,9 @@@ const void * offchannel_pending_action_
   */
  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;
  }
   */
  #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 +124,10 @@@ wpas_p2p_get_group_iface(struct wpa_sup
                         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 +351,7 @@@ static int wpas_p2p_scan(void *ctx, enu
        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;
        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,
                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 +551,39 @@@ static unsigned int p2p_group_go_member
  }
  
  
+ 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) */
  }
  
  
- /* 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 +626,34 @@@ wpas_p2p_get_persistent_go(struct 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.
         * 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) {
        /* 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;
  
                         * 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;
        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;
                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 +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 +877,7 @@@ static int wpas_p2p_group_delete(struc
  
        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);
        }
                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);
        }
        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;
                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 +1076,7 @@@ static int wpas_p2p_persistent_group(st
                   "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 +1134,8 @@@ static int wpas_p2p_store_persistent_gr
        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 +1275,7 @@@ static void wpas_p2p_group_started(stru
         * 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 +1301,6 @@@ static void wpas_group_formation_comple
        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
        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)
                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;
        }
  
        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 +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)
  {
                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 +1436,13 @@@ static void wpas_p2p_action_tx_clear(st
  {
        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 +1498,7 @@@ static void wpas_p2p_send_action_tx_sta
                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 +1641,11 @@@ static void wpas_start_wps_enrollee(str
        } 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 +1671,7 @@@ static void wpas_p2p_add_psk_list(struc
        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 +1736,8 @@@ static void p2p_go_save_group_common_fr
  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 +1748,15 @@@ static void p2p_go_configured(void *ctx
        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);
                                       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,
                        } 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);
  
                        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;
                                          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 +1881,14 @@@ static void wpas_start_wps_go(struct wp
        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);
                 */
                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);
                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 +1948,12 @@@ static void wpas_p2p_clone_config(struc
        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);
        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 +2142,7 @@@ static void wpas_p2p_group_formation_fa
                                            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 +2153,9 @@@ static void wpas_p2p_grpform_fail_after
  {
        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 +2166,16 @@@ void wpas_p2p_ap_setup_failed(struct wp
                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);
                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
        }
  
        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);
                        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 +2378,10 @@@ static void wpas_dev_lost(void *ctx, co
  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 +2595,13 @@@ static void wpas_prov_disc_req(void *ct
        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 +2646,13 @@@ static void wpas_prov_disc_resp(void *c
        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 +2675,7 @@@ static void wpas_prov_disc_fail(void *c
        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 +2771,29 @@@ static int wpas_p2p_go_is_peer_freq(str
  }
  
  
+ 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 +2920,11 @@@ static u8 wpas_invitation_process(void 
                                   "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 +3006,31 @@@ static void wpas_invitation_received(vo
                           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 +3131,7 @@@ static void wpas_remove_persistent_clie
        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 +3159,37 @@@ static void wpas_invitation_result(voi
        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) {
                                      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 +3331,6 @@@ static int wpas_p2p_default_channels(st
  }
  
  
- 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 +3364,12 @@@ static int has_channel(struct wpa_globa
  }
  
  
- 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 +3425,75 @@@ static enum chan_allowed wpas_p2p_verif
  }
  
  
+ 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)
                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 +3540,14 @@@ static int wpas_p2p_setup_channels(stru
  
        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 +3602,13 @@@ int wpas_p2p_get_ht40_mode(struct 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 +3633,15 @@@ int wpas_p2p_get_vht80_center(struct wp
  }
  
  
+ 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 +3773,7 @@@ int wpas_p2p_add_p2pdev_interface(struc
                return -1;
        }
  
+       p2pdev_wpa_s->p2pdev = p2pdev_wpa_s;
        wpa_s->pending_interface_name[0] = '\0';
        return 0;
  }
@@@ -3638,11 -3835,12 +3835,12 @@@ static int wpas_get_persistent_group(vo
  
  
  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
         * 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 +3956,13 @@@ static void wpas_p2ps_prov_complete(voi
                                    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];
        }
  
        /* 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)) {
                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,
                                        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;
                        }
  
                        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) {
        }
  
        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 +4244,13 @@@ static int wpas_prov_disc_resp_cb(void 
  {
        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))
  
        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 +4555,7 @@@ static void wpas_p2p_deinit_global(stru
  
  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 +4636,7 @@@ static void wpas_p2p_check_join_scan_li
                                       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 +4772,7 @@@ static void wpas_p2p_scan_res_join(stru
                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,
                                         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;
                }
  
                           "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;
                }
                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,
                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(
  
  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 +4944,7 @@@ static void wpas_p2p_join_scan_req(stru
        struct wpabuf *wps_ie, *ies;
        size_t ielen;
        int freqs[2] = { 0, 0 };
+       unsigned int bands;
  
        os_memset(&params, 0, sizeof(params));
  
                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;
                /*
                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 +5100,13 @@@ static int wpas_p2p_join_start(struct w
                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;
                        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 +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
  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;
  
        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)
        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';
  
                }
                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;
        }
  
                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);
        }
  
  
  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) {
                        }
                }
  
-               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);
        }
  
        /* 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;
                }
                                                       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 +5991,20 @@@ wpas_p2p_get_group_iface(struct wpa_sup
        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;
        }
  
   * @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;
  
        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 +6118,10 @@@ static int wpas_start_p2p_client(struc
        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) {
        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;
  
  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;
                           "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
                                   "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;
        }
                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 +6318,8 @@@ struct p2p_group * wpas_p2p_group_init(
        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));
        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 +6375,7 @@@ void wpas_p2p_wps_success(struct wpa_su
                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) {
                        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
                        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 +6443,7 @@@ void wpas_p2p_wps_failed(struct wpa_sup
                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 +6468,14 @@@ int wpas_p2p_prov_disc(struct wpa_suppl
        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 +6536,12 @@@ static void wpas_p2p_clear_pending_acti
        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 +6632,12 @@@ int wpas_p2p_listen(struct wpa_supplica
        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 +6711,7 @@@ int wpas_p2p_probe_req_rx(struct wpa_su
                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 +6743,15 @@@ void wpas_p2p_rx_action(struct wpa_supp
  
  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 +6781,8 @@@ int wpas_p2p_reject(struct wpa_supplica
  /* 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;
  
        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) {
                                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;
                                   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 +6877,8 @@@ int wpas_p2p_invite_group(struct wpa_su
        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)
  
        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) {
                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 +6944,6 @@@ void wpas_p2p_completed(struct wpa_supp
  {
        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];
  
        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)
                               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 +7338,7 @@@ int wpas_p2p_set_cross_connect(struct w
  
                        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 +7368,7 @@@ static void wpas_p2p_enable_cross_conne
                        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 +7388,7 @@@ static void wpas_p2p_disable_cross_conn
                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 +7451,7 @@@ static void wpas_p2p_cross_connect_setu
                        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 +7467,8 @@@ int wpas_p2p_notif_pbc_overlap(struct w
  
        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 +7575,7 @@@ int wpas_p2p_cancel(struct wpa_supplica
                                   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;
                                   wpa_s->ifname);
                        found = 1;
                        wpas_p2p_group_formation_failed(wpa_s, 0);
+                       break;
                }
        }
  
@@@ -7367,7 -7705,7 +7705,7 @@@ void wpas_p2p_network_removed(struct wp
  {
        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
                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 +7761,7 @@@ void wpas_p2p_notify_ap_sta_authorized(
                                       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 +7817,12 @@@ static int wpas_p2p_fallback_to_go_neg(
        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 +7840,7 @@@ int wpas_p2p_scan_no_go_seen(struct wpa
  
        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 +7949,7 @@@ void wpas_p2p_new_psk_cb(struct wpa_sup
                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");
                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) {
        }
        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 +8170,14 @@@ int wpas_p2p_4way_hs_failed(struct wpa_
  
                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 +8356,10 @@@ static int wpas_p2p_nfc_join_group(stru
  
        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 +8386,17 @@@ static int wpas_p2p_nfc_auth_join(struc
                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;
  
  
        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 +8435,9 @@@ static int wpas_p2p_nfc_init_go_neg(str
                   "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 +8451,9 @@@ static int wpas_p2p_nfc_resp_go_neg(str
                   "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 +8744,9 @@@ int wpas_p2p_nfc_tag_enabled(struct wpa
                }
  
                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 +8822,115 @@@ static void wpas_p2p_optimize_listen_ch
  
  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 +8950,7 @@@ static void wpas_p2p_move_go_no_csa(str
        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 +8987,13 @@@ static void wpas_p2p_move_go(void *eloo
  
        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 +9070,25 @@@ static void wpas_p2p_consider_moving_on
                           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;
+                       }
                }
        }
  
                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 +9212,86 @@@ void wpas_p2p_ap_deinit(struct wpa_supp
                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;
+ }
@@@ -34,17 -34,22 +34,22 @@@ struct wpa_supplicant * wpas_get_p2p_cl
                                                  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 +116,8 @@@ void wpas_sd_response(void *ctx, const 
  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 +146,8 @@@ int wpas_p2p_get_ht40_mode(struct 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 +207,10 @@@ int wpas_p2p_wps_eapol_cb(struct wpa_su
  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 */
  
@@@ -48,7 -48,7 +48,7 @@@ static int p2p_sd_dns_uncompress_label(
                        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;
                        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 +722,11 @@@ void wpas_sd_request(void *ctx, int fre
        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 +827,10 @@@ static void wpas_sd_p2ps_serv_response(
                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 +917,13 @@@ void wpas_sd_response(void *ctx, const 
                }
        }
  
-       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;
@@@ -36,8 -36,7 +36,7 @@@ static void wpa_supplicant_gen_assoc_ev
  
        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 +59,7 @@@ static int wpas_wps_in_use(struct 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 +162,8 @@@ static void wpas_trigger_scan_cb(struc
        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 +227,11 @@@ int wpa_supplicant_trigger_scan(struct 
        }
  
        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 +263,14 @@@ wpa_supplicant_sched_scan_timeout(void 
  }
  
  
- 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
  }
  
  
- 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 +426,39 @@@ static void wpas_add_interworking_eleme
  #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;
        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 &&
                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 +572,6 @@@ static int non_p2p_network_enabled(stru
  #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 +621,12 @@@ static void wpa_set_scan_ssids(struct w
        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 +881,10 @@@ static void wpa_supplicant_scan(void *e
                 * 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 +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:
  #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 +1244,7 @@@ int wpa_supplicant_req_sched_scan(struc
        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;
        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;
  
        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;
        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);
                }
        }
  
-       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) {
                                       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 +1556,9 @@@ void wpa_supplicant_cancel_sched_scan(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 +1618,7 @@@ static int wpa_scan_get_max_rate(const 
   */
  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 +1639,8 @@@ const u8 * wpa_scan_get_vendor_ie(cons
        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 +1676,8 @@@ const u8 * wpa_scan_get_vendor_ie_beaco
        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 +1712,8 @@@ struct wpabuf * wpa_scan_get_vendor_ie_
        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 +1921,8 @@@ int wpa_supplicant_filter_bssid_match(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;
  
  
  /*
   * 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 +2039,8 @@@ static unsigned int max_vht80_rate(int 
  }
  
  
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 +2237,9 @@@ void scan_only_handler(struct wpa_suppl
                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 +2306,19 @@@ wpa_scan_clone_params(const struct wpa_
        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;
  
                        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 +2367,7 @@@ void wpa_scan_free_params(struct wpa_dr
        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
         */
        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;
  
                }
        }
  
+       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;
                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) {
        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");
                }
        }
  
-       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 +2542,7 @@@ int wpas_stop_pno(struct wpa_supplican
                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 +2610,160 @@@ int wpas_mac_addr_rand_scan_set(struct 
        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);
+ }
@@@ -39,20 -39,25 +39,25 @@@ void wpa_supplicant_update_scan_int(str
  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 */
@@@ -161,9 -161,10 +161,10 @@@ static void sme_auth_handle_rrm(struct 
                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;
        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 +212,9 @@@ static void sme_send_authentication(str
        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 "
        }
  #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);
        }
  #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) {
                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;
                }
        }
  
-       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 &&
        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 +677,8 @@@ void sme_authenticate(struct wpa_suppli
                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 +859,7 @@@ void sme_event_auth(struct wpa_supplica
                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 +1022,8 @@@ void sme_associate(struct wpa_supplican
        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 +1367,6 @@@ int sme_proc_obss_scan(struct wpa_suppl
  }
  
  
- 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 +1585,10 @@@ static void sme_sa_query_timer(void *el
        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);
  
        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;
        }
  
@@@ -5,9 -5,9 +5,9 @@@ Wants=network.targe
  
  [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
@@@ -88,7 -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;
@@@ -24,6 -24,7 +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,
  
  /* 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 +140,8 @@@ int ieee802_11_send_wnmsleep_req(struc
        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);
  
  
  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);
                /* 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 +192,14 @@@ static void wnm_sleep_mode_exit_success
        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 +250,20 @@@ static void ieee802_11_rx_wnmsleep_resp
         * 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);
                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 +430,7 @@@ static int wnm_nei_get_chan(struct wpa_
  {
        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);
                        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 +500,7 @@@ static void wnm_parse_neighbor_report(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;
        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);
                        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) {
                        /*
                        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)",
  }
  
  
+ 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;
                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,
  }
  
  
+ 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;
        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");
        }
  
        /* 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;
        }
  
        /* 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 +1056,90 @@@ static void wnm_set_scan_freqs(struct w
  }
  
  
+ 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)
                   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;
                }
        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;
                }
        }
  
+ #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;
  
                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++;
  
                        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;
                        }
                                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;
                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;
  
                }
  
                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;
  
  
  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));
        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 +1376,7 @@@ static void ieee802_11_rx_wnm_notif_req
        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",
                                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));
                                   "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)
@@@ -56,7 -56,7 +56,7 @@@ void ieee802_11_rx_wnm_action(struct wp
                              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);
  
  
@@@ -1,6 -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 +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 +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 +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 +256,6 @@@ static int wpa_ctrl_command(struct wpa_
  }
  
  
- 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 +355,7 @@@ static char ** wpa_cli_complete_help(co
  
  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 +451,10 @@@ static char ** wpa_cli_complete_set(con
                "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 +482,13 @@@ static int wpa_cli_cmd_dump(struct wpa_
  }
  
  
+ 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 +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",
  #ifdef CONFIG_HS20
        "update_identifier",
  #endif /* CONFIG_HS20 */
-       "mac_addr"
+       "mac_addr", "pbss", "wps_disabled"
  };
  
  
@@@ -1764,6 -1548,13 +1548,13 @@@ static int wpa_cli_cmd_scan_results(str
  }
  
  
+ 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 +1595,48 @@@ static int wpa_cli_cmd_get_capability(s
  }
  
  
+ 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 +1699,15 @@@ static int wpa_cli_cmd_interface_add(st
  
        /*
         * 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 +1747,12 @@@ static int wpa_ctrl_command_sta(struct 
                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 +1862,20 @@@ static int wpa_cli_cmd_mesh_group_remov
        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 +1995,13 @@@ static int wpa_cli_cmd_p2p_group_add(st
  }
  
  
+ 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 +2338,27 @@@ static int wpa_cli_cmd_p2p_remove_clien
        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 +2601,13 @@@ static int wpa_cli_cmd_signal_poll(stru
  }
  
  
+ 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 +2712,20 @@@ static int wpa_cli_cmd_get_pref_freq_li
  }
  
  
+ 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 +2783,9 @@@ static const struct wpa_cli_cmd wpa_cli
        { "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" },
        { "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,
        { "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" },
        { "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,
          "<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" },
        { "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,
        { "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" },
        { "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" },
        },
        { "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" },
        { "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 +3518,6 @@@ static int wpa_request(struct wpa_ctrl 
  }
  
  
- 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)
  {
        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 +3573,7 @@@ static void wpa_cli_action_process(cons
                        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");
                        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 +3760,7 @@@ static int check_terminating(const cha
                        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 +3811,6 @@@ static void wpa_cli_recv_pending(struc
        }
  }
  
- #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 +3995,7 @@@ static void try_connection(void *eloop_
        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 +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;
                        }
                }
  
-               if (daemonize && os_daemonize(pid_file))
+               if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
                        return -1;
  
                if (action_file)
@@@ -29,6 -29,8 +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;
        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 +71,8 @@@
  
        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 +645,7 @@@ static void wpa_priv_interface_deinit(s
  
  
  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;
        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 +1010,37 @@@ void wpa_supplicant_event(void *ctx, en
  }
  
  
+ 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 +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 +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)
  
        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);
        ret = 0;
  
  out:
-       iface = interfaces;
+       iface = global.interfaces;
        while (iface) {
                struct wpa_priv_interface *prev = iface;
                iface = iface->next;
@@@ -1,6 -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 +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 +192,9 @@@ static void wpa_supplicant_timeout(voi
  {
        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 +403,18 @@@ void free_hw_features(struct wpa_suppli
  }
  
  
+ 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;
        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 */
  
        }
  
        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 +998,11 @@@ static void wpa_supplicant_reconfig(in
                        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 +1190,10 @@@ int wpa_supplicant_set_suites(struct wp
                        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) {
        }
        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
                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
                                    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));
                }
                                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
                                        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 +1452,20 @@@ static void wpas_ext_capab_byte(struct 
                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 +1475,9 @@@ int wpas_build_ext_capab(struct wpa_sup
        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 +1648,15 @@@ void wpa_supplicant_associate(struct wp
        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
  
        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;
                        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");
                return;
        }
  
+       wpas_abort_ongoing_scan(wpa_s);
        cwork = os_zalloc(sizeof(*cwork));
        if (cwork == NULL)
                return;
@@@ -1715,6 -1789,36 +1789,36 @@@ static int bss_is_ibss(struct wpa_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)
        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;
  
        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;
        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) {
  
        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);
                   "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;
                        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 +2099,7 @@@ static void wpas_start_assoc_cb(struct 
        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;
         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) {
                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;
        } 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);
        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
         * 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;
                }
        }
  
+ #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;
        }
  #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;
                }
                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 &&
  
        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;
  
        }
  #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 "
        }
        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 +2707,12 @@@ void wpa_supplicant_deauthenticate(stru
                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
  
  #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 +2769,95 @@@ static void wpa_supplicant_enable_one_n
  
  
  /**
+  * 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 +2987,8 @@@ void wpa_supplicant_select_network(stru
                        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");
        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 +3295,7 @@@ static int select_driver(struct wpa_sup
        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 +3378,13 @@@ void wpa_supplicant_rx_eapol(void *ctx
        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 +3669,11 @@@ wpa_supplicant_alloc(struct wpa_supplic
        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 +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 */
  #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 +4130,9 @@@ static void wpas_fst_update_mb_ie_cb(vo
  }
  
  
- 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;
  
  }
  
  
- 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 +4185,55 @@@ static int wpas_set_wowlan_triggers(str
  }
  
  
+ 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 +4286,103 @@@ static void radio_work_free(struct wpa_
        }
  #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;
        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 +4540,7 @@@ int radio_add_work(struct wpa_supplican
                   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;
  
        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);
        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 +4834,11 @@@ static int wpa_supplicant_init_iface(st
                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;
  
        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 +5004,8 @@@ static void wpa_supplicant_deinit_iface
  
        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;
  }
  
  
+ #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 +5445,18 @@@ struct wpa_global * wpa_supplicant_init
        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 +5532,18 @@@ int wpa_supplicant_run(struct wpa_globa
        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 +5609,9 @@@ void wpa_supplicant_deinit(struct wpa_g
        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 +5644,9 @@@ void wpa_supplicant_update_config(struc
        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 +5886,16 @@@ int wpa_supplicant_ctrl_iface_ctrl_rsp_
                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 +5965,19 @@@ int wpas_get_ssid_pmf(struct wpa_suppli
                        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 +6136,27 @@@ void wpas_request_connection(struct wpa
  }
  
  
+ /**
+  * 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 +6339,19 @@@ void wpas_rrm_process_neighbor_rep(stru
  #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
   * 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)
        }
  
        /* 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");
                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,
  }
  
  
+ 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,
        }
        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;
+ }
@@@ -118,6 -118,25 +118,25 @@@ eapol_version=
  # 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
  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
  #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"
  # 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)
  
  # 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
  #     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
  #     (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.
  #
  #     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:
  #
  #     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
  #
  # 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
  # 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
  # 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
  # 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
  #     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.
  #     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.
  #     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
  # 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
  # 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
  ##### 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 +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
@@@ -44,6 -44,7 +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 +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 +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;
        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 +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 +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 +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 +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 +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 +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 */
        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;
        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;
  
        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);
        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
  #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;
  
        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;
        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;
        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;
        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;
        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;
        /* 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;
        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;
        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 +1110,8 @@@ void wpa_supplicant_cancel_auth_timeout
  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 +1136,8 @@@ void free_hw_features(struct wpa_suppli
  
  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 +1167,7 @@@ int disallowed_bssid(struct wpa_supplic
  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 +1177,37 @@@ void wpas_rrm_reset(struct wpa_supplica
  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 +1269,12 @@@ int get_shared_radio_freqs(struct 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 +1284,18 @@@ void fst_wpa_supplicant_fill_iface_obj(
  
  #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 */
@@@ -739,6 -739,8 +739,8 @@@ enum wpa_ctrl_req_type wpa_supplicant_c
                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 +784,10 @@@ const char * wpa_supplicant_ctrl_req_to
                *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 +843,8 @@@ static void wpa_supplicant_eap_param_ne
        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 +1021,6 @@@ static void wpa_supplicant_set_rekey_of
  
        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,
        else
                return 0;
  }
+ #endif /* CONFIG_NO_WPA */
  
  
  int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
@@@ -1124,6 -1132,7 +1132,7 @@@ void wpa_supplicant_rsn_supp_set_config
                        }
                }
  #endif /* CONFIG_P2P */
+               conf.wpa_rsc_relaxation = wpa_s->conf->wpa_rsc_relaxation;
        }
        wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
  }
@@@ -50,10 -50,9 +50,9 @@@ static int wpas_set_replay_protect(voi
  }
  
  
- 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 +108,8 @@@ static int wpas_create_receive_sc(void 
                                  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 +150,8 @@@ wpas_create_transmit_sc(void *wpa_s, u3
                        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));
  }
  
@@@ -9,6 -9,7 +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 +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;
  }
@@@ -583,8 -583,8 +583,8 @@@ static void wpa_supplicant_wps_event_m2
                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 +617,8 @@@ static void wpa_supplicant_wps_event_fa
                        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,
                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 +683,13 @@@ static void wpas_wps_reenable_networks_
  }
  
  
+ 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 +1142,13 @@@ int wpas_wps_start_pbc(struct wpa_suppl
                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);
                        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 +1204,13 @@@ static int wpas_wps_start_dev_pw(struc
        }
        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) {
                        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);
                }
                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);
        }
@@@ -85,6 -85,7 +85,7 @@@ int wpas_er_wps_nfc_report_handover(str
  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 +148,12 @@@ static inline void wpas_wps_notify_asso
  {
  }
  
+ static inline int
+ wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s)
+ {
+       return 0;
+ }
  #endif /* CONFIG_WPS */
  
  #endif /* WPS_SUPPLICANT_H */
diff --combined libeap/wpaspy/test.py
@@@ -7,13 -7,23 +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)]
      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 +76,7 @@@
  
  
  if __name__ == "__main__":
-     main()
+     if len(sys.argv) > 2:
+         main(host=sys.argv[1], port=int(sys.argv[2]))
+     else:
+         main()
diff --combined libeap/wpaspy/wpaspy.py
@@@ -7,27 -7,60 +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):
                  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)
              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: